viewmodel return null on HttpPost - asp.net-mvc-3

i have created a view like below.
<%for (var i = 0; i < Model.customerCDTO.Count();i++)
{%>
<tr>
<td style="text-align: center; width: 10%;" class="table-content-middle">
<%if (Model.customerCDTO[i].Active == true)
{%>
<%=Html.CheckBoxFor(m=>m.customerCDTO[i].Active)%>
<%}
else
{ %>
<%=Html.CheckBoxFor(m => m.customerCDTO[i].Active)%>
<%} %>
</td>
<td class="table-content-middle" align="center" style="width: 80%;">
<%=Html.DisplayTextFor(m=>m.customerCDTO[i].Name)%>
</td>
</tr>
<%} %>
the problem with the above view is that it is giving value for null for customerCDTO[i].Name
below is my view model
public class CustomerVM
{
public List<CustomerCDTO> customerCDTO { get; set; }
}
In the above view model I have created a List property. The CustomerCDTO class definition is as follows.
public class CustomerCDTO
{
public string Name { get; set; }
public bool Active { get; set; }
public bool? IsChecked { get; set; }
}
please help.
thanks

It's giving you a null value because your form does not contain any <input> elements corresponding to the Name property (which you can immediately spot if you View Source). The reason for this is that DisplayTextFor is not supposed to create such elements in the first place.
An almost always bad idea would be to also call Html.HiddenFor, which does create input elements:
<td class="table-content-middle" align="center" style="width: 80%;">
<%=Html.DisplayFor(m=>m.customerCDTO[i].Name)%>
<%=Html.HiddenFor(m=>m.customerCDTO[i].Name)%>
</td>
This would solve your problem, but then the user could simply edit the values with a tool like Firebug and change the value of Name, which you obviously do not want since otherwise you 'd have presented an <input> element for that. (Note: I also changed DisplayTextFor to DisplayFor, which in general is the more correct way to do things).
But what to do then? Well, there's no magic solution here. If the form doesn't contain Name then it will be null, but if it does contain Name (even hidden) then the user can change it at will. If that's a problem, the only option is to modify your backend code to populate Name from your data store.

Could you make sure that your list is populated with your intended data after running your query against database. In fact, it seems like your data is not populated properly.

Related

ASP.NET MVC 3 WITH RAZOR : How to pass selected checkbox' ids in a Partial view to controller action?

I have a partialview [_SearchProduct] within the main view, let's say [product] view. The Partialview has a number of checkboxes segregated into different sections like search by company,search by product etc. with one [search] button.
A User can select multiple checkboxes. When user clicks [search] button I need to pass ids of all selected checkbox to controller action and re-render the page again considering the user's selection . Please guide me how to pass selected checkbox ids to my controller action.
My partial view is something like below:
<fieldset>
<legend>By Company</legend>
<table style="border-style: none;">
<tr>
#{
int i = 0;
foreach (var item in Model.CompanyName)
{
i = i + 1;
<td style="border-style: none;text-decoration:none;" >
#Html.CheckBox("chkCompany",new {id="chkCompany_" + Model.CompanyId.Tostring()}) #Model.CompanyName
</td>
if (i == 5)
{
#:</tr><tr>
i = 0;
}
}
}
</tr>
</table>
</fieldset>
<fieldset>
<legend>By Product</legend>
<table style="border-style: none;">
<tr>
#{
i = 0;
foreach (var item in Model.Product)
{
i = i + 1;
<td style="border-style: none;text-decoration:none;" >
#Html.CheckBox("chkProduct",new {id="chkProduct_" + Model.CompanyId.Tostring()}) #Model.ProductName
</td>
if (i == 10)
{
#:</tr><tr>
i = 0;
}
}
}
</tr>
</table>
</fieldset>
checkboxes are dynamic
Checkbox id represent the primarykey of respective table based on which i do filtering.
Please guide me>>
So it sounds like you have a structure containing names (of companies/products), and ids.
I would create a View Model structure that looked like
public class PartialViewModel //Make sure this is included in your main view model
{
public List<ObjectsToInclude> Companies { get; set; }
public List<ObjectsToInclude> Products { get; set; }
}
public class ObjectsToInclude //Give this a better name
{
public string Name { get; set; }
public string Id { get; set; }
public bool Include { get; set; }
}
Then in order to bind them you could do
for (int i =0; i<Model.Companies.Count(); i++)
{
<td style="border-style: none;text-decoration:none;" >
#Html.HiddenFor(m => m.Companies[i].Id)
#Html.CheckBoxFor(m => m.Companies[i].Include) #Model.Companies[i].Name
</td>
if (i == 5)
{
#:</tr><tr>
i = 0;
}
}
Then provided your post takes a parameter of PartialViewModel (or some MainViewModel where that contains an instance of PartialViewModel), you'll have lists of companies and products binded. You can loop through the list, and take the respective ids of anything checked to be included.
Edit: If you wanted a single comma separated array to be posted, it would be possible by by creating an onclick event for your checkboxes, and then setting a value of a hidden input every time a checkbox is clicked. But then your code would only work with JavaScript enabled. If you need a comma separated string, you can create it server side with the view model I suggested.
string companyIds = String.Join(",", model.Companies
.Where(company => company.Include)
.Select(company => company.Id));
http://dotnetnsqlcorner.blogspot.in/2012/09/multiple-checkboxes-in-mvc-3-and-post.html

View model property is null on POST in MVC3

I have an issue with my view where on HTTP POST the view model returns null for all of my properties.
Below is my view model.
public class CustomerVM
{
public List<CustomerCDTO> customerCDTO { get; set; }
}
In the above view model I have created a List<CustomerCDTO> property. The CustomerCDTO class definition is as follows.
public class CustomerCDTO
{
public string Name { get; set; }
public bool Active { get; set; }
public bool? IsChecked { get; set; }
}
Below is my view:
<%foreach (var item in Model.customerCDTO) {%>
<tr>
<td style="text-align: center; width: 10%;" class="table-content-middle">
<%if (item.Active == true)
{%>
<%=Html.CheckBoxFor(m=>item.Active)%>
<%}
else
{ %>
<%=Html.CheckBoxFor(m=>item.Active)%>
<%}%>
</td>
<td class="table-content-middle" align="center" style="width: 80%;">
<%: item.Name%>
</td>
</tr>
<%} %>
When I perform an HTTP GET everything works as expected but on POST I am getting null for CustomerVM.customerCDTO.
Please suggest what should I do to make it work.
thanks,
That's because you are not getting to each CustomerCDTO with expressions containing the information that it's part of a List.
Use a for loop instead:
<%for (var i = 0; i < Model.customerCDTO.Count; ++i)
And refer to the elements with expressions like
<%=Html.CheckBoxFor(m => m.customerCDTO[i].Active)%>
Basically you need to have the expression m => ... resolve to the property you are interested in starting from m, not from some other variable.

MVC3 Some of my fields validate while some do not

Im sitting here scratching my head with a validation problem in ASP MVC3.
Somehow I'm able to validate the field Quantity, but the field OrderNumber does not validate. I can leave it empty and it still accepts it. I've tried to add other restrictions to it as well (such as max and min length) but same result - it accepts anything.
I also try changing 'TextBoxFor' to 'EditorFor' - but it's the same result.
Quantity on the other hand works as I want it. It requires you to enter an integer and it cannot be blank.
Hopefully some of you will be able to see what I'm doing wrong here :)
Here is my model:
public class Order
{
[Required(ErrorMessage="Insert Ordernumber (6-digits)")]
public string OrderNumber { get; set; }
[Required]
public string Partnumber { get; set; }
[Required]
public long Quantity { get; set; }
public Order()
{
}
}
And here is my view :
model POWeb.Models.AddModel
#using (Html.BeginForm("Add", "Home", FormMethod.Post))
{
//Create table
<table>
<tr>
<td>Select Partnumber to produce</td>
<td>#Html.DropDownListFor(model => model.SelectedPartNumber, Model.PartNumbers)</td>
</tr>
<tr>
<td>Enter PO number</td>
<td>#Html.TextBoxFor(model => model.OrderNumber)#Html.ValidationMessageFor(model => model.OrderNumber)</td>
</tr>
<tr>
<td>Quantity</td>
<td>#Html.TextBoxFor(model => model.Quantity)#Html.ValidationMessageFor(model => model.Quantity)</td>
</tr>
<tr>
<td colspan="2">
<button type="submit" name="SubmitButton">Add</button>
</td>
</tr>
</table>
}
You have the view of type POWeb.Models.AddModel, but you try to validate Order type. I'm pretty sure validation attributes on those types are not the same, so you get problems
Anders,
My 'guess' is that your ViewModel model POWeb.Models.AddModel isn't mirroring the [Required] attribute on OrderNumber. Can you add the definition of AddModel to your question for verification on that please as it's more than likely that the Order class differs.

How can I retrieve the List in my controller?

My controller always gets "null" for the "adjModel" parameter.
How can I retrieve the values?
CONTROLLER
[HttpPost]
public ActionResult AdjustmentList(List<AdjustmentVM> adjModel)
{
// adjModel is null
}
VIEW
#model List<ExtFramework.ViewModels.BillingArea.AdjustmentVM>
<div class="no-fancybox">
#using (Html.BeginForm("AdjustmentList", "Deposit", new { depositId = ViewBag.depositId }))
{
<div>
<table id="adjustment">
<tr>
<th>Description</th>
<th>Montant</th>
</tr>
#foreach(var item in Model)
{
<tr>
<td>#Html.TextBoxFor(model => item.Description)</td>
<td>#Html.TextBoxFor(model => item.Amount)</td>
</tr>
}
</table>
<input type="submit" value="" class="save" />
</div>
}
</div>
MODEL
namespace ExtFramework.ViewModels.BillingArea
{
public class AdjustmentVM
{
public int AdjustmentId { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
public int DepositId { get; set; }
}
}
This is where editor templates are useful. Instead of using a foreach loop to go through the list of view models, use #Html.EditorFor(m => m). Then, in a subfolder named EditorTemplates (an MVC naming convention) add a view with the name AdjustmentVM.cshtml. Again, this is another MVC naming convetion - using the name of the type being used. This file would look like:
#model AdjustmentVM
<tr>
<td>#Html.TextBoxFor(model => model.Description)</td>
<td>#Html.TextBoxFor(model => model.Amount)</td>
</tr>
The runtime will automatically loop over the items in the list and render the contents of the editor template, giving unique names for each form value, so that the default model binder can map these to the properties on the view model on postback.
You can customise the name of the editor template if you want, look a the UIHintAttribute class.
By default, when you want a collection, you need to make sure the names of the controls indicate they are from an array, etc. The default binder doesn't have this magic to my knowledge.

MVC3 - jQuery unobtrusive validation

I am new to MVC and need some guidance for the problem that I am running into.
I have a text field to contain Date using date picker. In the model, I didn't specify to validate the text field.
But I submit the form, the jQuery unobstrusive validates the date text field.
The model
Using System;
Using System. Collections. Generic;
Using System. ComponentModel;
Using System. ComponentModel. DataAnnotations;
Using System. Linq;
Using System. Web;
Using DataAnnotationsExtensions;
Namespace heavy_haulage_general_freight. Models
{
public class nsc_gf_job
{
[Key]
public int id { get; set; }
public DateTime pickup_date { get; set; }
}
}
The View
#model heavy_haulage_general_freight. Models. Nsc_gf_job
#using heavy_haulage_general_freight. Helpers
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html. BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Resources Division Heavy Haulage Details:</legend>
<table>
<tbody>
<tr>
<td>#Html.Label("Pickup Date")</td>
<td>
#Html.TextBox("pickup_date", "") <br />
#Html.ValidationMessage("pickup_date")
</td>
<tr>
</tbody>
</table>
</fieldset>
<p>
<input type="submit" value="Create" />
</p>
}
Try using a nullable date - ie
public DateTime? pickup_date { get; set; }
also note this applies to ints as well, as there is no 'empty' default for an int, you need a nullable value
That happens because you have defined the property of type DateTime in your model. Validation will always happen for this type because you cannot assign an invalid value to such field.

Resources