ASP.Net MVC 3 Data Annotation - asp.net-mvc-3

I am building an ASP.Net MVC 3 Web application using Entity Framework 4.1. To perform validation within one of my Views which accepts a ViewModel. I am using Data Annotations which I have placed on the properties I wish to validate.
ViewModel
public class ViewModelShiftDate
{
public int shiftDateID { get; set; }
public int shiftID { get; set; }
[DisplayName("Start Date")]
[Required(ErrorMessage = "Please select a Shift Start Date/ Time")]
public DateTime? shiftStartDate { get; set; }
[DisplayName("Assigned Locum")]
public int assignedLocumID { get; set; }
public SelectList AssignedLocum { get; set; }
}
View
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<br />
<div class="editor-label">
#Html.LabelFor(model => model.shiftStartDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.shiftStartDate, new { #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.shiftStartDate)
</div>
<br />
<div class="editor-label">
#Html.LabelFor(model => model.assignedLocumID)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.assignedLocumID, Model.AssignedLocum)
#Html.ValidationMessageFor(model => model.assignedLocumID)
</div>
<br />
<p>
<input type="submit" value="Save" />
</p>
<br />
}
The SelectList 'AssignedLocum' is passed into my View for a DropDownList, and the item selected is assigned to the property 'assignedLocumID'.
As you can see from my ViewModel, the only required field is 'shiftStartDate', however, when I hit the Submit button in my View, the drop down list 'AssignedLocum' also acts a required field and will not allow the user to submit until a value is selected.
Does anyone know why this property is acting as a required field even though I have not tagged it to be so?
Thanks.

Try to use default value for dropdown (for example "Please select")
#Html.DropDownListFor(model => model.assignedLocumID, Model.AssignedLocum, "Please select")

Related

How do i put validation on checkbox with MVC3 razor?

I have created the register page on mvc3 razor. I want to put the validation on user notification field. Below is my code.
[Required]
[Display(Name = "Student Notification ?")]
[Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")]
public Boolean UserNotification { get; set; }
Below is my register page view
<div class="editor-label">
#Html.LabelFor(model => model.UserNotification)
</div>
<div class="editor-label">
#Html.CheckBoxFor(model =>model.UserNotification)
#Html.ValidationMessageFor(model => model.UserNotification)
</div>
<p>
<input type="submit" value="Register" />
</p>
So when i will click the button, there should be validation message there ..
You need to change your datatype of the property UserNotification. Change:
public Boolean UserNotification { get; set; }
To:
public bool UserNotification { get; set; }
There is a lot difference between Boolean and bool.

Why doesn't Html.LabelFor work in a partial view?

I thought I have asked this before, but I am not finding it. I am making partial view for a form so I can use it in multiple places. Here is one short snippet:
#model Permits.Domain.Entities.PermitRequest
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.JobAddress)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.JobAddress)
#Html.ValidationMessageFor(model => model.JobAddress)
</div>
<p>
<input type="submit" value="Submit request" />
</p>
</fieldset>
}
My model looks like:
public class PermitRequest
{
[Description("Job address")]
public string JobAddress { get; set; }
}
Why would my label still be "JobAddress" instead of "Job Address" (with the space)? I feel like I am missing something obvious.
[DisplayName("Job address")]
public string JobAddress { get; set; }
or if you prefer:
[Display(Name = "Job address")]
public string JobAddress { get; set; }
Both set the DisplayName property of the ModelMetadata which is used by the LabelFor helper.

MVC 3 edit view for certain fields only

I have this model:
public class ExchangeRate
{
[Key]
public int ExchangeRateID { get; set; }
[Required]
[Display(Name = "Currency:")]
public string Currency { get; set; }
[Required]
public decimal Rate { get; set; }
}
The "Create" view is working fine, but when I am in the edit view, I only want the Currency property to be displayed, and not editable. How should I do this? If I create another "view-only" model for this class, then I would omit the "Currency" property and would not be able to display it.
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ExchangeRate</legend>
#Html.HiddenFor(model => model.ExchangeRateID)
<div class="editor-label">
#Html.LabelFor(model => model.Currency)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.Currency)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Rate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Rate)
#Html.ValidationMessageFor(model => model.Rate)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Changing #Html.EditorFor(model => model.Currency) to #Html.DisplayFor(model => model.Currency) doesn't work because the model state becomes invalid when it posts back to the controller.
You could add
#Html.HiddenFor(model => model.Currency)
in your form and then use
#Html.DisplayFor(model=> model.Currency)
to display the readonly value of the currency property. That way when you post the value will be sent along in the posted model.
You're looking for:
[HiddenInput(DisplayValue=true)]
Then show the editor, not the display (use EditorFor).
This displays the value read-only, but adds a hidden input so that the posted state is valid.
To display the currency but not edit it try
#Html.Label("Currency", Model.Currency)
if you also need to post the currency value back to the controller try
#Html.HiddenFor(m => m.Currency)
I hope this helps.

MVC binding to model with list property ignores other properties

I have a basic ViewModel with a property that is a List of complex types. When binding, I seem to be stuck with getting either the list of values, OR the other model properties depending on the posted values (i.e. the view arrangement).
The view model:
public class MyViewModel
{
public int Id { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public List<MyDataItem> Data { get; set; }
}
public class MyDataItem
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
The controller actions:
public ActionResult MyForm()
{
MyViewModel model = new MyViewModel();
model.Id = 1;
model.Data = new List<MyDataItem>()
{
new MyDataItem{ Id = 1, ParentId = 1, Name = "MyListItem1", Value = "SomeValue"}
};
return View(model);
}
[HttpPost]
public ActionResult MyForm(MyViewModel model)
{
//...
return View(model);
}
Here is the basic view (without the list mark-up)
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>My View Model</legend>
#Html.HiddenFor(model => model.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Property1)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Property1)
#Html.ValidationMessageFor(model => model.Property1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Property2)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Property2)
#Html.ValidationMessageFor(model => model.Property2)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
When posted back to the controller, I get the 2 property values and a null value for the 'Data' property as expected.
If I add the mark-up for the List as follows (based on the information in this Scott Hanselman post and Phil Haack's post):
<div class="editor-field">
#for (int i = 0; i < Model.Data.Count(); i++)
{
MyDataItem data = Model.Data[i];
#Html.Hidden("model.Data[" + i + "].Id", data.Id)
#Html.Hidden("model.Data[" + i + "].ParentId", data.ParentId)
#Html.Hidden("model.Data[" + i + "].Name", data.Name)
#Html.TextBox("model.Data[" + i + "].Value", data.Value)
}
</div>
The 'Data' property of the model is successfully bound but the other properties are null.
The form values posted are as follows:
Id=1&Property1=test1&Property2=test2&model.Data%5B0%5D.Id=1&model.Data%5B0%5D.ParentId=1&model.Data%5B0%5D.Name=MyListItem1&model.Data%5B0%5D.Value=SomeValue
Is there a way to get both sets of properties populated or am I just missing something obvious?
EDIT:
For those of you who are curious. Based on the answer from MartinHN, the original generated mark-up was:
<div class="editor-field">
<input id="model_Data_0__Id" name="model.Data[0].Id" type="hidden" value="1" />
<input id="model_Data_0__ParentId" name="model.Data[0].ParentId" type="hidden" value="1" />
<input id="model_Data_0__Name" name="model.Data[0].Name" type="hidden" value="MyListItem1" />
<input id="model_Data_0__Value" name="model.Data[0].Value" type="text" value="SomeValue" />
</div>
The new generated mark-up is:
<div class="editor-field">
<input id="Data_0__Id" data-val="true" name="Data[0].Id" type="hidden" value="1" data-val-number="The field Id must be a number." data-val-required="The Id field is required." />
<input id="Data_0__ParentId" name="Data[0].ParentId" type="hidden" value="1" data-val="true" data-val-number="The field ParentId must be a number." data-val-required="The ParentId field is required." />
<input id="Data_0__Name" name="Data[0].Name" type="hidden" value="MyListItem1" />
<input id="Data_0__Value" name="Data[0].Value" type="text" value="SomeValue" />
</div>
Which results in the following posted values:
Id=1&Property1=test1&Property2=test2&Data%5B0%5D.Id=1&Data%5B0%5D.ParentId=1&Data%5B0%5D.Name=MyListItem1&Data%5B0%5D.Value=SomeValue
Notice there's no 'model.' in the name and posted values...
Try to change the code for the Data collection to this, and let MVC take care of the naming:
<div class="editor-field">
#for (int i = 0; i < Model.Data.Count(); i++)
{
#Html.HiddenFor(m => m.Data[i].Id)
#Html.HiddenFor(m => m.Data[i].ParentId)
#Html.HiddenFor(m => m.Data[i].Name)
#Html.TextBoxFor(m => m.Data[i].Value)
}
</div>
Alternatively you could have created an EditorTemplate for your nested ViewModel as follows.
#model MyDataItem
#Html.HiddenFor(model => model.Id)
#Html.HiddenFor(model => model.ParentId)
#Html.HiddenFor(model => model.Name)
#Html.TextBoxFor(model => model.Value)
Create a folder named 'EditorTemplates' in your 'Shared' folder and save the above as 'MyDataItem.cshtml'.
Then in your View, just call the following instead of the foreach loop:
#Html.EditorFor(model => model.Data)
Feels a bit less hackier IMO :)
Just my 2 cents but something worth noting with this issue - the data member in the View Model must be defined as a public property for the postback model binding to work.
I had a very similar problem to the above but used a public data member in my View Model. The same HTML is generated as shown above and all looks well but the model binder threw back an empty collection. Worth watching for...

custom validator in asp.net mvc3

I have created a custom validator in my asp.net mvc3 application like this:
{
if (customerToValidate.FirstName == customerToValidate.LastName)
return new ValidationResult("First Name and Last Name can not be same.");
return ValidationResult.Success;
}
public static ValidationResult ValidateFirstName(string firstName, ValidationContext context)
{
if (firstName == "Nadeem")
{
return new ValidationResult("First Name can not be Nadeem", new List<string> { "FirstName" });
}
return ValidationResult.Success;
}
and I have decorated my model like this:
[CustomValidation(typeof(CustomerValidator), "ValidateCustomer")]
public class Customer
{
public int Id { get; set; }
[CustomValidation(typeof(CustomerValidator), "ValidateFirstName")]
public string FirstName { get; set; }
public string LastName { get; set; }
}
my view is like this:
#model CustomvalidatorSample.Models.Customer
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#using (#Html.BeginForm())
{
#Html.ValidationSummary(false)
<div class="editor-label">
#Html.LabelFor(model => model.FirstName, "First Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName, "Last Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
</div>
<div>
<input type="submit" value="Validate" />
</div>
}
But validation doesn't fire. Please suggest solution.
Thanks
How do you know the validation doesn't fire? Are you setting a break point in your controller?
You are not displaying any validation errors in your view. You need to add the following lines to the view.
#Html.ValidationMessageFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.LastName)
You will want to remove the custom validation from the class. Leave it on the properties though.

Resources