mvc clientside validation for nested (collection) properties
Asked Answered
B

1

7

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.

Barrage answered 1/4, 2011 at 9:16 Comment(0)
R
8

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

Reena answered 13/4, 2011 at 4:2 Comment(4)
Also, don't forget to reset ViewData.TemplateInfo.HtmlFieldPrefix = "" if you have inputs after the loop.Kenweigh
@JustinP8, @counsellorben, @Per : I am having the same problem, but this did not fix it. I am using EditorTemplates for my nested collection and all the 'input' tag's 'id' attributes are already prefixed with the appropriate/equivalent "Elements[0]". The 'ViewData.TemplateInfo.HtmlFieldPrefix' is handy to know, but not the issue for me. @Per mentioned that the 'the data-val, data-required etc. attributes are missing'. I have noticed the same thing.Bulter
@tkerwood, there is an issue with unobtrusive validation of nested dropdownlists, see aspnet.codeplex.com/workitem/7629 and my workaround at forums.asp.net/t/1649193.aspx/1/…. Based on your description, I expect that the EditorFor templates have the same bug.Reena
Thanks for the feedback. I have added (hardcoded) in two missing attributes on the input tag and it now works. <input data-val="true" data-val-required="* required." I will look at writing a helper to do this.Bulter

© 2022 - 2024 — McMap. All rights reserved.