2

I have an ASP.NET MVC 4 application and I'd like to have unobtrusive validation for several properties of the view model. Here's a simplified version :

ViewModel :

[AtLeastOne(new[] {"FirstName", "LastName"})]
public class PersonViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Validation attribute :

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AtLeastOneAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _propertyNames;

    public AtLeastOneAttribute(string[] propertyNames)
    {
        if (propertyNames == null) throw new ArgumentNullException("propertyNames");
        if (propertyNames.Length < 2) throw new ArgumentOutOfRangeException("propertyNames");
        _propertyNames = propertyNames;
    }

    public override bool IsValid(object value)
    {
        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var modelClientValidationRule = new ModelClientValidationRule
        {
            ErrorMessage = "AAAAA!!!",
            ValidationType = "atleastone",
        };
        modelClientValidationRule.ValidationParameters.Add(new KeyValuePair<string, object>("propertynames", _propertyNames));
        return new[]
        {
            modelClientValidationRule
        };
    }
}

Although I have :

<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

in Web.config and

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script type="text/javascript">
        jQuery.validator.unobtrusive.adapters.add("atleastone", ['FirstName', 'LastName'], function (options) {
            alert('options!');
        });
    </script>

set in my view nothing is rendered for this validation. If I, for example, add [Required] for FirstName or LastName, data-* validation attributes are added.

How can I achieve this multi-property custom client-side validation?

WANT TO SEE / DOWNLOAD THE WHOLE SOLUTION?

Andrei Rînea
  • 20,288
  • 17
  • 117
  • 166
  • Does your `AtLeastOneAttribute` has the `[AttributeUsage]` attribute? – haim770 May 28 '13 at 09:49
  • I don't think so. did you register your custom validation method on the client side? something like: `jQuery.validator.unobtrusive.add("atleastone")`? – haim770 May 28 '13 at 09:52
  • I added [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] but nothing is being emitted. I get the feeling that this scenario is not covered.. – Andrei Rînea May 28 '13 at 09:53
  • I also added javascript to add an adapter with a dummy function (see update above) and still I get nothing. – Andrei Rînea May 28 '13 at 10:01
  • This guy is saying that this is not possible : http://stackoverflow.com/a/5803339/1796 – Andrei Rînea May 28 '13 at 10:18
  • By carefully studying the ASP.NET MVC 4 source files I observed there is no output for the form in the case of unobtrusive validation. Therefore this won't work.. – Andrei Rînea May 28 '13 at 14:12

1 Answers1

2

Adding custom validator in the client-side is a 2 step process:

  1. First you need to register your validator (letting the unobtrusive framework knows that such validation exists - but not adding the validation function itself), as you did in jQuery.validator.unobtrusive.adapters.add. you have to remember the function (third parameter) is not the validator, it's only intended for rule configuration (and could be ommited in your case).

  2. Adding the validator itself:

    jQuery.validator.addMethod("atleastone", function (value, element, param) { alert("validating 'atleastone'"); });

haim770
  • 48,394
  • 7
  • 105
  • 133
  • Yes, that's true. I added this code too but I don't have data-* attributes emitted and upon submission no validation either (no alert is being hit).. – Andrei Rînea May 28 '13 at 10:19
  • 1
    Seems like i missed the whole point, that the validation is being done on the `viewModel` as a whole. sorry. – haim770 May 28 '13 at 10:21
  • No problem. So you're saying the scenario is not supported? – Andrei Rînea May 28 '13 at 10:26
  • I don't know, but that guy in the other post you mentioned eventually claimed it worked for him using another answer: http://stackoverflow.com/a/7122108/1625737 – haim770 May 28 '13 at 10:27
  • Yes but he worked it around by tying it to a property instead. It's a valid work-around that I was already considering but I was still hoping for something a bit more elegant. If not, that's that and I'll do it like that. – Andrei Rînea May 28 '13 at 10:32