MVC client side validation for a model that has a list of models

I have this model that has a list of another model. Then, in my opinion, I have my form, which fills a couple of fields for my main model. But I want this form to also be able to add X-models of a different type and be connected to the network, and I'm wondering how to do it right.

So here are my two models:

public class MyMainModel { public int MyMainId { get; set; } [Required(ErrorMessage = "Groovy name required")] [Display(Name = "MyMainModel groovy name:")] public string Name { get; set; } public List<MySubModel> MySubModels { get; set; } } public class MySubModel { public int MySubId { get; set; } [Required(ErrorMessage = "Cool name required")] [Display(Name = "MySubModel cool name:")] public string Name { get; set; } } 

When I hit my controller for my β€œcreation”, I go through this action:

 public ActionResult SomePageAboutCreating() { // [...] Some other stuff return View(new MyMainModel()); } 

Now it goes to my strongly typed view:

 @model myFunProject.WebModels.MyMainModel <div> <form id="my-create-form" onsubmit="CreateMyMainModel(this); return false;"> @Html.AntiForgeryToken() @Html.ValidationSummary() <div class="result" style="background-color: silver;">This is the operation result box</div> <img class="loading" src="/Images/ajax-loader.gif" alt="Loading..." width="16" height="16" style="display: none;" /> <section> @Html.LabelFor(m => m.Name) @Html.TextBoxFor(m => m.Name) @Html.ValidationMessageFor(m => m.Name) </section> <!-- Here begins the fields for my list of "MySubModel" --> @Html.EditorFor(x => x.MySubModels) <!-- Here I'm thinking about a javascript that will add the previous fields X times so that the user can create "MyMainModel" as well as x times "MySubModel"... --> <input type="submit" class="btn-send" id="my-create-form-submit" value="Send" /> </form> </div> 

So, I think I need to use EditorTemplates here ... Therefore, I configure in my /Views/EditorTemplates/MySubModels.cshtml (with the name of my property MyMainModel), and then when I write my form there, I get confused ...

 @model myFunProject.WebModels.MyMainModel @*<section> @Html.LabelFor(m => m.Name) @Html.TextBoxFor(m => m.Name) @Html.ValidationMessageFor(m => m.Name) </section>*@ 

So, here I am not sure what to add here ... I want my Name property to be one of the "MySubModel". And since the user sees this form, let's say, for example, he will consider this scenario:

  • Enters a name for "MyMainModel".
  • Change to another name and fill in the name of the first instance of "MySubModel".
  • Then he presses a special button that will manipulate dom to add another MySubModel.Name field.
  • He will write in the second "MySubModel".
  • He will click the Submit button.

The Ajax call that I put in there, I do the wiring normally, but my confusion comes with the code I have to write for the editor template, and then I also wonder how I am going to create a new field (for this second "MySubModel", for example ...).

Any help would be appreciated; I looked through a lot of articles about subjects close to this, but have not yet found this case. Thanks!

EDIT:

I will add an action (a too simplified version of hehe) that is called by my ajax when the form is submitted.

 public ActionResult CreateMyMainModel(MyMainModel myMainModel) { // [...] Do stuff like save to database... // var aGroovyNAme = myMainModel.Name; foreach(var mySubModel in myMainModel.MySubModels) { // Here I would have the sub models available to manipulate... // var aCoolName = mySubModel.Name; } return Content("ok"); } 
0
source share
3 answers

I have looked through many articles about subjects close to this, but have not yet found this case.

I would recommend you read the article editing a variable length list from Stephen Sanderson, which illustrates a very good approach for handling this scenario. It presents a special Html.BeginCollectionItem helper that can be used to generate disjoint indexes (pointers) for input field names and, thus, allows you to easily remove items dynamically without leaving holes in the indexes. When the user decides to add another element, an AJAX call is made for the controller action, which simply returns an empty template (partial).

You can also do this exclusively on the client side using javascript only. Stephen Sanderson illustrated this approach using knockoutjs in this similar article .

These two articles are truly the best approach for dynamically editing a list of variables in an ASP.NET MVC variable. Reading them really will be useful for a better understanding of some basic concepts in model binding in ASP.NET MVC.

+1
source

I had a similar problem in a project where I wanted to check some fields several times and not on others (i.e. when they are saved, they are not checked, but everything is checked on submit).

I ended up doing everything manually in javascript and sent back the json object.

On reflection, I would rather manipulate the validation javascript file (MicrosoftMVCValidation.js).

For problems with model binding, I recommended looking at the user model binding.

I used EditorTemplates quite often, especially with partial views.

I find asp.net mvc 3 a bit weak in model binding. I was hoping that some problems would be fixed in mvc 4, but from what I was just looking at, MVC4 is, first of all, an update for creating applications for Windows phones.

Here is an example of a custom binder for decimal properties in a model.

You can use the same logic with your own models.

I found that there are cases when I want to bind a model to a set of entities on large pages, and not just bind a basic set of properties, for example.

 public class DecimalModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); //return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) : Convert.ToDecimal(valueProviderResult.AttemptedValue); if (valueProviderResult == null) return base.BindModel(controllerContext, bindingContext); else if (valueProviderResult.AttemptedValue == "") return base.BindModel(controllerContext, bindingContext); else return Convert.ToDecimal(valueProviderResult.AttemptedValue); } } 
0
source

I recently answered this question in another question:

ASP.Net MVC4 associates "create view" with a model containing a list

0
source

Source: https://habr.com/ru/post/1440785/


All Articles