2

Microsoft unobtrusive validation fails to work for our MVC 4.0 site when we upgrade the jQuery version from 1.7.1 to jQuery 1.9.

Attempted Fixes

These are fixes that I've tried, and some related posts that I read. But suggestions that I read here did not resolve the issue.

Background

We are in the process of upgrading an MVC 4.0 site to the latest version of jQuery. Part of our aim is to upgrade the other jQuery libraries on the site, like Bootstrap, to their respective latest versions. These upgrades will require later versions of jQuery, newer than the present version we currently employ (1.7.1). We would like to get this to jQuery 1.11, and for now I'm implementing the intermediate step of trying jQuery 1.9 and utilizing the JQMigrate script. I have read the suggested fix noted on GitHub for jQMigrate, but it's unclear to me how to implement this on the unobtrusive validation code. https://github.com/jquery/jquery-migrate/blob/master/warnings.md#jqmigrate-jqueryparsejson-requires-a-valid-json-string

Sample Code

Sample code showing changes for the onError and onSuccess functions in the 4.0 version of jquery.validate.unobtrusive.js are below. The original Microsoft implementation is noted in each case. Above that, the comments show some attempts we made to fix the original implementation, along with a corresponding link showing where the recommendation was obtained.

function onError(error, inputElement) {  // 'this' is the form element

    /*
    // Codeplex fix from http://bit.ly/1xasYAq
    var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
        replace = $.parseJSON(container.attr("data-valmsg-replace") || null) !== false;

    // StackOverflow fix from http://bit.ly/1tKjGqS
    var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
        replace = container.attr("data-valmsg-replace") && $.parseJSON(container.attr("data-valmsg-replace")) !== false;
    */
    // Original Microsoft implementation
    var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
         replaceAttrValue = container.attr("data-valmsg-replace"),
         replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
        container.empty();
        error.removeClass("input-validation-error").appendTo(container);
    }
    else {
        error.hide();
    }
}

function onSuccess(error) {  // 'this' is the form element
    /*
    // Codeplex fix from http://bit.ly/1xasYAq
    var container = error.data("unobtrusiveContainer"),
        replace = $.parseJSON(container.attr("data-valmsg-replace") || null);

    // StackOverflow fix from http://bit.ly/1tKjGqS
    var container = error.data("unobtrusiveContainer"),
        replace = container.attr("data-valmsg-replace") && $.parseJSON(container.attr("data-valmsg-replace"));
    */
    // Original Microsoft implementation.
    var container = error.data("unobtrusiveContainer"),
         replaceAttrValue = container.attr("data-valmsg-replace"),
         replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;

    if (container) {
        container.addClass("field-validation-valid").removeClass("field-validation-error");
        error.removeData("unobtrusiveContainer");

        if (replace) {
            container.empty();
        }
    }
}

These are the controls from the view.

@Html.TextBoxFor(m => m.DealerAccountNumber)
@Html.ValidationMessageFor(m => m.DealerAccountNumber)

These are the data annotations in our model.

[Required(ErrorMessage = "Dealer is required")]
[RegularExpression(@"[a-zA-Z0-9]*", ErrorMessage = "Not a valid dealer number")]
[Display(Name = "Account")]
[Remote("ValidateDealerAccountNumber", "Registration", ErrorMessage = "Dealer was not found")]
public string DealerAccountNumber { get; set; }

This is the remote validator in our controller.

public virtual ActionResult ValidateDealerAccountNumber(Dealer dealer)
{
    var success = (dealer != null);
    return Json(success, JsonRequestBehavior.AllowGet);
}

Upon entering an invalid dealer number, the JQMigrate script shows the following warning:

JQMIGRATE: jQuery.parseJSON requires a valid JSON string  jquery-migrate-1.2.1.js:41
console.trace() jquery-migrate-1.2.1.js:43
migrateWarn jquery-migrate-1.2.1.js:43
jQuery.parseJSON jquery-migrate-1.2.1.js:232
q jquery.js:8197
r jquery.js:8000
r jquery.js:8558

My understanding is that Microsoft corrected this problem in MVC 5.0, but we presently lack the luxury of upgrading our entire site from MVC 4.0 to MVC 5.0 and performing a full regression test. The unobtrusive validation of course works as long as we reference JQMigrate, but we don't want that dependency.

Presently I'm using a local copy of the jquery.validate.unobtrusive.js file, version 4.0, in this project, as originally copied from http://ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.js.

In that file I've replaced andSelf() with addBack(), to align with the latest version of jQuery. And I've attempted the changes commented out in the onError and onSuccess functions noted in the first code block above. But none of that worked.

Thanks for your help.

Community
  • 1
  • 1
Ken Palmer
  • 2,355
  • 5
  • 37
  • 57

2 Answers2

1

I tried out your scenario, but I can't quite seem to repro the issue. What's strange is that the file on the CDN that you pointed to already has the fix for parseJSON1 2. It doesn't have the fix for andSelf() but you should be able to fix that by updating the Unobtrusive.Validation package.

If you continue seeing the error once update, could you expand on the stack trace you get from JQMigrate? It doesn't mention unobtrusive validation in the trace. For instance, here's one where I forced an error in the script:

JQMIGRATE: jQuery.parseJSON requires a valid JSON string jquery-migrate-1.2.1.js:41 console.trace() jquery-migrate-1.2.1.js:43 migrateWarn jquery-migrate-1.2.1.js:43 jQuery.parseJSON jquery-migrate-1.2.1.js:232 onError jquery.validate.unobtrusive.js:58 ...

Pranav
  • 543
  • 4
  • 9
  • Thanks for replying @Pranav, and for those links to the ParseJSON fixes. Yes, those changes are reflected in that file, and in my example above appear under the comments "Original Microsoft implementation." I'm hosting the file locally, and applied the andSelf() fix to that. The full stack trace from JQMIGRATE appears in my post. You're right, the stack trace doesn't flag the unobtrusive script. But the warning only occurs upon triggering the remote validator. Removing the reference to jQMigrate makes the remote validator fail, where before it worked with jQuery 1.7.1. – Ken Palmer Sep 05 '14 at 12:04
  • I just tried to update the Unobtrusive Validation package via NuGet, and got the messages below. I'm searching for references to jQuery 1.4.1 right now. Attempting to resolve dependency 'jQuery (= 1.8)'. Attempting to resolve dependency 'jQuery.Validation (= 1.8)'. Attempting to resolve dependency 'jQuery (= 1.3.2 && = 1.6)'. Updating 'jQuery 1.8.0' to 'jQuery 1.4.1' failed. Unable to find a version of 'Microsoft.jQuery.Unobtrusive.Validation' that is compatible with 'jQuery 1.4.1'. – Ken Palmer Sep 05 '14 at 12:15
  • Narrowing it down to one project in the solution, NuGet still shows this message: Attempting to resolve dependency 'jQuery (≥ 1.8)'. Attempting to resolve dependency 'jQuery.Validation (≥ 1.8)'. Attempting to resolve dependency 'jQuery (≥ 1.3.2 && ≤ 1.6)'. Updating 'jQuery 1.8.0' to 'jQuery 1.4.1' failed. Unable to find a version of 'Microsoft.jQuery.Unobtrusive.Validation' that is compatible with 'jQuery 1.4.1'. – Ken Palmer Sep 05 '14 at 12:19
  • Regarding that NuGet error, this looks promising. I'll give this a shot. http://stackoverflow.com/questions/22045588/adding-the-microsoft-jquery-unobtrusive-validation-package-asks-for-jquery-1-4 – Ken Palmer Sep 05 '14 at 12:47
  • Okay, I just checked out my solution and did the following using NuGet: 1) Added jQuery 2.1.1. 2) Added jQuery Validation. 3) Added Microsoft jQuery Unobtrusive Validation. Then I referenced jQuery 2.1.1 on the interface where that DealerAccountNumber control appears. JQMigrate showed the warning. Upon removing the JQMigrate reference, the remote validation failed. – Ken Palmer Sep 05 '14 at 13:25
  • Could you (a) switch to the non-minified version of jquery.js so we get better stack traces (b) confirm that the remote validator you have there always returns `true` \ `false`? The only case where I see something similar to your trace is when I return a null value from `ValidateDealerAccountNumber`. – Pranav Sep 05 '14 at 16:30
  • Good idea @Pranav. I'll give that a shot and post the results. – Ken Palmer Sep 08 '14 at 14:05
  • This is the non-minified version.JQMIGRATE: jQuery.parseJSON requires a valid JSON string jquery-migrate-1.2.1.js:41 - console.trace() jquery-migrate-1.2.1.js:43 - migrateWarn jquery-migrate-1.2.1.js:43 - jQuery.parseJSON jquery-migrate-1.2.1.js:232 - ajaxConvert jquery.js:7786 - done jquery.js:8201 - (anonymous function) jquery.js:8598 – Ken Palmer Sep 09 '14 at 13:00
  • This does seem like the result you're sending from your action method is what's producing the warning. Could you list what the actual you're returning from `ValidateDealerAccountNumber` is? – Pranav Sep 09 '14 at 16:56
  • Hey @Pranav, just wanted to let you know that I changed jobs recently, and am no longer working on this particular problem. Thanks for all your previous help. – Ken Palmer Nov 21 '14 at 14:14
0

Install-Package Microsoft.jQuery.Unobtrusive.Validation this fixed all my validation errors for js version 3.1.1 in MVC bootstrap

  • Thanks @GiGi. I changed jobs a couple of months after posting this, and am consequently unable to confirm fixes. – Ken Palmer May 24 '17 at 15:24