1

I have an ajax form on a partial view which uses a custom unobtrusive validator for an either/or style validator (described here). My custom validator works fine when used on a form which is not loaded via an ajax call. This partial however, is loaded via an @Ajax.ActionLink call which loads the partial into the containing view.

Containing view:

<div id="form-container">
    @Html.Action("Login", "MyController") //Initial state. Loads Login.cshtml partial view
</div>

Login.cshtml partial:

//contains markup for login form fields, but also this link to the signup partial (Signup.cshtml) 
@Ajax.ActionLink("click here", "Signup", "MyController", 
    new AjaxOptions
    {
        OnSuccess = "initializeValidation();", 
        InsertionMode = InsertionMode.Replace, 
        UpdateTargetId = "form-container"
    })

Signup.cshtml partial:

@model SignupViewModel
<div>
    @using (Ajax.BeginForm("Signup", "MyController", new AjaxOptions
                            {
                                OnSuccess = "initializeValidation();",
                                InsertionMode = InsertionMode.Replace, 
                                UpdateTargetId = "form-container"
                            }))
    {
    <p>
        @Html.LabelFor(m=>m.Username)
        @Html.EditorFor(m=>m.Username)
        @Html.ValidationMessageFor(m=>m.Username)
    </p>
    <p>               
        @Html.LabelFor(m=>m.Email)
        @Html.EditorFor(m=>m.Email)
        @Html.ValidationMessageFor(m=>m.Email)
    </p>        
    <input type="submit" value="Next"/>
    }
</div>

My javascript method initializeValidation() has the following code to reset the unobtrusive validation:

$('form').removeData("validator");
$('form').removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse('form');

The problem I have is that the custom validator does not work on a form which is loaded via @Ajax.ActionLink. I looked at this question and this question which correctly reset the standard unobtrusive validation methods, but I can't figure out how to reset the custom one. The custom validation method and its unobtrusive adapter is configured with the code below

$.validator.addMethod("eitherorrequired", function (value, element, params) {
    var otherValue = $(params).val();
    return value != "" || otherValue != "";
});
$.validator.unobtrusive.adapters.add("eitherorrequired", ["dependentproperty"], function (options) {
    options.rules["eitherorrequired"] = "#" + options.params.dependentproperty;
    options.messages["eitherorrequired"] = options.message;
});

I've tried including this within the initializeValidation() method, but it still does not work.

Community
  • 1
  • 1
Matthew Dresser
  • 11,273
  • 11
  • 76
  • 120
  • Is the `initializeValidation` function ever called? – Darin Dimitrov Dec 31 '13 at 16:03
  • Yes, I've put console.log statements inside this and it's definitely called when the new partial is loaded. – Matthew Dresser Dec 31 '13 at 16:07
  • I think the issue is that validation which is associated to any input control doesn't have data-val attribute for custom validator.One solution is use fluent and try injecting client side validaton from model validator or manually create this data-val attribute for that input. – Roshan Srivastava Dec 31 '13 at 16:14
  • Are your input fields inside an `Html.BeginForm` or `Ajax.BeginForm`? Inside the same partial? Or is the form declaration outside of the partial and you are refreshing only the input fields and not the entire form? – Darin Dimitrov Dec 31 '13 at 16:15
  • @DarinDimitrov the input fields are within an Ajax.BeginForm statement which is in the partial. The AjaxOptions parameter for the BeginForm method reference an UpdateTargetId which is in the containing view, rather than the partial itself. – Matthew Dresser Dec 31 '13 at 16:33
  • I think that's the problem. Your Ajax form should reference an element that is outside the partial. For example you could use the same container as your Ajax link: `#form-container`. – Darin Dimitrov Dec 31 '13 at 16:35
  • It does reference an element outside the partial - sorry if my previous comment was not clear. I will update the question to clarify. – Matthew Dresser Dec 31 '13 at 16:43

1 Answers1

0

It turned out that the custom validator method I had did not account for the fact that my input elements had names with underscores in them (due to the fact that my view model class had a property exposing another object containing the properties representing the form fields).

My view model is something like this:

public class MyViewModel
{
    public Info Step1 { get; set; }

    public class Info
    {
         public string Property1 { get; set; }

         [EitherOrRequired(DependentProperty="Property1")]
         public string Property2 { get; set; }
    }
}

Which produces input elements with ids of Step1_Property1 and Step1_Property2. The problem is that the Step1_Property2 input has its data-val-dependentproperty set to "Property1" (the value of the attribute in the view model), so the custom validator method looks for a dependent property which doesn't exist. To overcome this, I modified the custom validator function to ensure that the dependent property has the same prefix as the current property.

$.validator.addMethod("eitherorrequired", function(value, element, params) {
    var name = $(element).attr('name').replace('#', '');
    var i = name.lastIndexOf('.');
    if (i > -1) {
        params = '#' + name.substr(0, i).replace('.', '_') + '_' + params.replace('#', '');
    }
    var otherValue = $(params).val();
    return value != "" || otherValue != "";
});
Matthew Dresser
  • 11,273
  • 11
  • 76
  • 120