Why does setting the Name attribute explicitly on a Partial View input cause the Value to change after POST?

richard12511

I ran across a problem today where the Code value of a nested object in one of our forms was being changed to an incorrect value. After some digging, I discovered that it is being assigned the value of the Parent object Code, only after POSTing, and only when I try to set the Name attribute explicitly with Html.TextBoxFor's second object parameter.

I setup a simple MVC(Version 5.2.2.0) project to isolate the issue. Here is the code for that.

Models

public class Parent
{
    public string Code { get; set; }
    public Child Child { get; set; } 
}

public class Child
{
    public string Code { get; set; }
}

Controllers

public class ParentController : Controller
{
    public ActionResult Show()
    {
        var child = new Child() { Code = "999"};
        var parent = new Parent() { Code = "1", Child = child };

        return View("Show", parent);
    }

    public ActionResult Update(Parent parent)
    {
        return View("Show", parent);
    }
}

Views/Parent/Show

@model TextBoxForBugTest.Models.Parent

@using (Html.BeginForm("Update", "Parent"))
{
    @Html.TextBoxFor(o => o.Code)
    @Html.Partial("~/Views/Child/Show.cshtml", Model.Child)
    <button type="submit">Submit</button>
}

Views/Child/Show

@model TextBoxForBugTest.Models.Child

@Html.TextBoxFor(o => o.Code, new { Name = "Child.Code" })

When I first load /Parent/Show, I see the correct values in the inputs: 1(Code), and 999(Child.Code).

Before POST

However, after returning from the Update Action Method after submitting the form, Child.Code has been assigned the Value "1" - the Parent Code.

After POST

I've found that I can fix the issue by setting the HtmlFieldPrefix.

@model TextBoxForBugTest.Models.Child

@{ Html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "Child"; }

@Html.TextBoxFor(o => o.Code)

or by using a local variable

@model TextBoxForBugTest.Models.Child

@{ var theCode = Model.Code; }

@Html.TextBoxFor(o => theCode, new { Name = "Child.Code" })

but I'd like to understand why. What is going on here? Why is Child.Code being assigned the value of Parent.Code after POSTing?

I also found some related questions that get into using extensions, but they seem to be answering different questions

ASP.NET MVC partial views: input name prefixes

ASP.MVC 3 Razor Add Model Prefix in the Html.PartialView extension

***Edit - It's clear from the answers that I did a poor job of stating my actual question, so I'll attempt to clarify a bit more here.

The problem I was seeing that was leading to an end user identified bug was that

@Html.TextBoxFor(o => o.Code, new { Name = "Child.Code" })

was generating html with a different "value" the second time it was called(after POSTing).

I was able to solve that problem by setting the Html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix. Stephen Muecke also pointed out another - probably better - solution to that problem in Editor Templates.

What I was trying to ask though was this:

Why does

@Html.TextBoxFor(o => o.Code, new { Name = "Child.Code" })

generate

<input name="Child.Code" id="Code" type="text" value="999">

the first time (/Parent/Show), but then generate

<input name="Child.Code" id="Code" type="text" value="1">

the second time (after POSTing to /Parent/Update)?

The Form Data that gets POSTed is

enter image description here

and the binded Model in

public ActionResult Update(Parent parent)
{
    return View("Show", parent);
}

has the expected values of Parent.Code == 1 and Child.Code == 999.

I think Stephen Muecke is probably close to the answer I'm looking for in his comment

Note also that the new { Name = "Child.Code" } hack does not change the id attribute and you have invalid html. – Stephen Muecke

Indeed, using

@Html.TextBoxFor(o => o.Code, new { Name = "Child.Code" })

, I end up with 2 inputs with id="Code", which is invalid according to the spec.

Even knowing that though, I still don't understand why the value attribute generated by TextBoxFor is different based on whether I'm GETing /Parent/Show or POSTing to /Parent/Update.

user3559349

Your use of @Html.Partial("~/Views/Child/Show.cshtml", Model.Child) is generating an input with

<input name="Code" ... />

whereas it need to be

<input = name="Child.Code" ... />

Do not use a partial to generate form controls. Instead use an EditorTemplate which will generate the correct name attributes with the prefix.

Rename you partial to Child.cshtml and place it in the /Views/Shared/EditorTemplates folder, and in the main view use

@Html.EditorFor(m => m.Child)

Edit (based on revised question)

To explain what is happening. When you pass a view to the model and use the HtmlHelpers to generate a form control for a property of your model, the helper first evaluates the expression and gets the ModelMetadata for the property. The ModelMetadata includes the value of the model itself plus addition properties used to determine how you html needs to be generated and how the value of the model is displayed. The helper also adds the htmlAttributes as defined in the 2nd parameter of your TextBoxFor() method.

Now assuming you have edited the value of your second textbox with the value of 999, when you submit the form, its posts back Code=1&Child.Code=999 because you have given the input element an attribute name="Child.Code". The DefaultModelBinder reads the form data, finds a match for both Code and Child.Code in your model and sets their values to 1 and 999 respectively

Now when you return the view your second TextBoxFor() method is binding to property Code (not Child.Code) which has a value of 1 (not 999). Just adding a name attribute does not change the property you binding to (but it does screw up model binding when your send the data back to the controller).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Why does setting the Name attribute explicitly on a Partial View input cause the Value to change after POST?

From Dev

Setting value of name attribute breaks after setAttribute()

From Dev

Why does the 'name' attribute on my hidden input element change from what I set it to be?

From Dev

Why does attribute value of input = text, but attribute value of li = number?

From Dev

Why does my array turn into string separated by ',' after setting it to input value?

From Dev

Why does jquery .val() only change value attribute for hidden input fields?

From Dev

Seed setting: why is the output different after no change in input

From Dev

jQuery change input button value attribute text after click

From Dev

Why does explicitly calling a destructor cause double freeing?

From Dev

Why does explicitly calling a destructor cause double freeing?

From Dev

Post from partial View change the URL

From Dev

Why does min attribute cause ngChange to be called?

From Dev

Change the value of input attribute dynamically

From Dev

Change input value with attribute in javascript

From Dev

Change value attribute of element with specific name attribute

From Dev

Why doesn't explicitly setting the value of an AutoField increment the table sequence?

From Dev

Why does partial invalidate span the entire View?

From Dev

Why does my partial view not working?

From Dev

Setting route value of main url from a partial view

From Dev

Setting route value of main url from a partial view

From Dev

Why does adding a Selected value to my SelectList cause a model change / migration error?

From Dev

Why does top()'s return value change after calling pop()?

From Dev

Model after post not change why

From Dev

Model after post not change why

From Dev

How to change attribute "name" of ion-input when its value changes?

From Dev

I do not understand why setting a value defined in the execution context of a constructor function with a set property does not change the value

From Dev

Why does php form works fine with value="name" not value="$_POST['value']"?

From Dev

Why does the poster attribute of the video element cause my video to offset?

From Dev

Change input value when i press <a> Attribute

Related Related

  1. 1

    Why does setting the Name attribute explicitly on a Partial View input cause the Value to change after POST?

  2. 2

    Setting value of name attribute breaks after setAttribute()

  3. 3

    Why does the 'name' attribute on my hidden input element change from what I set it to be?

  4. 4

    Why does attribute value of input = text, but attribute value of li = number?

  5. 5

    Why does my array turn into string separated by ',' after setting it to input value?

  6. 6

    Why does jquery .val() only change value attribute for hidden input fields?

  7. 7

    Seed setting: why is the output different after no change in input

  8. 8

    jQuery change input button value attribute text after click

  9. 9

    Why does explicitly calling a destructor cause double freeing?

  10. 10

    Why does explicitly calling a destructor cause double freeing?

  11. 11

    Post from partial View change the URL

  12. 12

    Why does min attribute cause ngChange to be called?

  13. 13

    Change the value of input attribute dynamically

  14. 14

    Change input value with attribute in javascript

  15. 15

    Change value attribute of element with specific name attribute

  16. 16

    Why doesn't explicitly setting the value of an AutoField increment the table sequence?

  17. 17

    Why does partial invalidate span the entire View?

  18. 18

    Why does my partial view not working?

  19. 19

    Setting route value of main url from a partial view

  20. 20

    Setting route value of main url from a partial view

  21. 21

    Why does adding a Selected value to my SelectList cause a model change / migration error?

  22. 22

    Why does top()'s return value change after calling pop()?

  23. 23

    Model after post not change why

  24. 24

    Model after post not change why

  25. 25

    How to change attribute "name" of ion-input when its value changes?

  26. 26

    I do not understand why setting a value defined in the execution context of a constructor function with a set property does not change the value

  27. 27

    Why does php form works fine with value="name" not value="$_POST['value']"?

  28. 28

    Why does the poster attribute of the video element cause my video to offset?

  29. 29

    Change input value when i press <a> Attribute

HotTag

Archive