3

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 });
}
Community
  • 1
  • 1
Eric Garrison
  • 291
  • 1
  • 10
  • 21
  • Clearly the code you posted is not the same as the code you're using. There is no UserId in the class you posted, but yet you are referencing it in your razor code. If you want help, you have to post the EXACT same code that has problems. If it's too big, you need to simplify the code and produce the simplest WORKING set of code that illustrates the problem. – Erik Funkenbusch Jul 20 '13 at 16:48
  • I've updated the code and removed the UserId reference. It's in the model, but it's not being validated. The only fields being validated are the ones that are listed. If I pass this back to the controller, it gets validated on the server correctly, just not client-side. – Eric Garrison Jul 20 '13 at 17:10
  • The problem here is that YOUR code has a lot of other stuff in it, and when YOU test, your also testing that other stuff. That others stuff may be part of the problem. You need to give us a barest complete working example that illustrates the problem. By that, I mean you have verified that the problem exists in the code you have given us. – Erik Funkenbusch Jul 20 '13 at 18:20
  • There are no other fields in the model are being validated. I've verified that what I posted reproduces the same error. There shouldn't be anything else in the model that will break this since it's just an entity model. If I use the jQuery validation plugin, it works fine, but I didn't think that was needed. I updated the code to show the full model that's being bound to the view. – Eric Garrison Jul 20 '13 at 18:33
  • I also added the controller method. I'm not sure if returning it as a partial view is part of the problem or not. – Eric Garrison Jul 20 '13 at 18:56

4 Answers4

1

You have to add the following scripts to your _Layout or to the view "jquery.unobtrusive-ajax.js" "jquery.validate.js" "jquery.validate.unobtrusive.js"

0

If

alert("Is the form valid? " + val.valid());  //Always returns true

What about

alert("Is the form valid? " + $("#AddNewClassForm").valid());  // ???

This worked for me...

Amin Saqi
  • 18,549
  • 7
  • 50
  • 70
0

You need to call .valid() on the form that you want to verify, not on the result of the .validate() method.

Unlike many jQuery methods, .validate() isn't suitable for chaining, as it returns an object of type Validator instead of the original jQuery object (see: http://jqueryvalidation.org/validate/)

UweB
  • 4,080
  • 2
  • 16
  • 28
0

This extension works form me:

$(document).ready(function () {
    jQuery.noConflict();

    // if the form is in a dialog box {
    var form = $('#formCreateRequest');
    form
        .removeData('validator')
        .removeData('nobtrusiveValidation');
    $.validator.unobtrusive.parse(form); // }

    $.fn.extend({
        // form validation {
        isValid: function () {
            var self = $(this);
            $.validator.unobtrusive.parse(self);
            return self.data('unobtrusiveValidation').validate();
        } // }
    });
});

using:

if ($('#formId').isValid()) {
    ...
} else {
    ...
}
oyaebunterkrah
  • 101
  • 2
  • 6