How can I use Html.DisplayFor inside of an iterator? - c#

I am loving MVC 2. The whole thing just fits the web so well.
There is one piece of functionality, however, that I am unable to coax out of the Html.DisplayFor() function:
<# Page Inherits="ViewPage<IEnumerable<Foo>>">
<% foreach(var item in Model) { %>
<%: Html.DisplayFor(item.BarBaz) %>
<% } %>
I need to be able to use the DisplayTemplate for this value. Is there a way to do this?

Actually, I figured it out. How stupid of me.
This works:
<# Page Inherits="ViewPage<IEnumerable<Foo>>">
<% foreach(var item in Model) { %>
<%: Html.DisplayFor(m => item.BarBaz) %>
<% } %>
However, this will not work correctly for Html.HiddenFor and Html.ValueFor. In particular, Html.HiddenFor(m => item.NullableDecimal) will render as <input name="NullableDecimal" value="0" /> and Html.ValueFor(m => item.NullableDecimal, "0.00##) will render as 0.00##. However, if you apply a [DisplayFormat(DataFormatString = "{0:0.00########}" to your view model, then it will suddenly work. For this reason, you're probably best off using Html.Display, Html.Hidden, and Html.Value extensions, since you're less likely to run into scenarios where things fail when someone makes a non-local change.

You can accomplish it by getting away from the foreach and using a regular for loop:
<% for (int i = 0; i < Model.Count(); i++) { %>
<%: Html.DisplayFor(p=> p.ElementAt(i).BarBaz) %>
<%} %>
Another option would be to create a PartialView that took an Foo object and only displayed the information that you wanted.
<% foreach (var item in Model)
{
Html.RenderPartial("FooBarBazLine", item);
} %>

This is an old question, but i guess that someone can get benefits from my solution:
Aspx view
<%# Page Inherits="ViewPage<IEnumerable<Foo>>" %>
<% foreach (var item in Model) { %>
<%: Html.DisplayFor(m => item) %>
<% } %>
Razor view
#model IEnumerable<Foo>
#foreach (var item in Model)
{
Html.DisplayFor(m => item)
}
Since DisplayFor accepts an implicit typed lambda, we can directly indicate the instance to display in the loop.
Finally, i'm agree with Anders E. Andersen's answer for the template usage

Html.DisplayFor can automatically iterate over collections, displaying a partial view for each element in the collection.
The first thing you need to do is create an actual model class, with the collection being a property of the class.
public class Bar
{
public IEnumerable<Foo> foo { get; set; }
}
Return this class from your controller instead of the raw collection.
Secondly you need a display template for the Foo class. Display templates are partial views that need to be placed in the folder Views/Shared/DisplayTemplates.
Edit: You can have them in your controller subfolder of Views as well if you want to limit the template to a particular controller. See this question for more information.
Here is an example in razor syntax:
#model YourNameSpace.Foo
<p>#Model.BarBaz</p>
Save it as Foo.cshtml in the DisplayTemplates folder given above.
This template is pretty simple because it is based on your example where you are only displaying a string, but if the collection elements where a class with its own properties you could create a more elaborate template.
Now in the original view, you can get rid of the loop entirely and just write
#Html.DisplayFor(m => m.foo)
Notice foo is the name of the property in your new model class that contains the old collection you looped over before.
DisplayFor will automatically know that the foo property is of type (collection of) Foo and pick up the Foo.cshtml template in the DisplayTemplates folder and show it once for each element in foo.

In Razor I am using
#Html.DisplayFor(model => item.CreatedDate)

Just be careful that a DisplayFor on a POST of a form doesnt actually create a field that can be referenced back in the controller. You would need to use an additional HiddenFor if you need to refer to fields in your submitted POST method.

Related

MVC Problems 16

I am trying to post a part of my model for a view to action in another controller. I've tried to do it this way:
<% using (Html.BeginForm("Register", "User", new {createDto = Model.UserCreateDto}, FormMethod.Post))
{%>
Form code here...
<%}%>
UserCreateDto is a part of my model and it's being filled in this form. I'm trying to pass it to "Register" action in UsersController:
[HttpPost]
public ActionResult Register(UserCreateDto createDto)
The problem is that route value in Register action is null (createDto) after form submit. Maybe it is happening because route values are being attached to url before form submit event (and before model fields are filled).
Is there any way to do what I want?
UPDATE Here is the actual HTML code:
Имя пользователя
Пароль
E-mail
And here is the updated form code:
<% using (Html.BeginForm("Register", "User", FormMethod.Post))
{%>
<%: Html.HiddenFor(userCreateDto => Model.UserCreateDto.Username) %>
<%: Html.HiddenFor(userCreateDto => Model.UserCreateDto.Password) %>
<%: Html.HiddenFor(userCreateDto => Model.UserCreateDto.Email) %>
<%: Html.HiddenFor(userCreateDto => Model.UserCreateDto.Active) %>
<%= Html.LabeledValidatedTextBoxFor(username => Model.UserCreateDto.Username, true) %>
<%= Html.LabeledValidatedTextBoxFor(password => Model.UserCreateDto.Password, true)%>
<%= Html.LabeledValidatedTextBoxFor(email => Model.UserCreateDto.Email, true)%>
<input type="submit" value="Register"/>
<%}%>
Html.LabeledValidatedTextBoxFor is just my custon HTML helper.
Here is updated action signature:
[HttpPost]
public ActionResult Register(UserCreateDto userCreateDto)
userСreateDto in this action is still null.http://www.media fire.com/file/5dcrv5zupy44c0i/A16.rar/file By the way, is there any way not to use hidden fields? They are not secure enough to pass through them user registration information.
Probably what you're looking for is ModelBinding. If your UserCreateDto Model is complex enough, and by that I mean that it contains any other complex type inside, the DefaultModelBinder is not going to know how to fill your model. So you need to tell it explicitly how to map the values in your request to the Model you are expecting in the Register post method in your UserController.
This link shows an example of how to do it in ASP.NET Core. I couldn't find the ASP.NET MVC official documentation but it's not so different than this.
Hope it helps!

Fill a table from a list C# asp.net

I have a class Car, with some atributtes Model and Year. I have a list (List<Car> carList = new List<Car>()) of some objects of the class Car, and I want to put this list into an HTML tag , but I have no idea how to do this.
I got a template that already has a <table>, that's why I'm trying to use <table> instead of <asp:GridView>.
I'm using WebForms
If you are set on using a <table> and not any of the <asp:*> controls, you can manually build your markup on the page.
First, you need to be able to access the object from your markup. By making it a protected (or public) property on the code-behind, the page can access it:
protected IList<Car> CarList { get { return carList; } }
Then in the page (which inherits from the code-behind class) you can access that property to build markup. Something like this:
<% foreach (var car in CarList) { %>
<% } %>
Inside of that loop would be your rows, outside would be your table dressing. Something like this, perhaps:
<table>
<tr>
<th>Column Heading</th>
</tr>
<% foreach (var car in CarList) { %>
<tr>
<td><%= car.SomeValue %></td>
</tr>
<% } %>
</table>
This is similar to how one may construct markup in MVC, so you can think of it like that. Though it's not common for WebForms and it's often recommended to use the framework the way it's meant to be used. In the long run, if you're set on using WebForms, it may be less work to adjust the template to work with the server-side controls than to manually build the markup. The server-side controls have the added benefit of lots of event binding and code-behind interactions.

C# ASP.NET MVC User Control

I want to insert a user control on to a master page
The user control is a basic menu that lists categories of items
I want to pull the category list dynamically from SQL Server
I can do this in web forms using code behind, but how do you go about this in MVC?
Thank you
Categories.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<ul>
<% foreach (string category in Model.Categories ) { %>
<li>
<%= Html.Encode(category) %>
</li>
<% } %>
</ul>
I would make a base controller for all the controllers that will use your MasterPage. In that base controller I would load up your list of data to create the menu (from a cache, sql, whatever) and store it in ViewData.
If you want to you could also make a base model for all your models that will be loading your views based on the controller as well and then you could just load it directly into the models that extend this base class.
Assuming your went the easier ViewData route, in your user control you can just access the ViewData and load your menu since you can assume that all your contorllers will have pre-loaded this data.
this is in your Controller:
ViewData["CategoryList"] = _categoryService.GetCategoryList();
this exists in a file called NameOfMyPartial.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% foreach (var category in (IList<Category>)ViewData["CategoryList"])) { %>
// do stuff with category
<% } %>
Then in your Master page:
<% RenderPartial("NameOfMyPartial"); %>

How to declare a global variable in ASP.NET MVC page

I've began working with asp.net mvc very recently and I've ran into a problem.
I've got an aspx page which renders a few ascx pages. What I'd like to do is declare a global var at the aspx page so it is visible to all its childs. I tried <% var i = 0; %> but it wasn't visible at the child pages.
What could I do?
variables from a aspx page are not shared with the partial views.
The view is just a representation of a piece of data. You have to pass the data as a Model to each view you want to render, whether it's a plain View or a PartialView.
<% Html.RenderPartial("ViewName", Model, ViewDataDictionnary) %>
If you want to pass a variable to a partial view, I would strongly recommend you to add this parameter to the model of the partial view, rather that to pass it additionally via the ViewDataDictionnary.
You can add it to the ViewData and then pass the ViewData to the ascx with
<% Html.RenderPartial("ViewName", Model, ViewData) %>
see msdn on RenderPartial
So in your aspx page you'd do something like
<% ViewData["i"] = 0; %>
And in your userControl you'd just retrive it and use it as you want
<% int i = (int)ViewData["i"] %>
Another way would be to use RenderAction eand pass it as a parameter... so we'd need to know how you display your ascx.
see msdn on RenderAction

Best way to do ListView in ASP.NET MVC?

bascially, how should i do it now that using the asp:listview control is out of the question?
i am migrating from webforms to mvc and former implementation was in <asp:ListView...> so how should i do it now in terms of best user experience for the user? ie: i will need to ajax everything.
thanks
You should use the standard list box now. If you need to return the list from your controller you return a SelectList [i think that's it].
To ajax the select list you can use say jQuery to add click and change events which will then call actionresults in your controller.
Edit
Ah right, there are a couple of ways. You could use a jQuery grid which will display the rows and allow you to have edit delet buttons. You then post back to an action, make the changes and come back. All Ajax of course.
The other way might be to write a couple of PartialViews. The first loops through your collection and the second displays the row. The last one would have say the buttons or a check box or whatever.
Then you again post back, via ajax, to an action result, make the changes and come back.
Your action result can return a fully rendered partial view so after you make your changes, return a new partial view of your data rows and replace the old with the new.
edit 2
if you want code, leave a comment and i'll provide
edit 3
There are a bunch of jQuery grids out there, just google it.
As for partial views something like this would work;
HTML Partial View 1 called BenefitList;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<Models.Benefit>>" %>
<% foreach(Benefit benefit in Model){ %>
<% Html.RenderPartial("Benefit", benefit); %>
<% } %>
HTML Partial View 2;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.Benefit>" %>
<fieldset class="Benefit benefit" id="<%= Model.Id %>">
<legend><label class="Title"><%= Html.Encode(Model.Title) %></label> <a class="BenefitDescriptionView" href=".">View</a><a class="BenefitDescriptionEdit" href=".">Edit</a></legend>
<div class="BenefitDescription hidden">
<%= Html.Encode(Model.Description) %>
</div>
</fieldset>
Some jQuery for you to do a post to an action result;
function jQueryDeleteBenefit() {
$.post("/Home/jQueryDeleteBenefit", { Id: YOURID },
function(NEWHTML) {
$('.EditProductContainer').html(NEWHTML);
});
}
An action result;
[AcceptVerbs(HttpVerbs.Post)]
public void jQueryDeleteBenefit(int id
{
//delete item
return PartialView("BenefitList", AllMyBenefits);
}

Categories