ASP NET MVC: Dynamically adding or removing inputs on the form - unobtrusive validation

2.6k views Asked by At

Before starting, I do have a very particular question and if you want to answer it go straight to the end. But I do welcome comments and advices hence the lengthy post.

OK, we deal with a lot of forms and some of these forms are quite lengthy and have many fields. We also have a requirement - in addition to top level fields - to be able to have variable number of repating rows - as we call them. For example, let's think of a customer which has name, surname and age while it can have zero or many addresses (say 0 to 10) so the user must be able to add or remove contacts from the form while filling it in. So typically user gets and "Add" button to add more addresses and next to each address, a delete button. Potentially there could be more than one repeating section in the same form but I am not going there. The point is, because of legal and historical reasons, all the forms must be saved at once so while the forms can be edited, we cannot accept a half-filled form and have another page for users to add and remove addresses, e.g.

I am using ASP NET MVC 2 (strongly typed views with a single generic controller) with client side validation and heavy jquery scripting for flashy features. We are probably going to migrate to ASP NET MVC 3 very soon and I am already playing with 3 for finding a good solution. These addresses are defined on the Model as List<Address>, e.g.

I currently have a working solution for this issue but I am not satisfied with it: I have an HTML Helper that names the add or delete buttons and a bit of JavaScript to disable validation and allow the form to be posted back (even invalid) and since I can find out the name of the button that was clicked, I have all the necessary logic to handle add or delete and works really well.

But I am posting back and the form is reloaded and I am looking for an aletrnative solution. Here are what I can do:

  • Do everything in the client side. "Add" button will clone one of such addresses and "Delete" button will remove() the element. I only have to rename the indexes which I have done. We were using jquery calendar and it was breaking on the new elements which I have also fixed. But the validation is not working which can probably work with ASP NET MVC but this solution looks like a very brittle one - a house of card which looks great before you add another card.
  • Post the whole page usin Ajax and then load it back again: This is probably better than my current solution but only slightly.
  • Use ajax to post the form and get back JSON and use the data to build the elements or remove them: Again a house of card because of extensive client side scripting
  • Serialize the form and post using Ajax to a particular action and get back only the repating section (as a partial view). The action on the controller can be reused and called from the view itself to return the partial view

    OK last one is the one I am working on but there is an issue. ASP NET MVC 3 with unobtrusive validation works only if the form is engulfed in a BeginForm() while my top level view has a BeginForm() but not my partial view. It works well when I call it from the view but not on the ajax call to get just the repeating section.

(Question)

So is there a way to tell ASP NET MVC 3 to spit out validation data atttributes regardless being in a BeginForm() block?? To be honest if this is not a bug, this is definitely an important feature request. I have in fact used reflector to disassemble the code and the condition seems to be there.

2

There are 2 answers

0
Aliostad On BEST ANSWER

Short Answer:

Add this to the partial view:

if (ViewContext.FormContext == null)
{ 
    ViewContext.FormContext = new FormContext();
}
3
lancscoder On

I don't think it is possible using the default unobtrusive libraries supplied. If you look at jquery.validate.js and jquery.validate.unobtrusive.js it looks like it only validates what is inside the form.

There's a few posts about it if Googled and a few work arounds.

I had a similar issue (although much simpler) where I had a validation summary at the top of the page and multiple forms but the unobtrusive javascript would only populate the view summary if its inside the form (jquery.validate.unobtrusive.js line 39 if interested...).

I'm not sure if the validation library is extendible but most things in jquery are so that might be an option if you want to go down that road.

As far a possible solution to your problem I'll put in my 2 cents for whats its worth.

You could have two actions that are posted to. The first action is you post your model with no js validation and all validation is handled in the code - this will catch all user with javascript turned off.

Your second action is you serialized the model. In mvc 3 using the Ajax.BeginForm has an AjaxOption for Url where you can specify an action for the jquery to call (where it serializes the form form you and you can decorate your action with your strongly typed model). Here you can check the model and return a json result and handle this in the javascript.