Why doesn't Html.LabelFor work in a partial view? - asp.net-mvc-3

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.

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.

Creating View Models consisting of objects of other models in MVC3

I have a model and an enumerable of that model that I am putting together into a view model in asp.net mvc3 like so.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
namespace FuelPortal.Models.DBModels
{
public class UserDBModel
{
public int userId { get; set; }
[Required, Display(Name = "User Name")]
public string userName { get; set; }
[Required, Display(Name = "Password")]
public string password { get; set; }
[Required, Display(Name = "First Name")]
public string firstName { get; set; }
[Required, Display(Name = "Last Name")]
public string lastName { get; set; }
[Required, Display(Name = "Email")]
public string email { get; set; }
[Display(Name = "Phone")]
public string phone { get; set; }
[Display(Name = "Account Expiration Date(Optional)")]
public DateTime expireDate { get; set; }
[Display(Name = "Password Expiration Date")]
public DateTime passwordExpireDate { get; set; }
[Display(Name = "Last Date Modified")]
public DateTime DateModified { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FuelPortal.Models.DBModels;
namespace FuelPortal.Models.ViewModels
{
public class UserMaintenanceViewModel
{
public UserDBModel user = new UserDBModel();
public List<UserDBModel> userList = new List<UserDBModel>();
}
}
Now I strongly type a view to use the view model.
#model FuelPortal.Models.ViewModels.UserMaintenanceViewModel
<div class="frmBG">
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "wrapperData" }))
{
<h5>Create New User</h5>
<br />
<table cellpadding="2" cellspacing="10" border="0">
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.userName)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.userName)
#Html.ValidationMessageFor(model => model.user.userName)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.password)
</div></td><td>
<div class="editor-field">
#Html.PasswordFor(model => model.user.password)
#Html.ValidationMessageFor(model => model.user.password)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.firstName)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.firstName)
#Html.ValidationMessageFor(model => model.user.firstName)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.lastName)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.lastName)
#Html.ValidationMessageFor(model => model.user.lastName)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.email)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.email)
#Html.ValidationMessageFor(model => model.user.email)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.phone)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.phone)
#Html.ValidationMessageFor(model => model.user.phone)
</div></td></tr>
<tr><td>
<div class="editor-label">
#Html.LabelFor(model => model.user.expireDate)
</div></td><td>
<div class="editor-field">
#Html.EditorFor(model => model.user.expireDate)
#Html.ValidationMessageFor(model => model.user.expireDate)
</div></td></tr>
<tr><td></td><td>
<p>
<input type="submit" value="" class="create" /><input type="button" value="" class="close_tab"/>
</p></td></tr>
</table>
}
</div>
For some reason on post it does not populate the object within the view model. So when i create a post action all values of (UserMaintenanceViewModel model) are null. Like so..
[HttpPost]
public ActionResult CreateUser(UserMaintenanceViewModel model)
{
try
{
/// TODO: Add insert logic here
var result = repository.insertNewUser(Session["UserId"].ToString(), model.user.UserName, model.user.Password, model.user.FirstName,
model.user.LastName, model.user.Email, model.user.Phone, model.user.ExpireDate);
// If result > 0 user insert successful
Also, if I switch to getting postback through a (FormCollection form) I see that the names of the html elements are "user.UserName" instead of the expected "UserName". Any guidance would be greatly appreciated I feel like I should be able to accomplish this.
Thanks so much
If you have a complex view model which is what you have, then you have to make sure to create instance of an object in the constructor. You can then add info to any child object since it now has an instance.
public class MyViewModel
{
public MyViewModel()
{
Customer= new CustomerViewModel ();
Address = new AddressViewModel();
}
public int OrderNumber{ get; set; }
public CustomerViewModel Customer { get; set; }
public AddressViewModel Address { get; set; }
}
}

ASP.Net MVC 3 Data Annotation

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")

Using an interface as the model type of a partial view + data annotations

I have a case where a complex partial view needs different validation of fields depending on where the partial view is used.
I thought I could get around this by making the partial view take an interface as the model type and implementing two different ViewModels based on the interface. The data annotations in the two ViewModels would be different. I would then supply an instance of the correct ViewModel to the partial view.
But what I'm finding is that the only annotations that are recognized are those on the interface itself. DAs on the interface-implementing ViewModel classes are ignored, even though those are the objects that are being passed as models. So my plan isn't working.
Is there a way around this? A better approach? I'd prefer not to split the partial view into separate views if I can avoid it.
ETA: This is an abbreviated version of the partial view, as requested:
#model IPerson
#Html.ValidationSummary(false)
<fieldset>
<table class="editForm">
<tr>
<td class="editor-label">
#Html.LabelFor(model => model.FirstName)
</td>
<td class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</td>
<td class="editor-label">
#Html.LabelFor(model => model.LastName)
</td>
<td class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</td>
</tr>
</table>
<fieldset>
The real partial view is quite long and has a lot of #if statements managing the rendering (or not) of optional sections, but it doesn't do anything tricky.
My idea isn't going to work: this thread reminded me that classes don't inherit attributes from their interfaces. (As the answer points out, what would happen if two interfaces specified the same property with different attributes, and both were implemented by one class?)
It might work with a common base class. I will try that tomorrow.
Thanks, everybody.
Ann, you're right. I've deleted my comment. You can't post an interface back through your view. However, I don't know what exactly your trying to do since I can't see your code. Maybe something like this? I'm passing an interface to the view, but passing it back as the class I'm expecting. Again, I'm not sure the application is here.
Let's say you have classes like this:
[MetadataType(typeof(PersonMetaData))]
public class Customer : IPerson {
public int ID { get; set; }
public string Name { get; set; }
[Display(Name = "Customer Name")]
public string CustomerName { get; set; }
}
public class Agent : IPerson {
public int ID { get; set; }
public string Name { get; set; }
}
public partial class PersonMetaData : IPerson {
[Required]
public int ID { get; set; }
[Required]
[Display(Name="Full Name")]
public string Name { get; set; }
}
public interface IPerson {
int ID { get; set; }
string Name { get; set; }
}
public interface IAgent {
int AgentType { get; set; }
}
public interface ICustomer {
int CustomerType { get; set; }
}
Your Controller looks like:
public ActionResult InterfaceView() {
IPerson person = new Customer {
ID = 1
};
return View(person);
}
[HttpPost]
public ActionResult InterfaceView(Customer person) {
if (ModelState.IsValid) {
TempData["message"] = string.Format("You posted back Customer Name {0} with an ID of {1} for the name: {2}", person.CustomerName, person.ID, person.Name);
}
return View();
}
And your View Looks like this:
#model DataTablesExample.Controllers.Customer
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#if (#TempData["message"] != null) {
<p>#TempData["message"]</p>
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>IPerson</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CustomerName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CustomerName)
#Html.ValidationMessageFor(model => model.CustomerName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Well, actually you have a very reasonable idea! and can be archived is you use the non generic version of the HtmlHelper methods (ex. "#Html.Editor" instead of "#Html.EditorFor"), because the generic versions recreate the ModelMetadata (i don't know why!) based on the generic parameter type and don't use the ModelMetadata of the view. Freaking awful, isn't it?
Hope this help.

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