I've been having a hard time getting unobtrusive validation to work when submitting a form through an ajax request in my MVC 4 project. For reference, the person in this topic is doing almost the same thing I'm doing:
Manual form validation in MVC 3 and JQuery
I went through what was done there, but I still cannot get it to work. The issue is that when I do $("#Form").valid(), it always returns true, even though if I send the request, the model is not valid. I have the appropriate scripts set up in my bundles, but I cannot get the form to validate correctly client side. How can I make this validate correctly? I thought that once the data annotations were set up, it was "just supposed to work", but that clearly isn't the case here.
Also, this particular form is being loaded with jQuery in a Kendo UI window from a partial view as well. After looking at the answer on this post: Asp MVC unobtrusive Client Validation always returning true doing using the form id as the selector and .valid() still returns true, but the Class Name is false. However, the guid semester id returns true.
My code is below:
Model
public class Class
{
public Class()
{
ClassId = Guid.NewGuid();
}
[Key]
public Guid ClassId { get; set; }
[Display(Name = "Class Name")]
[Required(ErrorMessage = "A Class Name is required.")]
public string ClassName { get; set; }
public int UserId { get; set; }
[Display(Name = "Term Type")]
[Required(ErrorMessage = "The Term Type is required.")]
public Guid SemesterId { get; set; }
[ForeignKey("SemesterId")]
public virtual Semester Semester { get; set; }
[Display(Name = "Class Year")]
public int Year { get; set; }
[Display(Name = "Has Weighted Grades?")]
public bool HasWeightedGrades { get; set; }
public virtual List<Grade> Grades { get; set; }
}
Form
@using (Html.BeginForm("AddClass", "", FormMethod.Post, new { name = "AddNewClassForm", id = "AddNewClassForm" }))
{
<div>
<div>@Html.LabelFor(m => m.ClassName)</div>
<div>
@Html.TextBoxFor(m => m.ClassName, new { @class = "input-xlarge" })
@Html.ValidationMessageFor(m => m.ClassName)
</div>
<div>@Html.LabelFor(m => m.SemesterId)</div>
<div>
@Html.DropDownList("SemesterId", null, "-- Select a Term Type --", new { @class = "input-xlarge" })
@Html.ValidationMessageFor(m => m.SemesterId)
</div>
</div>
}
<div>
<button id="AddClassButton" class="btn btn-primary" type="submit"><i class="icon-plus icon-white"></i> Add Class</button>
<button id="CancelAddClassButton" class="btn btn-danger" type="submit"><i class="icon-ban-circle icon-white"></i> Cancel</button>
</div>
jQuery Event
//================================================================================================================================
// AddClassButton: Click event handlers.
//================================================================================================================================
$('#AddClassButton').unbind('click').bind('click', function (e) {
$.validator.unobtrusive.parse($('#AddClassWindow'));
var val = $("#AddNewClassForm").validate();
val.showErrors();
alert("Is the form valid? " + val.valid()); //Always returns true
alert("Is Class Name Valid? " + $("#ClassName").valid()); //Still returns true
alert("Is Semester Id Valid? " + $("#SemesterId").valid()); //Still returns true
e.preventDefault(); // Prevent this from doing default (possibly submit form).
e.stopPropagation(); // Prevent infinite loop.
});
Bundles
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
//Ignoring these so only the min.js versions get rendered
bundles.IgnoreList.Ignore("jquery.validate.js");
bundles.IgnoreList.Ignore("jquery.validate.unobtrusive.js");
bundles.IgnoreList.Ignore("jquery.unobtrusive-ajax.js");
Controller Action
[Authorize]
public ActionResult AddClass()
{
var userName = User.Identity.Name;
var userProfile = db.UserProfiles.SingleOrDefault(x => x.UserName == userName);
InitializeSemesters();
InitializeYears();
return PartialView(new Class() { UserId = userProfile.UserId, Year = DateTime.Now.Year });
}