0

I am using nested view models to display views based on user roles.

Model:

public class MainVM {
  //some properties
  public OneVM One {get; set;}
  public TwoVM Two {get; set;}
}

public class OneVM {
   //properties
}

public class TwoVM {
   //properties
}

As written here that only main model is need to be sent controller. I am using Automapper to map properties from received model.

Controller:

public ActionResult EditAction(MainVM model){
  var item = db.Table.Find(model.Id);
  //automapper to map
  AutoMapper.Mapper.Map(model.One, item); //does not work

  db.Entry(item).State = EntityState.Modified;
  db.SaveChanges();
}

Is this the right way to do that? What am I doing wrong here.

Update: This was the view I was using to render nested view models from partial views

View:

@model MainVM

@Html.RenderPartial("_OnePartial", Model.One)

This answer https://stackoverflow.com/a/6292180/342095 defines an Html helper which will generate the partial view with right names.

13
  • var result = Mapper.Map<OneVM>(item); Commented May 17, 2015 at 13:37
  • @FarhadJabiyev Mapper.Map<OneVM>(item); but you passed item as a source? While source should be the received model through parameter Commented May 17, 2015 at 13:44
  • Don't you want to convert item to OneVM? Commented May 17, 2015 at 13:45
  • @FarhadJabiyev No. I updated the code. I want to map properties from received model to item and will save the recieved changes in db Commented May 17, 2015 at 13:50
  • What you mean by not working? Commented May 17, 2015 at 13:52

2 Answers 2

2

The value of property One will be empty because you are passing an instance of OneVM to the partial (not the main model) so the form controls are not correctly named with the prefix (which need to be name="One.SomeProperty").

You have included a link to a PartialFor() helper (which works) but don't use it. In the main view it needs to be

@Html.PartialFor(m => m.One, "_OnePartial")

Which is the equivalent of

@Html.Partial("_OnePartial", Model.One, 
    new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "One" }})
Sign up to request clarification or add additional context in comments.

4 Comments

Helper gets called but nothing is rendered. Helper is a generic solution, why should I avoid it? The solution without helper, as you have given, does display the partial view correctly and data is submitted fine.
It should also be possible to have a generic way to receive and update only those properties which were used in the view.
Sorry, I don't understand your comments. In you question you use @Html.RenderPartial("_OnePartial", Model.One) which is invalid and does nothing - it needs to be @{ Html.RenderPartial("_OnePartial", Model.One) }. But even if you used it correctly, this does not add the prefix (by design). As I noted in the first part of my answer, you included a link to a custom helper method named PartialFor() which does work if you use it correctly, which is in your case @Html.PartialFor(m => m.One, "_OnePartial")
Also, if you are wanting to generate controls for properties which are complex objects or collections, then you should be using an EditorTemplate, not a partial. Just copy the partial into /Views/Shared/EditorTemplates/OneVM.cshtml (note the name of the file must match the name of the class) and in the main view use @Html.EditorFor(m => m.One) and the generated controls will all be correctly named with the prefix.
1

The problem probably lies in your HTML. If a model is nested, then the input fields of properties should be like this:

<input type="text" name="SubModel.PropertyName" />

Using HTML helpers, it would look something like this:

@Html.EditorFor(model => model.SubModel.PropertyName)

The ASP.NET MVC Action cannot know, that you want to fill your submodel if it's not in your HTML.

2 Comments

Helpers in stackoverflow.com/questions/1488890/… are not working.
If you really want to use partial views, then you could consider passing the parent model. The answer I gave will work in that scenario. If you don't want to pass the parent model, then you'll probably have to use @Html.Editor("SubModel.PropertyName", Model.PropertyName).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.