MVC3 Some of my fields validate while some do not - asp.net-mvc-3

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.

Related

viewmodel return null on HttpPost

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.

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 collection model binding with EditorFor

Regarding this post and this other one.
Suppose I have the following:
public class Foo
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class BarViewModel
{
public string Baz { get; set; }
public IList<Foo> Foos { get; set; }
}
And I have a view that receive a BarViewModel:
#model BarViewModel
#Html.EditorFor(model => model.Baz)
<table>
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
string name1 = "Foos[" + i.ToString() + "].Value1";
string name2 = "Foos[" + i.ToString() + "].Value2";
<tr>
<td>
<input type="text" name="#name1" value="#Model.Foos[i].Value1" />
</td>
<td>
<input type="text" name="#name2" value="#Model.Foos[i].Value2" />
</td>
</tr>
}
</table>
And in my controller I have a POST method that recive the BarViewModel.
Given the inputs names generated for Value1 and Value2 are "Foos[0].Value1" and "Foos[1].Value1" and so on, the collection on the BarViewModel, in the POST method, is automatically filled by the ModelBinder. Awesome.
The problem is, if I do it this way in my view :
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
<tr>
<td>
#Html.EditorFor(model => model.Foos[i].Value1);
</td>
<td>
#Html.EditorFor(model => model.Foos[i].Value2);
</td>
</tr>
}
Then the names generated for the input are like "Foos__0__Value1", and that break the model binding. The Foos property of my BarViewModel, in my POST method, is now null
I am missing something?
Edit
If I use EditorFor on the collection itself:
#EditorFor(model => model.Foos)
The names are generated correctly. But that force me to build a ViewModel in /Views/Share to handle the type Foos, that will generate the row, wich I dont really want to do...
Edit 2
I will clarify my question here, I understand that it's a bit vague.
If I do :
#EditorFor(model => model.Foos)
The names of the inputs will have the form "Foos[0].Value1" and the model binding works just fine on posts.
But if I do :
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
#EditorFor(model => Model.Foos[0].Value1)
}
The names takes the form "Foos__0__Value1" and the model binding does not works. On my post method, model.Foos will be null.
Is there a reason why the second syntax breaks the model binding?
I'm not entirely sure just exactly what your question is. However, this is how MVC works. EditorFor uses EditorTemplates, and you define an editor template for your type. It doesn't have to go in Share, it can go in whatever level you're using. For instance, you can have it at /Views/Home/EditorTemplates/Foos.cshtml, so long as you aren't using it anywhere other than your Home controller.

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