using System;

jQuery.validation breaks jQuery 1.5 ajax API

Today I found out (the hard way) that the use of the jQuery.validation plugin breaks the jQuery.ajax API. Since the Asp.net MVC 3 uses jQuery.validation for its unobtrusive validation it is included in the default project template. You can imagine my surprise when I updated jQuery to v1.5, and my heavy ajaxified MVC page stopped working correctly. Every ajax request contained an parseerror with an error message stating that the callback jQuery[some random string] was not called. I tried to fiddle with the ajax settings for JSONP (namely jsonp and jsonpCallback), but no matter how I set them, the error was still present.


So I started digging around, trying to replicate the problem. When I ran simple html pages $.ajax worked as expected. Then I started to gradually test all the jQuery plugins and found out that the plugin causing the error was jQuery.validation. So here is my reproduction and a simple workaround (the whole project is available here):

The controller:

using System.Linq;
using System.Web.Mvc;

public partial class DefaultController : Controller
  private static readonly int[] numbers = Enumerable.Range(1, 10).ToArray();

  public virtual ActionResult Index()
    return View();

  public virtual JsonResult SimpleArray(int id)
    return Json(numbers.Concat(new [] { id }));

The view:

@{ Layout = null; }  
<!DOCTYPE html>  
  <script src="/Scripts/jquery-1.5.js" type="text/javascript"></script>  
  <script src="/Scripts/jquery.validate.js" type="text/javascript"></script>  
  <script type="text/javascript">  
    $(function () {  
      $('a').click(function (e) {  
        var req = $.ajax({  
            url: '@Url.Action(MVC.Default.SimpleArray())',  
            type: 'POST',   
            data: $('form').serializeArray(),  
            dataType: 'json'   
        req.success(function (response, status, xhr) { alert('Success: ' + response); });  
        req.error(function (xhr, error, msg) { alert('Error "' + error + '": ' + msg); });  
  <a href="javascript:void(0);">Do request</a>  
  <form action="#">  
    <input type="hidden" value="-1" name="id" />  

The workaround:

$(function () {
  $.ajaxSettings.cache = false;
  $.ajaxSettings.jsonp = undefined;
  $.ajaxSettings.jsonpCallback = undefined;

The cause of the problem is this line of JavaScript in jQuery.validate.js, that overrides the settings you pass into the $.ajax call with all the default ones (and jQuery.ajaxSettings defaults to { jsonp: “callback”, jsonpCallback: function() {…}}):

    // create settings for compatibility with ajaxSetup
settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));