I am working on a asp.net mvc 3 application and I've made several partial views each one responsible for rendering of specific logic. Inside one of my views I use properties which can be null, but I don't want to pass null to the #Html.DisplayFor() and write something more user friendly to the user to know that these fields are not missing, they just don't have nothing assigned to them yet.
So I try this :
<tr>
<td>
#if (!string.IsNullOrEmpty(Model[0][0].FieldValue))
{
#Html.DisplayFor(Model => Model[0][0].FieldValue)
}
</td>
<td>
#Html.DisplayFor(Model => Model[1][0].FieldValue)
</td>
</tr>
I don't have else clause because writing the if statement results in getting both Model => in the DisplayFor marked with red and the following message :
A local variable named 'Model' can not be declared in this scope
because it would give a different meaning to 'Model' which is already
used in a 'parent or current' scope to denote something.
Basically I think I understand what this error means however I don't know how to check for null properly in this situation.
The error message is caused by the redefinition of the Model variable. Try
#Html.DisplayFor(x => x[0][0].FieldValue)
You might find this SO question useful to understand the "=>" thingie.
Related
Is it possible to use "Sum" within Razor, so you can sum up what has been interated through on the view. ie. my view is like this:
#model IEnumerable<cb2.ViewModels.ResultsVM>
...
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Qualified)
</td>
...
}
I then want to sum up all of the Qualified in at the bottom of the screen similar to this:
#Model.Qualified.Sum()
But I get the error:
'System.Collections.Generic.IEnumerable<cb2.ViewModels.ResultsVM>' does not contain a definition for 'Qualified'
I thought it would have been easy in Qazor to simply use Sum or Count on a model?
thanks, Mark
I think you want:
#Model.Sum(i => i.Qualified)
Qualified is a property of the items within the model, not the model itself.
Remember that Model is an IEnumerable<cb2.ViewModels.ResultsVM>, it does not contain a property for Qualified, but each item within the collection does. So you can call Sum directly on the collection and specify the property that you want to sum, namely Qualified...
#Model.Sum(x => x.Qualified)
In my application, I have two roles: Administrators and Users. Administrators can assign Users to allow them to perform specific functions to a specific object.
Since this goes beyond the scope of what the SimpleMembership Roles can provide, I have a static helper method that checks whether a user has access to a specific function:
public static class SecurityCheck
{
public static bool UserHasAccess(int objectId, string functionName)
{
// Decorates the security provider -- gets logged in User ID and calls to a repository to query the database
// ...
}
}
Which I can then use in my views to determine whether or not a specific function should be rendered for that user based on the object's ID:
#foreach (var item in Model.FooData)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Notes)
</td>
<td>
#Html.ActionLink("View Data", "View", new { #id = item.Id })
#if (SecurityCheck.UserHasAccess(item.id, "Edit Data"))
{
#Html.ActionLink("Edit Data", "Edit", new {#id = item.Id})
}
#if (SecurityCheck.UserHasAccess(item.id, "Delete"))
{
#Html.ActionLink("Delete", "Delete", new {#id = item.Id})
}
</td>
</tr>
}
I have to believe there is a better way to do this, since each individual call to the static method involves a separate round-trip to the database, but I am stuck on where the best place would be to put the code. Some thoughts I have considered:
Adding methods to my ViewModels to pass a list of functions to a repository, returning a list of the functions the user can perform for each object. Thinking about this further, I'm not even sure this is possible, as ugly as it would be.
Keep the ViewModel dumb, and have my application layer service fetch the available functions. This would involve adding additional properties to my domain model objects, which I am not crazy about.
Create a separate service that can be called from the controller that can populate the function list to the ViewModel. This would involve having multiple services injected into each controller -- also not crazy about this.
I'm leaning towards #2., but I still feel like I am overlooking what would be a more solid implementation. Has anyone dealt with something similar to this before?
I think each ViewModel "knows" what can be done with it, isn't it? So we can make implicit explicit. The ViewModel can explicitly have properties such as CanEdit, CanDelete, etc.
The UI should not care why some operations are allowed or not, it simply checks these properties in a way:
#if (item.CanEdit)
{
#Html.ActionLink("Edit Data", "Edit", new {#id = item.Id})
}
You can even come up with a helper that takes another boolean as a parameter to decide whether the control should be rendered (or enabled) or not, but it is minor:
#Html.SecureActionLink(item.CanEdit, "Edit Data", "Edit", new {#id = item.Id})
The idea is that it is not the responsibility of the UI to know how to figure out whether something is permitted due to some business rules or not.
But it is definitely UI's responsibility to know how and what to render in one ViewModel is not Editable or another is ReadOnly (different things can have different states).
Also, since we are talking about DDD I would advice against modeling CRUD operations. In the end of the day DDD is about Ubiquitous Language, and "Create, Update, Delete" is hardly a language business really speaks.
So you will end up with more precise and meaningful properties/operations in your models, such as CanAccept (for order screens) or `CanMakeRefund" (for payments).
You resolve/set these properties when you build up your ViewModel and apply security context to it.
Hope it helps.
Maybe you need to use SimpleMembership roles:
Assigning Roles with MVC SimpleMembership
In the standard MVC membership you can just use something like:
Roles.AddUserToRole(model.UserName, "Admin");
And in you View e.g.:
if (ViewContext.HttpContext.User.IsInRole("Admin"))
I’m fairly new at C# and MVC and have used lambdas on certain occasions, such as for anonymous methods and on LINQ.
Usually I see lambda expressions that look something like this:
(x => x.Name), (x => { Console.WriteLine(x))
I understand that lambda = "goes to". I have never seen a lambda expression where the left parameter is not used.
I don’t know how to translate this lambda expression though
#Html.DisplayFor(modelItem => item.FirstName)
Can anyone shed some light on this one for me? Shouldn’t this be
(modelItem => modelItem.FirstName)?
I got this from Microsoft's Introduction to ASP.NET MVC tutorial.
A lambda expression is a way to write an anonymous function, i.e. a function without a name. What you have on the left side of the "arrow" are the function parameters, and what you have on the right side are the function body. Thus, (x => x.Name) logically translates to something like string Function(Data x) { return x.Name } the types string and Data will obviously vary and be derived from the context.
The absence of the left-side parameter translates into a function without parameters, so that this (() => someVariable) logically translates to this: string Function() { return someVariable; }
At this point you might start wondering, where someVariable comes from, it's not a function parameter and it is not defined in the function. You would be correct, a function like this would never compile. However the lambda function like this is perfectly fine, as it allows outer-scope variables be lifted and used this way. (Internally a wrapper class is created where the variables that are used in the lambda expression become fields.)
Now let's see what model => item.FirstName means. Logically it would translate to string Function(Model model) { return item.FirstName; }. Basically this is a function with a parameter, but this parameter is not used.
And now, the last bit of the information. Although lambda expressions represent functions in the end, sometimes they are created not with the purpose of actually being executed (although potentially they can). A lambda expression can be represented in the form of an expression tree. This means that instead of executing it it can be parsed.
In this particular case the MVC engine does not run the function that the lambda expression represents. Instead the expression is parsed so that MVC engine knows what html to emit for this particular line. If your data item does not come from your model object directly, the left part of the lambda expression does not matter.
i think it's about the foreach loop. example:
#foreach(var item in model)
{
<td>
#html.displayfor(model => item.firstName) </td>
</td>
}
var item needs to be used because each item in the sequence is an anonymous type.
model => item.firstName means (input parameter) => expression. you can't use the input parameter because we store the current "item" in item.
It is using a parameterless lambada. See this question
Basically DisplayFor doesn't use the lambda function parameter model (it could be anything I'd say use _ or ()) and just uses the lambda function within the for loop to use displayfor against it. DisplayFor requires a lambda function.
I also struggled a lot to understand the codes generated by Visual Studio. Instead of providing a general explanation about lambda expression, I would like to put a context using ASP.NET MVC framework.
Suppose we prepared a Model class (e.g. Destination) with 2 attributes: City and ProvinceCode.
public class Destination
{
public string City { get; set; }
public string ProvinceCode { get; set; }
}
After generating the Controller and View, we should get the generated codes by Visual Studio as mentioned. Yet, the generated codes are somewhat hard to understand, especially for the data rows
#Html.DisplayFor(modelItem => item.City)
I just guess that the MVC team should think that Html helper class should be consistently used in the cshtml file. Thus, they tried to use tricks to pass the C# compiler. In this case, modelItem is not even used as an input parameter of this lambda expression. We can't use () as the type is NOT correct. That is why, if we replace model or any model object, the lambda expression works.
To be honest, I would like to rewrite the generated codes in a more readable form. Instead of using the Html helper class, we can simply render the correct output as follows:
#foreach (var item in Model) {
<tr>
<td>
#* Code Generated by Visual Studio. modelItem is a dummy param *#
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#* A better way - simply get rid of Html helper class *#
#item.ProvinceCode
</td>
</tr>
}
I have a partial view that inherits from ViewUserControl<Guid?> - i.e. it's model is of type Nullable<Guid>. Very simple view, nothing special, but that's not the point.
Somewhere else, I do Html.RenderPartial( "MyView", someGuid ), where someGuid is of type Nullable<Guid>. Everything's perfectly legal, should work OK, right?
But here's the gotcha: the second argument of Html.RenderPartial is of type object, and therefore, Nullable<Guid> being a value type, it must be boxed. But nullable types are somehow special in the CLR, so that when you box one of those, you actually get either a boxed value of type T (Nullable's argument), or a null if the nullable didn't have a value to begin with. And that last case is actually interesting.
Turns out, sometimes, I do have a situation when someGuid.HasValue == false. And in those cases, I effectively get a call Html.RenderPartial( "MyView", null ). And what does the HtmlHelper do when the model is null? Believe it or not, it just goes ahead and takes the parent view's model. Regardless of it's type.
So, naturally, in those cases, I get an exception saying: "The model item passed into the dictionary is of type 'Parent.View.Model.Type', but this dictionary requires a model item of type 'System.Guid?'"
So the question is: how do I make MVC correctly pass new Nullable<Guid> { HasValue = false } instead of trying to grab the parent's model?
Note: I did consider wrapping my Guid? in an object of another type, specifically created for this occasion, but this seems completely ridiculous. Don't want to do that as long as there's another way.
Note 2: now that I've wrote all this, I've realized that the question may be reduced to how to pass a null for model without ending up with parent's model?
<% Html.RenderPartial("MyView", someGuid ?? new Guid()); %>
UPDATE:
Using editor and/or display templates in ASP.NET MVC 2.0 you can achieve the desired result. Place a Guid.ascx file in the Shared/EditorTemplates folder and include it like this:
<%= Html.EditorFor(x => someGuid) %>
or if the guid is a property of the main model:
<%= Html.EditorFor(x => x.SomeGuid) %>
Now if you put a <%= Model.HasValue %> inside the partial you can get false but not with RenderPartial.
I'm looking at the new version of ASP.NET MVC (see here for more details if you haven't seen it already) and I'm having some pretty basic trouble displaying the content of an object.
In my control I have an object of type Person, which I am passing to the view in ViewData.Model. All is well so far and I can extract the object in the view ready for display. What I don't get though, is how I need to call the Html.DisplayFor() method in order to get the data to screen. I've tried the following...
<%
MVC2test.Models.Person p = ViewData.Model as MVC2test.Models.Person;
%>
// snip
<%= Html.DisplayFor(p => p) %>
but I get the following message:
CS0136: A local variable named 'p' cannot be declared in this scope because it would give a different meaning to 'p', which is already used in a 'parent or current' scope to denote something else
I know this is not what I should be doing - I know that redefining a variable will produce this error, but I don't know how to access the object from the controller. So my question is, how do I pass the object to the view in order to display its properties?
N.B. I should add that I am reading up on this in my limited spare time, so it is entirely possible I have missed something fundamental.
TIA
Html.DisplayFor can be used only when your View is strongly-typed, and it works on the object that was passed to the View.
So, for your case, you must declare your View with the type Person as its Model type, (e.g. something.something.View<Person>) (sorry, I don't remember the exact names, but this should make sense), and then when calling Html.DisplayFor(p => p), p would take the value of the passed model (Person) value into the view.
Hope that made sense.
p is already a variable name; and variable names have to be unique throughout the current scope. Therefore displayFor(p=>p) is not valid, as you're declaring a new variable 'p' there. That way the compiler doesn't know wether to use your Person p, or the (p =>) variable.
So just rename it to
<%= Html.DisplayFor(person => person) %>