Popup dialog for editing record using Grid.MVC in a ASP.NET MVC3 - asp.net-mvc-3

I am using Grid.MVC available at http://gridmvc.azurewebsites.net/, which provides functionality for displaying the data in grid nicely, where filtering, sorting, paging is nicely done. This is the way the data in Grid looks at the moment.
So far so good. To display the data I am using the following controller and .cshtml
Controller
/// <summary>
/// Brings List Of Customers
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult CustomerList()
{
CustomerListViewModel custList = new CustomerListViewModel();
List<CustomerViewModel> custVMList = new List<CustomerViewModel>();
custVMList = custRepository.GetCustomers();
custList.customers = custVMList;
return View(custList);
}
The .cshtml for the same is
#model IEnumerable<DataAccess.Models.CustomerViewModel>
#*Using Twitter Bootstrap API*#
<link href="#Url.Content("~/Content/Gridmvc.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/gridmvc.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/js/bootstrap.min.js")" type="text/javascript"> </script>
<link href="#Url.Content("~/Content/bootstrap/css/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/bootstrap/css/bootstrap-responsive.min.css")" rel="stylesheet" type="text/css" />
#using GridMvc.Html
#{
ViewBag.Title = "Customers List";
}
#Html.Grid(Model).Columns(columns =>
{
columns.Add(m => m.CustomerName).Titled(" Name ").Sortable(true).SortInitialDirection(GridMvc.Sorting.GridSortDirection.Ascending).Filterable(true);
columns.Add(m => m.Address1).Titled("Address1").Sortable(true).Filterable(true);
columns.Add(m => m.Address2).Titled("Address2").Sortable(true).Filterable(true);
columns.Add(m => m.City).Titled("City").Sortable(true).Filterable(true);
columns.Add(m => m.County).Titled("County").Sortable(true).Filterable(true);
columns.Add(m => m.ContactName).Titled("Contact Name").Sortable(true).Filters.ToString();
columns.Add(m => m.Email).Titled("Email Address").Sortable(true).Filterable(true);
columns.Add(m => m.ReferenceNumber).Titled("Reference Number").Sortable(true).Filterable(true);
columns.Add(m => m.ModifiedOn).Titled("Modified On").Filterable(true).Sortable(true);
columns.Add(m => m.CustomerId)
.Titled("Edit")
.Sanitized(false)
.Encoded(false)
//.RenderValueAs(o => Html.ActionLink("Edit", "EditCustomer", "Customer", new { CustomerId = o.CustomerId }, new { title = "Please click here to edit the record", #class = "modal-link" }).ToHtmlString());
.RenderValueAs(d => Html.ActionLink("Edit", "EditCustomer", "Customer", new { CustomerId = d.CustomerId }, new { #class = "modal-link" }));
}).WithPaging(4)
<br />
<br />
#Html.ActionLink("Click to Add Customer", "AddCustomer", "Customer", new { #class = "modal-link" })
<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×</button>
<h3 id="myModalLabel">
Edit Customer</h3>
</div>
<div class="modal-body">
<p>
Loading…</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">
Close</button>
</div>
</div>
<script type="text/javascript">
//this script reset modal each time when you click on the link:
$(function () {
$(".modal-link").click(function (event) {
event.preventDefault();
$('#myModal').removeData("modal");
$('#myModal').modal({ remote: $(this).attr("href") });
});
})
</script>
When I click on Edit button, the complete record loads in the Popup window like below. By the way this is using Twitter Bootstrap styles.
So far so good.
The controller and .cshtml are
/// <summary>
/// Brings a Specific Customer
/// </summary>
/// <param name="CustomerId"></param>
/// <returns></returns>
[HttpGet]
public ActionResult EditCustomer(Guid CustomerId)
{
CustomerViewModel cusVM = custRepository.GetCustomer(CustomerId);
return View(cusVM);
}
/// <summary>
/// Editing Customer
/// </summary>
/// <param name="cusVM"></param>
/// <returns></returns>
[HttpPost]
public ActionResult EditCustomer(CustomerViewModel cusVM)
{
if (ModelState.IsValid)
{
custRepository.EditCustomer(cusVM);
return RedirectToAction("CustomerList", "Customer");
}
else
{
return PartialView(cusVM);
}
}
The .cshtml for the Edit customer is
#model DataAccess.Models.CustomerViewModel
#{
Layout = null;
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<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>
<div class="editor-label">
#Html.LabelFor(model => model.Address1)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address1)
#Html.ValidationMessageFor(model => model.Address1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Address2)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address2)
#Html.ValidationMessageFor(model => model.Address2)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.County)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.County)
#Html.ValidationMessageFor(model => model.County)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ContactName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ContactName)
#Html.ValidationMessageFor(model => model.ContactName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div>
#Html.HiddenFor(model => model.CustomerId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ReferenceNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ReferenceNumber)
#Html.ValidationMessageFor(model => model.ReferenceNumber)
</div>
<p>
<input type="submit" value="Save" class="btn btn-primary" />
</p>
</fieldset>
}
I am using server side validations. The customer model is.
using System.ComponentModel.DataAnnotations;
using System;
namespace DataAccess.Models
{
/// <summary>
/// Class Holds the List Of Properties of a Customer
/// </summary>
public class CustomerViewModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Customer Name")]
public string CustomerName { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Address1")]
public string Address1 { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Address2")]
public string Address2 { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "City")]
public string City { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "County")]
public string County { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "ContactName")]
public string ContactName { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name = "Email")]
public string Email { get; set; }
[DataType(DataType.Text)]
public Guid CustomerId { get; set; }
[DataType(DataType.Text)]
public string ReferenceNumber { get; set; }
[DataType(DataType.Date)]
public DateTime ModifiedOn{ get; set; }
}
}
When there are no validations errors then it saving the data and loading the customerList Grid page.
Problem
When there are validation errors its redirecting to a EditCustomer with validations messages. How can I make the validations errors to be displayed in the Popup window.
This is the way it displays the errors in a plain page.
.
How can I make the errors to be displayed in Popup window itself.

You need to look more closely at AJAX validation and client side validation. Basically what's happening is the partial view you are loading which contains your edit form does not have validation bound to it since it was loaded after the initial page load. You can try adding this to your page (JQuery):
$.validator.unobtrusive.parse('#formId');
where formId is the ID of your HTML form. You also need to use Ajax.BeginForm helper instead of Html helper you're using.
Beyond that take a look at post:
ASP.NET MVC client validation with partial views and Ajax

Related

Page to create object and sub object

I'm sure there have been tons of people asking this type of question but I can't quite figure out how to word it.
I will try to explain. I am working to model an ethernet network where devices have ip addresses. I've setup my entity framework models so that the ip and subnet are stored in a separate table to ensure uniqueness across the system.
I'd like the user to be able to create a device and its associated IP at the same time if the IP they want is not already in a dropdown list.
I setip a partial of the IP Address page RenderPartial on the device page and I get this error:
Here is the question, How do I fix this error:
The model item passed into the dictionary is of type PcnWeb.Models.Device, but this dictionary requires a model item of type PcnWeb.Models.IPAddress.
Here are my models:
IP Address Model:
namespace PcnWeb.Models
{
public class IPAddress
{
public virtual ICollection<Device> Devices { get; set; }
[Key]
public int ipAddressRecId { get; set; }
public Nullable<int> ipOctet1 { get; set; }
public Nullable<int> ipOctet2 { get; set; }
public Nullable<int> ipOctet3 { get; set; }
public Nullable<int> ipOctet4 { get; set; }
public Nullable<int> smOctet1 { get; set; }
public Nullable<int> smOctet2 { get; set; }
public Nullable<int> smOctet3 { get; set; }
public Nullable<int> smOctet4 { get; set; }
}
}
And the Device Model:
namespace PcnWeb.Models
{
public class Device
{
[Key]
public int deviceRecId { get; set; }
public int ipAddressRecId { get; set; }
[Required, StringLength(64)]
[Unique]
public string Name { get; set; }
[StringLength(256)]
public string Comment { get; set; }
public virtual IPAddress IPAddress { get; set; }
}
}
I would have thought that it would be pretty easy to have the associated device creation page with an inline ipaddress creation page.
Here's the Device page:
#model PcnWeb.Models.Device
#{
ViewBag.Title = "Create a Device";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Device</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ipAddressRecId, "IPAddress")
</div>
<div class="editor-field">
#Html.DropDownList("ipAddressRecId", String.Empty)
#Html.ValidationMessageFor(model => model.ipAddressRecId)
</div>
#{
Html.RenderPartial("~/Views/IP_Address/_Create.cshtml");
}
<div class="editor-label">
#Html.LabelFor(model => model.Name, "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.Comment, "Comment")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Comment)
#Html.ValidationMessageFor(model => model.Comment)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Here is the IP Address Partial:
EDIT: Sorry I forgot to include this
#model PcnWeb.Models.IPAddress
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>IPAddress</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ipOctet1, "ipOctet1")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ipOctet1)
#Html.ValidationMessageFor(model => model.ipOctet1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ipOctet2, "ipOctet2")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ipOctet2)
#Html.ValidationMessageFor(model => model.ipOctet2)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ipOctet3, "ipOctet3")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ipOctet3)
#Html.ValidationMessageFor(model => model.ipOctet3)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ipOctet4, "ipOctet4")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ipOctet4)
#Html.ValidationMessageFor(model => model.ipOctet4)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.smOctet1, "smOctet1")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.smOctet1)
#Html.ValidationMessageFor(model => model.smOctet1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.smOctet2, "smOctet2")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.smOctet2)
#Html.ValidationMessageFor(model => model.smOctet2)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.smOctet3, "smOctet3")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.smOctet3)
#Html.ValidationMessageFor(model => model.smOctet3)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.smOctet4, "smOctet4")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.smOctet4)
#Html.ValidationMessageFor(model => model.smOctet4)
</div>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So from all this, it looks great to me, the validation works client side. I'll have to write some javascript to hide the IP address partial unless they select new from the dropdown list.
Here is the question again, How do I fix this error:
The model item passed into the dictionary is of type PcnWeb.Models.Device, but this dictionary requires a model item of type PcnWeb.Models.IPAddress.
This errors means that there is mismatch between model type in your partial view and type of model passed to this view. But as i can see you trying to render the partial view without model passing.
Your code example worked for me.
So, to solve this problem you can do the next steps.
Ensure that the view path is right;).
Try so 'send' model to your partial view explicity like
main view
#model PcnWeb.Models.Device
//some code here
#Html.Partial("path_to_view", Model)
partial view.
#model PcnWeb.Models.Device
#Html.DropdownListFor(x=>x.ipAddressRecId, YourDlistSource) //or anything you need
this works for me.
Alternatively if you need edit submodel in partial view you can do this
#model PcnWeb.Models.Device
//some code here
#Html.Partial("path_to_view", Model.IPAddress)//pass the submodel to partial view
then your partial view must be with another type.
#model PcnWeb.Models.IPAddress
//some code here
Answer on comment. To resolve object reference exception try initialize your submodel in constructor.
public class Device
{
///properties
public Device()
{
IPAddress = new IPAddress();
}
}

updating relational database in asp .net mvc

I am developing a simple blog application to teach myself C# and asp .net mvc3.
I am stuck at a stage where I need to update comments to a post.
Comment class in my code is as follows:
public class Comment
{
public int CommentID { get; set; }
public string Name { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[DataType(DataType.MultilineText)]
public string CommentBody { get; set; }
public int BlogID { get; set; }
public virtual Blog Blog { get; set; }
}
I have a comment form on the blog details page which takes the name, email and comment. The code is as follow:
<div class="editor-label">
#Html.LabelFor(model => model.Comment.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Comment.Name)
#Html.ValidationMessageFor(model => model.Comment.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Comment.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Comment.Email)
#Html.ValidationMessageFor(model => model.Comment.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Comment.CommentBody)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Comment.CommentBody)
#Html.ValidationMessageFor(model => model.Comment.CommentBody)
</div>
<p>
<input type="submit" value="Add Comment" />
</p>
I am not sure how to pass the blogid with this so that the comment gets updated with the correct blogid.
thanks.
You could use a hidden field inside the form:
#Html.HiddenFor(x => x.Comment.BlogID)
#Html.HiddenFor(model => model.Comment.BlogID)

Partialview not returning model for a sortedlist

I am very, very new to MVC, so please bear with my question, I have to work with the following structure.
I have the following models, Facility and Address. Facility contains a SortedList of Address, I have reduced the number of properties for clarity,
public class AppFacility
{
public AppFacility()
{
this.Addresses = new SortedList<string, AppAddress>();
}
public SortedList<string, AppAddress> Addresses { get; set; }
[DisplayNameAttribute("Facility ID")]
public int FacilityID { get; set; }
[Required(ErrorMessage = "Facility Name is a required field")]
[DisplayNameAttribute("Facility Name")]
public string FacilityName { get; set; }
[DisplayNameAttribute("Doing Business As")]
public string Dba { get; set; }
[DisplayNameAttribute("Nbr. Of Employees")]
public int NbrOfEmployees { get; set; }
}
public class AppAddress
{
[DisplayNameAttribute("City")]
public string City { get; set; }
[DisplayNameAttribute("State")]
public string State { get; set; }
[DisplayNameAttribute("Street Name")]
public string StreetName { get; set; }
}
Controller:
[HttpPost]
public ActionResult FacilityCreate(AppFacility objFacility)
{
facilityManager = new Manager.AppFacilityManager();
if (facilityManager.InsertAppFacility(objFacility))
{
return RedirectToAction("FacilityInfo", new { id = objFacility.FacilityID });
}
return View((AppFacility)Session["FacilityObject"]);
}
View:
FacilityCreate
#model Model.CORE.BO.AppFacility
<table width="100%" align="center" border="0" class="SectionTables">
<tr>
<td class="SubtitleHeader">
Facility
</td>
</tr>
<tr>
<td class="SubtitleHeader1">
Enter Facility Information
</td>
</tr>
<tr>
<td align="center">
#Html.Partial(p_CreateEditAppFacility, Model)
</td>
</tr>
Partial view:
p_CreateEditAppFacility:
This contains the p_CreateEditAddress partial view as well.
#model Model.CORE.BO.AppFacility
#using (Html.BeginForm("FacilityCreate", "Form", FormMethod.Post,
new { id = "saveForm", name = "saveForm" }))
{
#Html.ValidationSummary(true)
<div class="main">
<fieldset>
<legend>Operator Information</legend>
<div class="editor-label">
#Html.Label("Facility Name (Business Name of Operator to Appear): ")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FacilityName)
#Html.ValidationMessageFor(model => model.FacilityName)
</div>
<div class="editor-label">
#Html.Label("Owner's Business Name (If different from Business Name of Operator): ")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Dba)
#Html.ValidationMessageFor(model => model.Dba)
</div>
<div class="editor-label">
#Html.Label("No of Employees:")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.NbrOfEmployees)
#Html.ValidationMessageFor(model => model.NbrOfEmployees)
</div>
</fieldset>
<fieldset>
<legend>Address Information</legend>
#{
int i = 0;
foreach (KeyValuePair<string, Model.CORE.BO.AppAddress> addressRow in Model.Addresses)
{
<div class="editor-field">
#Html.Partial(p_CreateEditAddress, addressRow.Value, new ViewDataDictionary(Html.ViewDataContainer.ViewData) { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = string.Format("objFacility.Addresses[{0}]", i) } })
</div>
i++;
}
}
</fieldset>
<p>
<input id="SaveFacility" name="SaveInfo" type="submit" value="Save Information" />
</p>
</div>
}
PartialView:
p_CreateEditAddress
#model Model.CORE.BO.AppAddress
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.StreetName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StreetName)
#Html.ValidationMessageFor(model => model.StreetName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.State)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.State)
#Html.ValidationMessageFor(model => model.State)
</div>
My question is that in the Controller the objFacility.Addresses does not get the values entered for the model AppAddress, it is always null. The AppFacility gets populated though.
The html behind looks like this for p_CreateEditAddress
<div class="editor-field">
<input class="text-box single-line"
id="objFacility_Addresses_0__StreetName"
name="objFacility.Addresses[0].StreetName" type="text" value="" />
<span class="field-validation-valid"
data-valmsg-for="objFacility.Addresses[0].StreetName" data-valmsg-replace="true"></span>
</div>
Please help.
You just need to change your Partial View call to take the correct prefix. You don't give it the Model name as the default model binder will be creating an instance of your class and looking for fields that match the names of the items in the Request.Form collection. It knows nothing about the variable name you've gave your model, just the properties of your Model's class.
Try this (I put line breaks in for readability):
#Html.Partial(p_CreateEditAddress, addressRow.Value,
new ViewDataDictionary(Html.ViewDataContainer.ViewData) {
TemplateInfo = new System.Web.Mvc.TemplateInfo {
HtmlFieldPrefix = string.Format("Addresses[{0}]", i)
}
})
I guess the generated HTML is not proper for model binding.
It should not be objFacility.Addresses[0].StreetName but Addresses[0].StreetName.

Select tab containing controls with validation errors

I have found something close to what I want to do here but not exactly.
I want to find the first tab that has a control which has a validation error and make that tab selected.
I have the JQUERY working to clicked through the tabs with next and previous links, now if I can just get to the tab with the validation errors that would be great.
MVC3 DataAnnotations are doing the validation. Any suggestion would be greatful. Note: I did shorten the model and view code.
What I want to do is when the button is clicked to "submit" the form and the validation is performed if any validation errors occurr then I would like the the first tab in the lists of tabs with a control that has a validation error to be selected.
Here is the view model.
public class RegistrationViewModel
{
[Required(ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "Required")]
[StringLength(50, ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "StringLength")]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[StringLength(100, ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "StringLength")]
[Display(Name = "Street")]
public string Street1 { get; set; }
public IEnumerable<SelectListItem> SecurityQuestionOneList { get; set; }
[Required(ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "Required")]
[Remote("DistinctSecurityQuestionOne", "Validation", AdditionalFields = "SecurityQuestionTwo, SecurityQuestionThree", ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "DistinctSecurityQuestions")]
public string SecurityQuestionOne { get; set; }
[Required(ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "Required")]
[StringLength(200, ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "StringLength")]
public string SecurityQuestionOneAnswer { get; set; }
}
Here is the code I have in my view.
#model SteadyPayCustomer.Models.RegistrationViewModel
#using Resources;
#{
ViewBag.Title = "Register";
}
<h2>Create a New Account</h2>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<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>
<script type="text/javascript">
$(document).ready(function () {
var $tabs = $('#tabs').tabs();
$(".ui-tab-panel").each(function (i) {
var totalTabs = $(".ui-tab-panel").size() - 1;
if (i != totalTabs) {
next = i + 2;
$(this).append("<a href='#' class='next-tab mover' rel='" + next + "'>Next Step »</a>");
}
if (i != 0) {
previous = i;
$(this).append("<a href='#' class='previous-tab mover' rel='" + previous + "'>« Previous Step</a>");
}
});
$(".next-tab, .previous-tab").click(function () {
$tabs.tabs('select', $(this).attr("rel"));
return false;
});
});
</script>
<div id="tabs">
<ul id="tabstyle">
<li><span style="color:#000000;font-weight:bold;font-size:12px">User</span></li>
<li><span style="color:#000000;font-weight:bold;font-size:12px">Contact</span></li>
<li><span style="color:#000000;font-weight:bold;font-size:12px">Security</span></li>
</ul>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div id="fragment-1" class="ui-tab-panel">
<fieldset>
<legend>User Information</legend>
<div class="editor-label">
#Html.Label(UserViewText.FirstNameLabel)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</fieldset>
</div>
<div id="fragment-2" class="ui-tab-panel">
<fieldset>
<legend>Customer Information</legend>
<div class="editor-label">
#Html.Label(CustomerGeneralViewText.Street1Label)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Street1)
#Html.ValidationMessageFor(model => model.Street1)
</div>
</fieldset>
</div>
<div id="fragment-3" class="ui-tab-panel">
<fieldset>
<legend>Security Questions</legend>
<div class="editor-label">
#Html.Label(SecurityQuestionsViewText.SecurityQuestionOneLabel)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SecurityQuestionOne, Model.SecurityQuestionOneList, string.Empty, Model.SecurityQuestionOne)
#Html.ValidationMessageFor(model => model.SecurityQuestionOne)
</div>
<div class="editor-label">
#Html.Label(SecurityQuestionsViewText.SecurityQuestionOneAnswerLabel)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SecurityQuestionOneAnswer)
#Html.ValidationMessageFor(model => model.SecurityQuestionOneAnswer)
</div>
<p>
<input type="submit" value="#General.FinishButtonText" />
</p>
</fieldset>
</div>
}
</div>

Required data annotation is not working on a DropDownlist inside my asp.net mvc3

i have defined the following in my validation model class
public class Visit_Validation
{
[Display(Name = "Assign to Doctor")]
[Required(ErrorMessage= "Please select a Doctor")]
public string DoctorID { get; set; }}
Then i have created the DoctorID Selectlist as follow:-
public ActionResult Create(int patientid)
{
Visit visit = new Visit();
var allusers = Membership.GetAllUsers();
ViewBag.DoctorID = new SelectList(allusers, "Username", "Username");
return View(visit);
}
and finally i define the dropdownlist at the view as follow:-
<div class="editor-label">
#Html.LabelFor(model => model.DoctorID)
</div>
<div class="editor-field">
#Html.DropDownList("DoctorID", String.Empty)
#Html.ValidationMessageFor(model => model.DoctorID)
</div>
but the problem i am facing is that incase the user leave the DoctorID dropdownlist empty then the [Required(ErrorMessage= "Please select a Doctor")] error will not be displayed? so what might be going wrong?
BR
Update:-
here is the full view code:-
<h2>Create</h2>
#section scripts{
<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>}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Visit</legend>
<div class="editor-label">
#Html.LabelFor(model => model.VisitTypeID, "VisitType")
</div>
<div class="editor-field">
#Html.DropDownList("VisitTypeID", String.Empty)
#Html.ValidationMessageFor(model => model.VisitTypeID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Date)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Date, new { value = "FL", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.Date)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Note)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Note)
#Html.ValidationMessageFor(model => model.Note)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DoctorID)
</div>
<div class="editor-field">
#Html.DropDownList("DoctorID", String.Empty)
#Html.ValidationMessageFor(model => model.DoctorID)
</div>
<div class="editor-label">
Visit Status
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.VisitStatu.Description, new { value = "FL", disabled = "disabled" })
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CreatedBy)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.CreatedBy, new { value = "FL", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.CreatedBy)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
here is the Post action method code:-
[HttpPost]
public ActionResult Create(Visit visit)
{
if (ModelState.IsValid)
{
visit.StatusID = repository.GetVisitStatusByDescription("Assinged");
visit.CreatedBy = User.Identity.Name;
visit.Date = DateTime.Now;
repository.AddVisit(visit);
repository.Save();
return RedirectToAction("Index");
}
ViewBag.DoctorID = new SelectList(Membership.GetAllUsers(), "Username", "Username");
ViewBag.StatusID = new SelectList(repository.FindAllVisitStatus(), "StatusID", "Description");
ViewBag.VisitTypeID = new SelectList(repository.FindAllVisitType(), "VisitTypeID", "Description");
return View(visit);
}
In order for validation to be triggered you need to have your POST controller action take the model as parameter:
[HttpPost]
public ActionResult Create(Visit visit)
{
...
}
or use the TryUpdateModel method:
[HttpPost]
public ActionResult Create()
{
Visit visit = new Visit();
if (!TryUpdateModel(visit))
{
// validation failed
}
...
}
When the form is submitted to this controller action the default model binder will invoke the validation rules contained in this Visit model. If your controller action never works with this model there's nothing out there that will ever interpret the data annotations that you put on it.

Resources