6
votes

I have a strongly-typed partial view whose model contains a property with the same name as the parent page's view model. For some reason the rendering engine is rendering the parent view model value, not the expected value (well, the value I expect at least!)

Parent page view model extract:

public class ParentPageViewModel
{
    public int Id { get; set; } // problem property
    ...
    public IEnumerable<ChildViewModel> Children { get; set; }
}

Child page view model extract:

public class ChildViewModel
{
    public int Id { get; set; } // problem property
    ...
}

Parent page extract (Razor):

@model ParentPageViewModel
...
@foreach (var item in Model.Children)
{
    @Html.Partial("MyPartialView", item)
}
...

Partial view extract:

@model ChildViewModel
...
<form ...>
    @Html.HiddenFor(m => m.Id) // problem here - get ParentPageViewModel.ID not ChildViewModel.Id
</form>
...

So basically in my rendered output, my hidden field has the value of the parent view model element, NOT the value passed to the partial view. It's definitely being caused by the name, as changing the name of @ChildViewModel.Id@ to something like @ChildViewModel.ChildId@ makes it work as expected. Interestingly, when inspecting the view model values in the debugger I do see the correct values; it's only the rendered output that's wrong.

Is there a way round this or 'correct' way of doing what I'm trying to do (I'm rendering mini forms in a table for ajax validation/posting of updates to table rows)

Thanks,

Tim

4
The HtmlHelpers will take the values from the ModelState dictionary first (even over the value in the Model) - looks like that is the reason for this behaviour.Simon

4 Answers

14
votes

I think changing your call to this will solve the problem:

@Html.Partial("MyPartialView", item, new ViewDataDictionary())

The child view is picking up the value from the ViewData dictionary - so this passes in a new dictionary to the child view (hattip danludwig).

2
votes

Found a solution, just manually creating the hidden field, e.g.:

<input type="hidden" name="Id" value="@Model.Id" />

instead of using Html.HiddenFor.

(I won't mark this as answered for a while in case there are any other solutions or anyone can explain the problem)

2
votes

I know this an old post. But I figured since I landed here when I was facing the same problem, I might as well contribute. My issue was a little different. In my case, the main view's Id was incorrect after a partial view action that required the whole page/view to be refreshed was triggered. I solved the problem with ModelState.Clear

ModelState.Clear();
return View("Maintenance", model);  //call main view from partial view action
0
votes

Create a file named ChildViewModel.cshtml in Views/Shared/EditorTemplates. Put your partial view into that file:

in ~/Views/Shared/EditorTemplates/ChildViewModel.cshtml

@model ChildViewModel
...
<form ...>
    @Html.HiddenFor(m => m.Id)
</form>
...

Then, render it like this:

@model ParentPageViewModel
...
@foreach (var item in Model.Children)
{
    @Html.EditorFor(m => item)
}
...

Or, if you'd rather keep the view as a partial and not as an editor template, use Simon's answer.