I found this Related Topic, but it failed to answer my question.
When automatically creating a strongly typed view, lets say with a List scaffolding template, I will get something roughly like this:
#model IEnumerable<Test.Models.abc>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.ID)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
</tr>
}
</table>
I understand #Html.DisplayNameFor(model => model.ID) completely, but not #Html.DisplayFor(modelItem => item.ID).
What is the purpose of modelItem? Replacing it with any arbitrary text will result in a functional web page. It seems that modelItem is just a throwaway word. I guess my real question is why doesn't this work?
#Html.DisplayFor(item => item.ID)
Edit
A good point was brought up in the comments. It seems you are also able to change model to anything so long as you change it on both sides of the lambda expression:
#Html.DisplayNameFor(abc => abc.ID)
A side question would be: How does the #model statement at the top affect the functions below? I had previously thought model referenced the #model expression in order to figure out the display name via the class, but the page still works after the mentioned changes.
It does not work because item is already declared in outer scope in foreach.
#foreach (var item in Model).
The reason why modelItem lambda is not used is because of that iteration of IEnumerable. If there would be Test.Models.abc as model instead of IEnumerable, then would that lambda does matter and the code of DisplayFor would change to #Html.DisplayFor(m => m.ItemId).
Update
#model IEnumerable<Test.Models.abc> just declares that this view is strongly typed, with type of IEnumerable<Test.Models.abc> - in your case. That means that view property this.Model (not model) is of type IEnumerable<Test.Models.abc> - and also that model of that type should passed into this view. model in example above is just expression variable - it has scope just for that expression. You can change it's name to any unprotected legal variable name that was not already used in outer scope (that's why it should not be named Model, because it would hide the Model property already declared in view).
item is already a variable defined in an outer scope. You are capturing it as a closure, which is not ideal here. What your code should read is:
#Html.DisplayFor(modelItem => modelItem.ID)
Related
I have the following code in my view:
<table>
<tr>
<td>
Number of Records to Show:
</td>
<td>
#Html.DropDownListFor(m=>m.NumRecsToShow, Enumerable.Range(1, 100).Select(i => new SelectListItem {Text = i.ToString(), Value = i.ToString()}))
</td>
</tr>
<tr>
#Html.PagedListPager((IPagedList) Model.lp, page => Url.Action("List", new RouteValueDictionary()
{
{"Page",page},
{"Recs",?????}
}))
</tr>
</table>
What I need to do is read the new selected value and pass it back as a "Recs" parameter, so I can return the right number of Records. But I dont know how to read the selected value when the PagedListPager number is clicked on in the table. I would love to know of some #Html helper (Where the ???? is in the code above.) that can read the value when I need it, but I am starting to think that I might need to use JQuery. Of course the other route would be if I can use the DropdownList to change the model data then I can just pass back the model to the controller, but the dropdownlist doesnt seem to get read unless I do a form submit.
Any pointing me in the right direction is appreciated.
I have a view that is using a model. I just need to do a simple subtraction on the model variables using razor.
Here is what the code looks like:
#model Inquiry.Inq_Weights
<table id="mainWeights">
<tr>
<td>#Html.DisplayFor(model => Model.HotScaleHalfId)</td>
<td>#Html.DisplayFor(model => Model.HotScaleGrossWeight)</td>
<td>#Html.DisplayFor(model => Model.HotScaleTareWeight)</td>
</tr>
<tr>
<td><strong>Total Hot Scale Weight</strong></td>
</tr>
<tr>
<td align="right">(#Model.HotScaleGrossWeight - #Model.HotScaleTareWeight;)</td>
</tr>
</table>
I am trying the (#Model.HotScaleGrossWeight - #Model.HotScaleTareWeight;)
but it is just displaying "0 - 0". The zeros are correct at this point. but i don't want it to display the expression, just the result of that operation.
I have also tried using a variable then listing that, as in
#{
var netWeight = #Model.HotScaleGrossWeight - #Model.HotScaleTareWeight;
netWeight;
}
But that doesn't work either. How can I do simple math on model members?
You should do this:
#(Model.HotScaleGrossWeight - Model.HotScaleTareWeight)
With your other example:
#{
var netWeight = Model.HotScaleGrossWeight - Model.HotScaleTareWeight;
}
Then use it with #netWeight. Please note that the # symbol is razor specific, you don't have prefix your variables with it inside a c# expression. When you write # you are actually saying that you are going to write a c# expression. Writing # before Model is just for the razor engine to know that this is going to be a c# expression (your variable actually) and not a simple text 'Model'.
But I recommend to do this kind of stuff within your controller.
update
as Alexei wrote in comment # is not just for razor: What does the # symbol before a variable name mean in C#?
I am trying to use a display template (Pet.cshtml), which I have placed in ~/Views/Shared/DisplayTemplates, as per convention.
The Index action gets the IEnumerable and passes it to Index.cshtml, which passes it along to _PetTablePartial. So far, so good. However, when Html.DisplayForModel is called, I get this error:
The model item passed into the dictionary is of type 'Pet', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Pet]'.
But I (think) I can clearly see that the model item is in fact an IEnumerable. What am I doing wrong?
Controller:
public ActionResult Index()
{
return View(pet.GetPets()); // returns IEnumerable<Pet>
}
Index.cshtml:
#model IEnumerable<Pet>
{Html.RenderPartial("_PetTablePartial", Model);}
...
_PetTablePartial.cshtml:
#model IEnumerable<Pet>
#Html.DisplayForModel()
~/Shared/DisplayTemplates/Pet.cshtml:
#model IEnumerable<Pet>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
...
Pet.cshtml should have a model type of Pet, because you are only dealing with a single pet here.
DisplayTemplates automatically enumerate over a collection, and call your DisplayTemplate with a single item. That's one of their benefits. You don't need to do any enumeration.
Just change Pet.cshtml's type to Pet
I also suspect you don't want to have a separate table for each pet. So what you want is to create the table and header In your partial view, then only have a single data row in Pet.cshtml, because Pet.cshtml will be called multiple times, once for each row.
PetTablePartial.cshtml:
#model IEnumerable<Pet>
<table>
<tr>
<th> Pet Name </th>
</tr>
#Html.DisplayForModel()
</table>
~/Shared/DisplayTemplates/Pet.cshtml:
#model Pet
<tr>
<td>#Html.DisplayFor(x => x.Name)</td>
</tr>
In the Pet.cshtml you are passing in IEnumerable<Pet>, but then trying to access the Name property of the model. IEnumerable does not have a Name property.
In general, you would wrap this with a foreach loop so you can access the Name property of the elements on the list. However, since you are trying to write out the table header, you only want to write it out once and not traverse the list.
Take a look at these other SO questions:
#Html.DisplayNameFor for details model
How to get the column titles from the Display(Name=) DataAnnotation for a strongly typed list scaffold view at runtime?
is it possible i fill model's fields by content of table's tds. of course without using javascript .
i wanna pass a model to view and get content of tds .
some thing like text box : #Html.TextBoxFor(m => m.username)
is it possible i have some thing like this for tds? what can i put in place of tds?
<tr class="darckTr">
<td>code :</td>
<td id="tdPobox" colspan="3">12345</td>
<td>Email :</td>
<td id="tdEmail">example#yahoo.com</td>
</tr>
It sounds like what you want is a display template. Create a .cshtml view, for example "ContactDetails.cshtml":
#model ContactDetails
<tr class="darckTr">
<td>code :</td>
<td id="tdPobox" colspan="3">#Model.PoBox</td>
<td>Email :</td>
<td id="tdEmail">#Model.Email</td>
</tr>
If the filename of your partial view matches the type in your model, it will be used automatically. Otherwise, you have a couple of options. Either specify the partial on your model, e.g.:
public class MyWrappingClass
{
[UIHint("_ContactDetails")]
public ContactDetails Details { get; set; }
}
And then do this in your view:
#model MyWrappingClass
#Html.DisplayFor(m => m.Details)
Or, just specify the template directly in your view:
#model MyWrappingClass
#Html.DisplayFor(m => m.Details, "_ContactDetails")
Brad Wilson wrote a good blog post on templates, including how they are resolved, here:
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html
Edit
If you want to persist these values back on POST, you need to have an input element containing the values. In your case, the best way to do this would be to use a hidden field, for example:
#Html.HiddenFor(m => m.Username)
Currently in MVC, we have to define columns manually whenever we want to list out items:
<tr>
<td>
#Model.Name
</td>
<td>
#Model.Age
</td>
<td>
#Model.Gender
</td>
</tr>
What I want to do however, is to have a ViewModel where we specify which columns should be used, something like:
var model = new PersonViewModel(
// List of persons
CollectionOfPersons,
// List of columns that we want to display
new Expression<Func<Person, object>>[]
{
x => x.Name,
x => x.Age,
x => x.Gender
});
Then in our view, all I need to do is:
<tr>
// Model.Predicates is our ViewModel's selected columns
#foreach(var predicate in Model.Predicates)
{
<td>
// This would basically loop each pre-defined lambda expression in our ViewModel
#Html.DisplayFor(predicate)
</td>
}
</tr>
I have to admit I have a very weak understanding of expressions, and I have so far been unsuccessful in looking for information. Does anyone have any idea if this is possible to do?
Seems like the html helpers don't work like that (passing in the expression as a variable). The compiler explicitly needs an expression to be able to determine the TModel and TResult types to be able to work.