mvc clientside validation for nested (collection)

2019-01-18 15:06发布

问题:

I'm using asp.net mvc 3 with jquery unobtrusive validation. I recently changed from standard DataAnnotations to FluentValidation and it works great.

My primary reason for picking up FluentValidation was the need to validate nested properties on my viewmodel (but i found there are other cool reasons for using it) that kinda looks like this (don't mind accessors this is pseudo):

class Vm {
  string Prop;
  string AnotherProp;
  IEnumerable<ElementsVm> Elements;
}

class ElementsVm {
  bool Required;
  string Id;
  string Title;
  string Value;
}

Using FluentValidation I make a validator for Vm and for ElementVm and my unit tests are green, showing me server side validation is working.

Client side, 'Prop' and 'AnotherProp' is working - my validation rules are also running client-side as expected (as they would with DataAnnontation), but all my Elements are not getting any client-side validation at all - i inspect the dom and can see all the data-val, data-required etc. attributes are missing.

I've tried different approaches to generating the html in my views, but the 'Prop' and 'AnotherProp' are generated using Html.TextBoxFor(m => m.Prop) while my elements are generated in a partial - this is where the problems start. If i choose Html.TextBoxFor(m => m.Value) all my Element Textboxes will have the same name/id, so i also tried using Html.TextBox(Model.Id) to generate unique id/name but still no validation properties.

So is there a way to make my senario work - i don't mind rewriting it a bit, but i would really like FluentValidation to write my html for me.

My fallback solution would be to make my own Html helpers to generate the correct Html with attributes, but that would suck i think, since i would have to keep updating those helpers when new releases/patches were made to either FluentValidation, jquery validation or the link in mvc between the two.

回答1:

In your partial, before each instance of ElementsVM, you must set a unique prefix using ViewData.TemplateInfo.HtmlFieldPrefix, like so:

var i = 0; 
foreach (var element in Model) 
{ 
    ViewData.TemplateInfo.HtmlFieldPrefix = "Elements[" + i.ToString() + "]"; 
    @Html.TextBoxFor(m => m.Value) 
    i++; 
}

This should give you your unobtrusive validation attributes, and should also work with the default model binder.

counsellorben