1

Based upon this link here I made custom validation, its same as the one in link. But for me the client side validation doesn't work.

Here is my validator

public class AtLeastOneRequiredAttribute:ValidationAttribute,IClientValidatable
{
    private readonly string[] _properties;
    public AtLeastOneRequiredAttribute(params string[] properties)
    {
        _properties = properties;
    }

    protected override ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
    {
        if (_properties == null || _properties.Length < 1)
        {
            return null;
        }
        foreach (var property in _properties)
        {
            var propertyInfo = validationContext.ObjectType.GetProperty(property);
            if (propertyInfo==null)
            {
                return  new ValidationResult(string.Format("Unknown property {0}", property));
            }
            var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))
            {
                return null;
            }
            if (propertyValue !=null)
            {
                return null;
            }
        }
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule()
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "atleastonerequired"
        };
        rule.ValidationParameters["properties"] = string.Join(",", _properties);
        yield return rule;
    }
}

Here is the model public class Person {

    [AtLeastOneRequired("FirstName","LastName",ErrorMessage = "*At Least First Name or Last Name is required.")]
    public string FirstName { get; set; }

    public string LastName { get; set; }

}

Here is the conroller

[HttpGet]
public ActionResult AddPerson(int contactId)
{
    _personRepository.AddPerson(contactId);
    ..
    return PartialView(person);
}

[HttpPost]
public ActionResult AddPerson(Person person)
{

    return Content("Success!");
}

and finally the view

@model WebApplication1.Models.Person


<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script type="text/javascript">
    jQuery.validator.unobtrusive.adapters.add('atleastonerequired', ['properties'], function(options) {
        options.rules['atleastonerequired'] = options.params;
        options.messages['atleastonerequired'] = options.message;
    });
    jQuery.validator.addMethod('atleastonerequired', function(value, element, params) {
        var properties = params.defineProperties.split(',');
        var values = $.map(properties, function(property, index) {
            var val = $('#' + property).val;
            return val != '' ? val : null;
        });
        return values.length > 0;
    },'');
</script>


@using(Html.BeginForm("AddPerson","Person",FormMethod.Post))
{
    @Html.ValidationSummary(false)
    @Html.HiddenFor(m=>m.ContactId)
    <div class="label">First Name</div>
    <div class="input-block-level">@Html.TextBoxFor(m=>m.FirstName)@Html.ValidationMessageFor(m=>m.FirstName)</div>
    <br/>
    <div class="label">Last Name</div>
    <div class="input-block-level">@Html.TextBoxFor(m=>m.LastName)@Html.ValidationMessageFor(m=>m.LastName)</div>
    <button type="submit" class="btn-primary">Submit</button>
}

I also have clientvalidation set to true in web.config. Any reason why it is not working? When user clicks submit button without filling in any information i was expecting error to be shown on client side, but that doesn't happen and I get forwarded to HttpPost method of the controller.

What I have noticed is in view of the provided link inside jQuery.validator.addMethod('atleastonerequired', function(value, element, params) function properties is set as var properties = params.propertynames.split(','); but for me my intellisense in VS2013 doesn't provide params.propertynames it has these two options params.defineProperties and params.originalProperties.

Is that the reason why it is not working? What should I do to make my validation work?

Edit1: Rendered HTML

<script src="/Scripts/jquery-1.8.2.min.js"></script>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>

<form action="/" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#partialDiv" id="form0" method="post" novalidate="novalidate">    <div class="input-block-level"><input data-val="true" data-val-required="*Search text cannot be empty" id="SearchString" name="SearchString" type="text" value="" class="valid"> <span class="field-validation-valid" data-valmsg-for="SearchString" data-valmsg-replace="true"></span> </div>
    <button type="submit" class="btn-info">Submit</button>                              
</form><div id="partialDiv">





<form action="/Person/AddPerson" method="post" novalidate="novalidate"><div class="validation-summary-valid" data-valmsg-summary="true"><ul><li style="display:none"></li>
</ul></div><input data-val="true" data-val-number="The field ContactId must be a number." data-val-required="The ContactId field is required." id="ContactId" name="ContactId" type="hidden" value="1055">    <div class="label">First Name</div>
    <div class="input-block-level"><input data-val="true" data-val-atleastonerequired="*At Least First Name or Last Name is required." data-val-atleastonerequired-properties="FirstName,LastName" id="FirstName" name="FirstName" type="text" value=""><span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span></div>
    <br>
    <div class="label">Last Name</div>
    <div class="input-block-level"><input id="LastName" name="LastName" type="text" value=""><span class="field-validation-valid" data-valmsg-for="LastName" data-valmsg-replace="true"></span></div>
    <button type="submit" class="btn-primary">Submit</button>
</form>


</div>
        <hr>
        <footer>
            <p>© 2014</p>
        </footer>
    </div>

Edit2: I changed html.textboxfor to html.editorfor in view and removed the html.validationmessagefor but still not working.

Community
  • 1
  • 1
Cybercop
  • 8,475
  • 21
  • 75
  • 135

3 Answers3

0

As far as I can tell, you're not accessing your params object correctly.

Try modifying your code so it looks like this:

var properties = params[0].properties.split(',');

Furthermore, you're accessing your input fields value the wrong way. val is not a jQuery property. Use val() instead:

var val = $('#' + property).val();
Kippie
  • 3,760
  • 3
  • 23
  • 38
  • i changed it but still same thing is happening, i'm getting forwarded to post method of my controller. – Cybercop Jan 15 '14 at 12:17
  • @Biplov13 Well, you're going to have to be a bit more descriptive of what exactly happens. Are *any* errors logged to the console? Does the validator actually get run? If so, where do you go while stepping through it, and what is the value of "params" ? – Kippie Jan 15 '14 at 12:33
  • It may sound stupid but how do i check if the validator actually get run or not? right now i don't get any error, when the form is submitted, i get the values in post method. – Cybercop Jan 15 '14 at 12:36
0

I guess you're having a JavasSript error while submitting the form, because you've changed the validation parameters key to defineProperties.

Change your jQuery.validator.addMethod to:

jQuery.validator.addMethod('atleastonerequired', function (value, element, params) {
    var properties = params.properties.split(',');
    var values = $.map(properties, function (property) {
        var val = $('#' + property).val();
        return val != '' ? val : null;
    });
    return values.length > 0;
}, '');
Zabavsky
  • 13,340
  • 8
  • 54
  • 79
  • i changed to params.properties.split(',') and still doesn't work. I'll post the rendered HTML code in the browser for the form – Cybercop Jan 15 '14 at 12:03
  • there is not javascript error, i get forwarded to httppost method without any trouble and when i check the console in chrome, it doesn't show any error. But i don't know if the validator is actually running or not, how do i check that? – Cybercop Jan 15 '14 at 12:39
0
jQuery.validator.unobtrusive.adapters.add('atleastonerequired', ['properties'], function(options) {
    options.rules['atleastonerequired'] = {
      properties : options.params.properties;
    }
    options.messages['atleastonerequired'] = options.message;
});
jQuery.validator.addMethod('atleastonerequired', function(value, element, params) {
    var properties = params.properties.split(',');
    var values = $.map(properties, function(property, index) {
        var val = $('#' + property).val();
        return val != '' ? val : null;
    });
    return values.length > 0;
},'');
Lewis
  • 1