How to manipulate data in View using Asp.Net Mvc RC 2? - data-structures

I have a table [Users] with the following columns:
INT SmallDateTime Bit Bit
[UserId], [BirthDate], [Gender], [Active]
Gender and Active are Bit that hold either 0 or 1.
I am displaying this data in a table on my View.
For the Gender I want to display
'Male' or 'Female', how and where do
I manipulate the 1's and 0's? Is it done in the repository where I fetch the data or in the View?
For the Active column I want to show
a checkBox that will AutoPostBack on selection change
and update the Active filed in the
Database. How is this done without
Ajax or jQuery?

For Question #1:
Use a DisplayTemplate. In View/Shared create a folder named DisplayTemplates. Then Add a partial View to this folder named Gender.ascx. Make sure it is not strongly typed.
the markup in this file will look like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Boolean>" %>
<span><%= Model ? "Male" : "Female" %></span>
Then in your Model you decorate the Gender property with a UIHint thusly:
[UIHint("Gender")]
public boolean Gender { get; set; }
In your View you make it use this template by using DisplayFor
<%= Html.DisplayFor(model => model.Gender) %>
If you cannot use the UIHint you can explicity name your template in DisplayFor
<%= Html.DisplayFor(model => model.Gender, "Gender") %>

Related

ASP.Net MVC 3 - DropDownListFor fails to select the value form the model if HtmlFieldPrefix is set on the partial view

when using
<%= Html.DropDownListFor(model => model.FeeTypeId, Model.GetFeeTypes(), new { })%>
in this case the right option is selected according to Model.FeeTypeId when the select is rendered.
BUT
if you render the form using a partial view, passing it a specific HtmlFieldPrefix (you will need it if,for example, you want to render two identical views and want different ids the elements)
<% Html.RenderPartial("path-to-partial-view", Model, new ViewDataDictionary() { TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = "myPrefix" } }); %>
then the value will not be selected.
looks similar to the problem at DropDownListFor in EditorTemplate not selecting value but from different cause.
looked in the MVC 3 source and seems like the problem is at the SelectInternal method
it uses the htmlHelper.ViewData.Eval(fullName);
which fails to get the value by the full name when it contains the prefix,
TextBoxFor doesn't fail as it passes the value of the expression to InputHelper so it doesn't get to use the ViewData.Eval
just to be sure tested it at the partial view:
in the partial view the following will print "myPrefix.FeeTypeId"
<%= Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("FeeTypeId") %>
and the following will print "by property name: [value] by full name: [empty string]"
<%="by property name: " + Html.ViewData.Eval("FeeTypeId")%><br />
<%= "by full name: " + Html.ViewData.Eval(Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("FeeTypeId"))%>
The only solution i found is to generate a List at Model.GetFeeTypes() and mark the option i want as selected:
<%= Html.DropDownListFor(model => model.FeeTypeId, Model.GetFeeTypes(Model.FeeTypeId), new { })%>
don't really like this solution + i know i can create the List in the partial view which is also ugly,
is there another solution to this?
I have discovered that this is a bug in MVC. It's not fixed, though there is a work around.
See my question answered by myself (I had the same problem before finding your post).
MVC4 binding drop down list in a list (bug)
Regards
Craig

#foreach loop in MVC 3

I am new to MVC 3 and have this question to start with,
I have a class defined as
Class abc
{ public string Id { get; set; }
public string str1 { get; set; }
public string Action { get; set; }
public string Name { get; set; }
public string Title {get; set;}
}
on my MVC2 aspx viewpage , I was using this class abc as model and had this code
<%
Model.ForEach(a =>
{ %>
<%= Html.ActionLink(a.Title ,
a.Action , // <-- ActionMethod
a.Name , // <-- Controller Name.
new { key = a.Id }, // <-- Route arguments.
new { title = a.str1 })%>
<br /><br />
<% }); %>
can you please help me convert this piece of code to MVC razor view ?,
#model abc
<%
Model.ForEach(a =>
{ %>
<%= Html.ActionLink(a.Title ,
a.Action , // <-- ActionMethod
a.Name , // <-- Controller Name.
new { key = a.Id }, // <-- Route arguments.
new { title = a.str1 })%>
<br /><br />
<% }); %>
when I try to use #foreach ( var abc in Model) , I get error message , need to implement Ienumerable ? How can I implement using #for Please help or give me pointers.Thanks
The model shows only one object, not a list of objects.
Therefore you should not use ForEach but access the properties directly without a loop as Model.Name etc.
If you want a list of objects, then you need to update your controller to return a list of those by using a generic list, for example.
var abcCollection = new List<abc>();
That should point you in the right direction.
user1005310,
a bit of understanding of the Razor syntax will help here. there are plenty of examples out there via Mr google. However, if you have a LOAD of code to convert, then you have a great little 'tool' out there to help (now OSS, originally developed by Telerik). Take a look at:
https://github.com/telerik/razor-converter
this is basically a convertor that takes an entire set of aspx views and converts them to Razor. I've tried it on a few test projects now and it works to 99% of my satisfaction, the other 1% is being addressed (or i can live with the minor tweaking).
I'd recommend you using a display template. This way you don't need to write any loops. So:
#model IEnumerable<abc>
#Html.DisplayForModel()
and then you define a display template which will automatically be rendered for each element of the model collection (~/Views/Shared/DisplayTemplates/abc.cshtml):
#model abc
#Html.ActionLink(
Model.Title,
Model.Action,
Model.Name,
new { key = Model.Id },
new { title = Model.str1 }
)
<br /><br />
Notice that templates work by convention. They must be placed in either the ~/Views/Shared/DisplayTemplates folder or the ~/Views/SomeController/DisplayTemplates folder depending on whether you want to reuse them between views from multiple controllers or a single controller. ASP.NET MVC first looks in the specific folder for a template and then in the Shared. The name of the file is also important. In this case your model consists of an IEnumerable<abc> where abc is the type of the elements in this collection therefore the display template must be called abc.html.
Same rules apply for editor templates. Just replace display by editor. Editor templates, as their name suggests, are suitable for putting input fields for editing a view model.

Using ASP.NET MVC 3 with Razor, what's the most effective way to add an ICollection to a Create view?

I'm using Entity Framework Code First to generated my database, so I have an object defined like the following:
public class Band
{
public int Id { get; set; }
[Required(ErrorMessage = "You must enter a name of this band.")]
public string Name { get; set; }
// ...
public virtual ICollection<Genre> Genres { get; set; }
}
Now I'm looking at a create view for this and the default scaffolding isn't adding Genres to my form, which from past experience is about what I expect.
Looking online I've found Using ASP.NET MVC v2 EditorFor and DisplayFor with IEnumerable<T> Generic types which seems to come closest to what I want, but doesn't seem to make sense with Razor and possibly MVC 3, per ASP.NET MVC 3 Custom Display Template With UIHint - For Loop Required?.
At present I've added the listing of genres to the ViewBag and then loop through that listing in my create view:
#{
List<Genre> genreList = ViewBag.Genres as List<Genre>;
}
// ...
<ul>
#for (int i = 0; i < genreList.Count; i++)
{
<li><input type="checkbox" name="Genres" id="Genre#(i.ToString())" value="#genreList[i].Name" /> #Html.Label("Genre" + i.ToString(), genreList[i].Name)</li>
}
</ul>
Outside of not yet handling cases where the user has JavaScript disabled and the checkboxes need to be re-checked, and actually updating the database with this information, it does output the genres as I'd like.
But this doesn't feel right, based on how good MVC 3 has become.
So what's the most effective way to handle this in MVC 3?
I don't send lists into my View via the ViewBag, instead I use my viewmodel to do this. For instance, I did something like this:
I have an EditorTemplate like this:
#model IceCream.ViewModels.Toppings.ToppingsViewModel
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x =x> x.Name, new { #readonly="readonly"})
#Html.CheckBoxFor(x => x.IsChecked)
</div>
which I put in my Views\IceCream\EditorTemplates folder. I use this to display some html for allowing the user to "check" any particular topping.
Then in my View I've got something like this:
#HtmlEditorFor(model => model.Toppings)
and that will use that result in my EditorTemplate being used for each of the toppings in the Toppings property of my viewmodel.
And then I've got a viewmodel which, among other things, includes the Toppings collection:
public IEnumerable<ToppingsViewModel> Toppings { get; set; }
Over in my controller, among other things, I retrieve the toppings (however I do that in my case) and set my viewmodel's property to that collection of toppings. In the case of an Edit, where toppings may have been selected previously, I set the IsChecked member of the TopingsViewModel and it'll set the corresponding checkboxes to checked.
Doing it this way provided the correct model binding so that when the user checked a few toppings, the underlying items in the collection reflected those selections. Worked well for me, hope it's helpful for you.

asp.net MVC "Add View" wizard won't pre-populate fields when using a ViewModel

In VS 2010, When you use the "Add View" wizard to create an Edit view with a strongly typed view, such as Models.Person, the template generates all of Person fields for you.
If you use a view model instead, like this:
public class PersonVM
{
public Person person;
public List<Team> TeamList = new TeamServices().TeamPickList();
...
}
the template wont create all of the fields for Model.person.
Is there a way to make that work?
Not automatically.
Easiest method is to create a new View, select Team as the view data class, Select 'List' as the view content. Then you could cut and paste the markup generated from this view into the one you have already created.
If you use the List template it will normally create a table and iterate over an IEnumerable Model. You can also use one of the helpers and/or custom templates in your CodeTemplates folder:
<% Html.DisplayForModel(); %>
If you need to edit:
<% Html.EditorForModel(); %>
If you're having trouble with the list, maybe start with one of the helpers?
<%: Html.DropDownListFor(model => model.TeamList, new SelectList(Model.TeamList)) %>

MVC Transfer Data Between Views

I just started to learn MVC and am trying to understand how it works.
I don't want to send users to different views for all edit, insert and list operations.
In my sample application a View contains a list of items and below the list there is a form (for inserting new items) with action "{Controller}/Create" but there is no Create View.
When a user inserts a new item it posts to the Create action with httpverb post and creates the item and returns back to the List action with RedirectToAction method.
But I can not show any message(error, information etc) to the user in this style because I can not pass data between Create action and List action. How can I do that?
You need to use Post Redirect Get PRG pattern.
Please read this Use PRG Pattern for Data Modification section in this blog post by Kazi Manzur Rashid.
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx
This approach uses TempData to maintain ModelState data between redirects.
[HttpPost, ValidateAntiForgeryToken, ExportModelStateToTempData]
public ActionResult Create(FormCollection form)
{
Product p = new Product();
if (TryUpdateModel<IProductModel>(p))
{
productRepository.CreateProduct( p );
}
else
{
// add additional validation messages as needed
ModelState.AddModelError("_generic", "Error Msg");
}
return RedirectToAction("Index");
}
And here is your Index action method.
[ImportModelStateFromTempData]
public ActionResult Index()
{
IList<Product> products = productRepository.GetAll();
return View("Index", products);
}
And here is your Index view.
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IList<Product>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Products</h2>
<% foreach (var p in Model) { %>
<div><%= Html.Encode( p.ProductName ) %></div>
<% } %>
<%= Html.ValidationSummary("Please correct the errors", new { id = "valSumCreateForm" }) %>
<% using (Html.BeginForm("Create", "Product")) { %>
Product Name: <%= Html.TextBox("ProductName") %>
<%= Html.AntiForgeryToken() %>
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %>
<% } %>
</asp:Content>
The ImportModelStateFromTempData
and ExportModelStateToTempData
attributes helps transfer model
state errors between redirects. This
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %> associates the MVC Form with its corresponding Validation Summary.
You can check another answer by me on this here as well.
ViewModel with SelectList binding in ASP.NET MVC2
Let me know if you have any question.
-Soe
Most MVC frameworks have the ability to temporarily store a small bit of data just through the next request, for just this purpose. In ASP.NET MVC its called TempData, in Rails it's called :flash, etc.
This article explains how to use TempData:
One of the more annoying things to
deal with in Web programming is errors
on a form. More specifically, you want
to display error messages, but you
want to keep the previously entered
data. We've all had the experience of
making a mistake on a form that has 35
fields, only to be presented with a
bunch of error messages and a new,
blank form. The MVC Framework offers TempData as a place to store the previously entered information so that the form can be repopulated. This is
something that ViewState actually made
very easy in Web Forms, since saving
the contents of controls was pretty
much automatic. ... TempData is a dictionary,
much like the untyped ViewData.
However, the contents of TempData only
live for a single request and then
they're deleted.

Resources