66

I'm trying to change the emitted name of the html input created by @Html.HiddenFor.

The code I'm using this:

@Html.HiddenFor(e => e.SomeProperty, new { @id = "some_property", @name = "some_property" }

Now this works for the id, however it doesn't work for the name. Now I don't really care for the id now, I need the name to change, because that's the one that get's posted back to the target server.

Is there

  • A property I can apply on SomeProperty in my model?
  • A way in the Html.HiddenFor to override the name property?

Or am I stuck to do a plain <input ...> by hand?

Anemoia
  • 7,928
  • 7
  • 46
  • 71

4 Answers4

127

You need to use the Html.Hidden (or write out the <input ...> by hand) instead of the Html.HiddenFor

@Html.Hidden("some_property", Model.SomeProperty, new { @id = "some_property" })

The goal of the strongly typed helpers (e.g the one which the name end "For" like HiddenFor) is to guess the input name for you from the provided expression. So if you want to have a "custom" input name you can always use the regular helpers like Html.Hidden where you can explicitly set the name.

The answer from unjuken is wrong because it generates invalid HTML.

Using that solution generates TWO name attributes:

<input  Name="some_property"  name="SomeProperty" id="some_property" type="hidden" value="test" /> 

So you will have Name="some_property" AND name="SomeProperty" which is INVALID HTML because an input can only have ONE name attribute! (although most browers happen to take the first Name="some_property" and don't care about the second one...)

nemesv
  • 138,284
  • 16
  • 416
  • 359
  • I was having a similar problem with .EditorFor(). I used this trick, and also specified TextBox (instead of Editor). thanks! – Spiky Dec 12 '13 at 17:29
  • You don't even need to include `new { @id = "some_property" `} right? `@Html.Hidden` will generate an id as well as a name? Also why `@id` and `@name`? Neither are C# keywords? – nmit026 Feb 24 '16 at 09:01
  • @nmit026 yes, you don't need the id, and the `@` because they are not keywords. I've just copied the code from the question to my answer. – nemesv Feb 24 '16 at 12:23
  • This doesn't work specifically for the name property as asked in the question. See my answer. – sovemp Feb 22 '17 at 17:53
  • 3
    @sovemp My answer does work and it does work with the `name` attribute: the point that if you use `Html.Hidden` the first parameter will be used as the name: `@Html.Hidden("somePopertyName", "someValue", new { @id = "some_property" })` it will generate `` or you can manually build the input (as I also mentioned in the first line of my answer), as you have also concluded... – nemesv Feb 22 '17 at 18:12
  • 2
    @nemesv Oh, okay sorry I misunderstood. I'll edit my answer to reflect this. One minor suggestion, maybe in your answer use different values for name and id to make that more obvious, other than "some_property" for both – sovemp Feb 22 '17 at 18:18
38

If you use:

@Html.HiddenFor(e => e.SomeProperty, new { @id = "some_property", @Name = "some_property" });

Notice the capital "N" in @Name. It´ll work.

unjuken
  • 1,106
  • 9
  • 9
  • 1
    Worked for me on MVC 4 – Pola Edward Oct 31 '13 at 09:33
  • 4
    @MiniRagnarok no it is not working fine. You will be end up with TWO name attribute. Because the above code generates `` where you have `Name="some_property"` AND `name="SomeProperty"` which is INVALID HTML! (although most browers happen to take the first `Name="some_property"` and don't care about the second one...) – nemesv Nov 26 '13 at 21:07
  • @nemesv That's not what I get. I get ``. I do not get two name attributes, I checked the source. This is on MVC4. – MiniRagnarok Nov 27 '13 at 19:35
  • @nemesv It turns out that Chrome doesn't show me the second name. It still works fine. – MiniRagnarok Nov 27 '13 at 19:51
  • 10
    -1 This won't work. Chrome (or any other browser) would correct the wrong html, which doesn't mean the correct html is rendered. Please don't use this. If chrome change there fixing method then ofcourse invalid html will be rendered. – Subin Jacob Dec 24 '13 at 06:18
  • Works like a charm MVC4 (and chrome) – Michael Harper Nov 10 '14 at 11:19
  • 4
    Doesn't work, Chrome is cleaning up the html. Downvote this answer – Zac Feb 02 '15 at 14:28
  • How does one know the browser is cleaning the html? I'm using MVC5 and I've tested this in IE11, Chrome, FF, and Safari 5 and all works as described above and name even shows up with a lower case n. If I didn't read these comments, I wouldn't have any second thoughts about it. I don't see any browser messages. What's the trick? – Sum None Jul 21 '15 at 09:53
  • @SumNone [This](https://validator.w3.org/nu/) tool can detect duplicated name attributes. – roland Aug 27 '15 at 12:36
  • Still working for me today. Chrome. MVC4. BUT I was displaying to name properties so moved to use @Html.Hidden("clientId", new { value = Model.Client.ID }) instead. – Colin Wiseman Feb 03 '16 at 12:37
  • Works with MVC5, @Name is rendered to name and overwrites the existing generated name. – Oswin Mar 30 '16 at 13:27
  • This works somehow. Not convinced why it should work, – kheya Nov 22 '16 at 00:22
  • Tried this and while it worked fine for mot elements I hit an issue with `checkbox` , digging deeper (hitting F12 and inspecting) I found this was because a hidden false `input` is also rendered alongside the `checkbox` and the name for this does not get changed. – d219 May 14 '23 at 19:49
4

I was curious as to why specifically overriding the name attribute wouldn't work. Unless I capitalized it (i.e. new {@Name = 'somename'} ), then it doesn't seem to work. As others have pointed out, this only works because it generates duplicated name attributes and Chrome cleans it up.

I looked at the latest MVC source code to figure out what is going on. Consider the following snippet from the GenerateInput method in DefaultHtmlGenerator.cs:

var fullName = NameAndIdProvider.GetFullHtmlFieldName(viewContext, expression);
if (string.IsNullOrEmpty(fullName))
{
    throw new ArgumentException(
    ...
}

var inputTypeString = GetInputTypeString(inputType);
var tagBuilder = new TagBuilder("input");
tagBuilder.TagRenderMode = TagRenderMode.SelfClosing;
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("type", inputTypeString);
tagBuilder.MergeAttribute("name", fullName, replaceExisting: true);

We can see here, the problem is that, regardless of whatever name property you provide, it will be overridden by the last call to MergeAttribute, which will use whatever logic it is that assigns to the variable fullName from the GetFullHtmlFieldName method.

I sort of understand why they enforce this behavior, guessing it has something to do with controlling the names used in the postback to guarantee it works with the model binder.

In any case, to make this happen, I say just manually construct the input element and don't use the razor view helper.

sovemp
  • 1,402
  • 1
  • 13
  • 31
1

never worked for me (aspnet.core)

I used plain

<input type="hidden" id="@myid" name="@myname" value="@Model.prop" />

and worked like a charm. No need for HtmlHelper HiddenForModel.

Carl Verret
  • 576
  • 8
  • 21