HTML.CheckBox Behaviour - asp.net-mvc

I am using a model where a check box is there . where i am posting the form i always get more than one boolean value, Code is as follow
//controller code
// GET: /Home/
// GET: /Home/Test
public ActionResult HomeTest()
{
HomeTest ht = new HomeTest();
return View(ht);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult HomeTest(FormCollection collection, HomeTest model)
{
string str = collection["test"].ToString();
return View(model);
}
//View Html
<%= Html.CheckBox("test") %>
I am getting following value in str while debugging "true,false". Am i do anything wrong?

This is how Html.CheckBox was designed!
It always renders
<input name="test" type="checkbox" value="true" />
followed by a
<input name="test" type="hidden" value="false" />.
When you submit the form with the checkbox checked, you'll get test=true,false and when the checkbox is unchecked, you get test=false.
This is how it supports binding to a boolean value, because the ,false part is ignored. However, if you're binding to something else (such as string), that's when you'll see the "true,false" value.
If you want different behavior, you'll have to roll-your-own Html.CheckBoxAlt method. Here's a similar question, along with some code, that I wrote a while back: Passing checkbox selection through to an action

MVC does things this way so it can tell the difference between "There is no checkbox called 'test'" and "The checkbox called 'test' is unchecked." Since HTML doesn't provide any built-in way to tell the difference, MVC makes it always send a "false" value, which will get overridden by a "true" value if you check the box.
The easiest solution is to make better use of MVC's approach. Rather than using the FormCollection, just use a parameter that the model binder can bind to:
public ActionResult HomeTest(bool test, HomeTest model)

Related

MVC #Html.CheckboxFor submits true,false on form submission

I am using MVC 5 with EF Code First and have a View model that contains a bool:
public bool MyCheckbox { get; set; }
I initialize this in my View's get:
model.MyCheckbox = true;
In the View:
#Html.CheckBoxFor(m => m.MyCheckbox)
Which get rendered as:
<input checked="checked" data-val="true" data-val-required="The field is required." id="MyCheckbox" name="MyCheckbox" type="checkbox" value="true" />
<input name="MyCheckbox" type="hidden" value="false" />
One of my Buttons on the View triggers an Ajax POST to the Controller where I want to look at the checkbox value:
bool bValue = Request["MyCheckbox"] == "true";
But the value of Request["MyCheckbox"] is "true,false" due to the extra hidden field with name="MyCheckbox".
How do I view the value of this checkbox in the controller with Request["..."] and make sense of it (either true or false)?
I also have another bool member in the View model and I use it in a hidden field intentionally. In the model:
bool MyHiddenBool { get; set; }
In the Controller Get:
model.MyHiddenBool = true;
In the View:
#Html.HiddenFor(x => x.MyHiddenBool)
In the Controller (via Ajax POST):
bool AnotherBool = Request["MyHiddenBool"] == "true";
But the value of Request["MyHiddenBool"] is either "True" or "False" instead of "true" and "false".
What gives with this inconsistency and how can I reliably see the values of these two methods of bools in my Views?
The problem is how you are consuming the form request variable.
In ASP.NET MVC there's probably never a good reason to use Request.Form or it's variants to consume your request data. You need to make a model or put in an argument for the action.
[HttpPost]
public ActionResult PostedForm(bool myHiddenBool)
{
//Frameworks model binder will extract the form field into your variable based on the name
}
The following copied from this answer.
This isn't a bug, and is in fact the same approach that both Ruby on
Rails and MonoRail use.
When you submit a form with a checkbox, the value is only posted if
the checkbox is checked. So, if you leave the checkbox unchecked then
nothing will be sent to the server when in many situations you would
want false to be sent instead. As the hidden input has the same name
as the checkbox, then if the checkbox is unchecked you'll still get a
'false' sent to the server.
When the checkbox is checked, the ModelBinder will automatically take
care of extracting the 'true' from the 'true,false'

How to pass a hidden field value from one controller to another controller using Asp.net MVC Razor

I am trying to pass a hidden field value from a view in one controller to another controller. I tried the below code:
#using (Html.BeginForm("AddToCart","Cart"))
{
<input type="hidden" id="testName" value= #model[0].tblProd[0].ProductName />
}
and tried to retrieve that code in a controller called "Cart" as follows:
public ViewResult AddToCart(FormCollection collection1)
{
string prodName = Request["testName"];
return View();
}
But it's not work. Can someone assist me in solving this.
When a form is submitted, the values are sent to the server using the name property.
In your example the input only has an id.
Try:
<input type="hidden" id="testName" name="testName" value= #model[0].tblProd[0].ProductName />
Also, you can let default model binding take care of reading the POSTed values and setting properties for you so you don't have to do it manually with Request["testName"]:
public ViewResult AddToCart(FormCollection collection1, string testName)

Why is MVC persisting on HttpGet?

I thought I understood MVC until now.
To me a GET should be from a clean slate. But I discoved today MVC assumes a GET to be a POST if a page request a get from itself.
The text box should always show the text "Red" but instead it persist its last value from the previous view.
Acting like an HTTPPost. You have to uncomment ModelState.Clear to act like a HttpGet.
This appears to me to be a bug.
<form action="" method="get">
<div>
<%=Html.TextBox("search") %>
<input type="submit" value="Search" />
</div>
</form>
[HttpGet]
public ActionResult Index(string search)
{
//ModelState.Clear();
ViewData["search"] = "Red";
var items = GetYourTestData;
if (!string.IsNullOrEmpty(search))
{
var items2 = items.Where(x => x.Color == search).ToList();
return View(items2);
}
return View(items);
}
The search results returns correct and different data so it is not browser cache.
For the purpose of a search results page it does not make sense to have to redirect to another page to avoid this. That is why I chose GET thinking it should be clean each time.
Like I stated in the description. Other contents on the page does change so it is not cache. Uncomment ModelState.Clear() and all is good so that is not cache.
You can put a dynamic datetime label always showing the latest time from the server and it does change. That also proves it is not page cache.
It is a very simple test to do. Yes, just a sure as there is gravity, MVC2 framework 4.0 considers it an HTTPPost if the HttpGet requested page is the same as the requester. If you are not aware of this during programming the results could be disastrous. For instance, If someone like TurboTax uses MVC I hope that their developer are aware of that.
... ViewData["AdjustedTaxAmount"]=3435.00; ... is not going to work unless they call this
ModelState.Clear().
I don't know of why there should be ModelState on a get so
one sure fire work around is to
Inherit Controller from a base class
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
ModelState.Clear();
}
base.OnActionExecuted(filterContext);
}
The browser will cache GET requests that are from the same URL. If you add a querystring variable that is random then the GET request will be different each time and the browser will not cache the result.
That's to be expected.
When you submit a form via GET, you're serializing its elements and passing those to the target via the QueryString. So, it makes sense that your search value would be part of MVC's model in the next request. When you use the Html.TextBox helper, it's going to automatically inject the model's value as the HTML input's value. That's why you're seeing the value cover over.
One solution to avoid that is to not use the HTML Helper to render the input:
<form action="" method="get">
<div>
<input type="text" name="search" />
<input type="submit" value="Search" />
</div>
</form>
Then, you should get the clean slate you're expecting after each form submission.

asp.net MVC checkbox headache!

I have seen lots of questions relating to this topic.
I am using asp.net MVC 1.0
Problem area
If I use
<%= Html.CheckBox("Status", true) %>
Then why It renders like
<input checked="checked" id="Status" name="Status" type="checkbox" value="true" /><input name="Status" type="hidden" value="false" />
I put this in foreach loop and I have 5 rows.
when I submit form with true,true,true,false,false
then I get true,false,true,false,true,false,false,false
i.e. for false => false.
for true => true,false
If I use
<input type="checkbox" value="true" name="Status" checked="checked" />
Then I don't get unchecked one's.
so how do I overcome form this problem?
Please don't post answer with using loop in formcollection object and checking each key!
I know this isn't the elegant one but this is what I did:
collection["response"].Replace("true,false", "true").Split(',').ToList();
In your example, when you submit form with true,true,true,false,false and you get
true,false,true,false,true,false,false,falseit is interesting to note that you are not actually getting eight values back, but five arrays that merely looks like this is the case because all of the values are joined.
I know you asked to not get a loop for your answer, but I can use one to demonstrate what is really happening here:
foreach (string key in postedForm.AllKeys) {
// "value" will contain a joined/comma-separated list of ALL values,
// including something like "true,false" for a checked checkbox.
string value = postedForm[key].GetValue;
// "values" will be an array, where you can access its first element,
// e.g., values[0], to get the actual intended value.
string[] values = postedForm.GetValues(key);
}
So, for your checked boxes, you'll get a values array with two elements, and for unchecked boxes, you'll get just a single-element array.
Thus, to answer your question how do you overcome this problem, the answer lies in using GetValues rather than GetValue, and thinking of your posted fields as arrays rather than strings.
Best of luck!
Personally I think having to check for "true,false" everywhere on the server is a pain. I wrote a jquery fix that will remove the extra hidden field created by the Html.Checkbox helper when a box is checked, then add it back if the box is unchecked. Server values will always be "true" or "false". Checkbox lists are kind of subjective in how you want them to act, which I discuss, but I'm removing "false" from the value set, which means the form value will be excluded if all boxes in the list are unchecked.
http://www.mindstorminteractive.com/blog/?p=386
I've had pretty good success using this technique. Please let me know if you try it out and have issues.
You'll have to do your own model binding for the CheckBox values.
Get the list of values from the FormCollection or Request.Form for that CheckBox id and replace true,false with true:
string chkBoxString = Request.Form["checkboxID"].Replace("true,false", "true")
Now you have a list of whether a CheckBox was selected or not.... do the rest yourself :)
It renders so because default binder requires the FormCollection to have a value for nonnullable parameters. Using this technique we are sure that the value will be sent even the checkbox is not checked (by default the value sent only when it's checked). If you use this controller method with just one html input you'll get error on form post with unchecked checkbox (value of checkbox will not be posted and binder will not know what to use for value of isItemSelected):
public ActionResult SomeActionMethod(bool isItemSelected)
You can try use something like this with just one html input:
public ActionResult SomeActionMethod(bool? isItemSelected)
But in this case isItemSelected will be null or will be true. And it will never become false.
Well there are couple of ways you can do based on your requirement.
I use this method.
<input type="checkbox" value="<%= item.ID %>" name="check" checked="checked")" />
This is may checkboxes.
On server side I will also have array of ID's of item in the model.
So I check it whether it is in array
var strArray = form["checkbox"]; //Request.form["checkbox"] or "FormCollection form" in action parameter; array of ID's in comma separated string.
Different people have different tests.
this was intended to use for just just simple CheckBox, what you want is checkboxList, which is not yet cover in the API of ASP.net MVC
If you looking for some thing like checkboxlist, maybe you should write your own helper, provide you understand HTML well..
That's it! :)
Easier just to check whether AttemptedValue.Contains("true") - it will, if it's checked, not if it's unchecked....
in the View :
<input id="radio5" type="checkbox" name="rb_abc" value="5"/>
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult YourForm(FormCollection fc)
{
if (fc["rb_abc"] == "on")
{
//Hey .. you have selected a Radio Button.. just kidding.. its a CheckBox
}
}
To get checkbox value even it is true or false
var boolValue = bool.Parse(collection.GetValues("checkboxID")[0])

Possible bug in ASP.NET MVC with form values being replaced

I appear to be having a problem with ASP.NET MVC in that, if I have more than one form on a page which uses the same name in each one, but as different types (radio/hidden/etc), then, when the first form posts (I choose the 'Date' radio button for instance), if the form is re-rendered (say as part of the results page), I seem to have the issue that the hidden value of the SearchType on the other forms is changed to the last radio button value (in this case, SearchType.Name).
Below is an example form for reduction purposes.
<% Html.BeginForm("Search", "Search", FormMethod.Post); %>
<%= Html.RadioButton("SearchType", SearchType.Date, true) %>
<%= Html.RadioButton("SearchType", SearchType.Name) %>
<input type="submit" name="submitForm" value="Submit" />
<% Html.EndForm(); %>
<% Html.BeginForm("Search", "Search", FormMethod.Post); %>
<%= Html.Hidden("SearchType", SearchType.Colour) %>
<input type="submit" name="submitForm" value="Submit" />
<% Html.EndForm(); %>
<% Html.BeginForm("Search", "Search", FormMethod.Post); %>
<%= Html.Hidden("SearchType", SearchType.Reference) %>
<input type="submit" name="submitForm" value="Submit" />
<% Html.EndForm(); %>
Resulting page source (this would be part of the results page)
<form action="/Search/Search" method="post">
<input type="radio" name="SearchType" value="Date" />
<input type="radio" name="SearchType" value="Name" />
<input type="submit" name="submitForm" value="Submit" />
</form>
<form action="/Search/Search" method="post">
<input type="hidden" name="SearchType" value="Name" /> <!-- Should be Colour -->
<input type="submit" name="submitForm" value="Submit" />
</form>
<form action="/Search/Search" method="post">
<input type="hidden" name="SearchType" value="Name" /> <!-- Should be Reference -->
<input type="submit" name="submitForm" value="Submit" />
</form>
Please can anyone else with RC1 confirm this?
Maybe it's because I'm using an enum. I don't know. I should add that I can circumvent this issue by using 'manual' input () tags for the hidden fields, but if I use MVC tags (<%= Html.Hidden(...) %>), .NET MVC replaces them every time.
Many thanks.
Update:
I've seen this bug again today. It seems that this crops its head when you return a posted page and use MVC set hidden form tags with the Html helper. I've contacted Phil Haack about this, because I don't know where else to turn, and I don't believe that this should be expected behaviour as specified by David.
Yes, this behavior is currently by design. Even though you're explicitly setting values, if you post back to the same URL, we look in model state and use the value there. In general, this allows us to display the value you submitted on postback, rather than the original value.
There are two possible solutions:
Solution 1
Use unique names for each of the fields. Note that by default we use the name you specify as the id of the HTML element. It's invalid HTML to have multiple elements have the same id. So using unique names is good practice.
Solution 2
Do not use the Hidden helper. It seems like you really don't need it. Instead, you could do this:
<input type="hidden" name="the-name"
value="<%= Html.AttributeEncode(Model.Value) %>" />
Of course, as I think about this more, changing the value based on a postback makes sense for Textboxes, but makes less sense for hidden inputs. We can't change this for v1.0, but I'll consider it for v2. But we need to think through carefully the implications of such a change.
Same as others I would have expected the ModelState to be used to fill the Model and as we explicitly use the Model in expressions in the view, it should use the Model and not ModelState.
It's a design choice and I do get why: if validations fail, the input value might not be parseable to the datatype in the model and you still want to render whatever wrong value the user typed, so it's easy to correct it.
The only thing I don't understand is: why isn't it by design that the Model is used, which is set explicitly by the developer and if a validation error occurred, the ModelState is used.
I have seen many people using workarounds like
ModelState.Clear(): Clears all ModelState values, but basically disables usage of default validation in MVC
ModelState.Remove("SomeKey"): Same as ModelState.Clear() but needs micromanagement of ModelState keys, which is too much work and it doesn't feel right with the auto binding feature from MVC. Feels like 20 years back when we were also managing Form and QueryString keys.
Rendering HTMLthemselves: too much work, detail and throws away the HTML Helper methods with the additional features.
An example: Replace #Html.HiddenFor by <input type="hidden" name="#NameFor(m => m.Name)" id="#Html.IdFor(m=>m.Name)" value="#Html.AttributeEncode(Model.Name)">. Or replace #Html.DropDownListFor by ...
Create custom HTML Helpers to replace default MVC HTML Helpers to avoid the by-design issue. This is a more generic approach then rendering your HTML, but still requires more HTML+MVC knowledge or decompiling System.Web.MVC to still keep all other features but disable ModelState precedence over Model.
Apply the POST-REDIRECT-GET Pattern: this is easy in some environments, but harder in the ones with more interaction/complexity. This pattern has it's pros and cons and you shouldn't be forced to apply this pattern because of a by-design choice of ModelState over Model.
Issue
So the issue is that the Model is filled from ModelState and in the view, we set explicitly to use the Model. Everybody expects the Model value (in case it changed) to be used unless there's a validation error; then the ModelState can be used.
Currently, in the MVC Helper extensions, the ModelState value gets precedence over the Model value.
Solution
So the actual fix for this issue should be: for each expression to pull the Model value the ModelState value should be removed if there is no validation error for that value. If there's a validation error for that input control the ModelState value shouldn't be removed and it will be used like normal.
I think this solves the issue exactly, which is better than most workarounds.
The code is here:
/// <summary>
/// Removes the ModelState entry corresponding to the specified property on the model if no validation errors exist.
/// Call this when changing Model values on the server after a postback,
/// to prevent ModelState entries from taking precedence.
/// </summary>
public static void RemoveStateFor<TModel, TProperty>(this HtmlHelper helper,
Expression<Func<TModel, TProperty>> expression)
{
//First get the expected name value. This is equivalent to helper.NameFor(expression)
string name = ExpressionHelper.GetExpressionText(expression);
string fullHtmlFieldName = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
//Now check whether modelstate errors exist for this input control
ModelState modelState;
if (!helper.ViewData.ModelState.TryGetValue(fullHtmlFieldName, out modelState) ||
modelState.Errors.Count == 0)
{
//Only remove ModelState value if no modelstate error exists,
//so the ModelState will not be used over the Model
helper.ViewData.ModelState.Remove(name);
}
}
And then we create our own HTML Helper extensions todo this before calling the MVC extensions:
public static MvcHtmlString TextBoxForModel<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
string format = "",
Dictionary<string, object> htmlAttributes = null)
{
RemoveStateFor(htmlHelper, expression);
return htmlHelper.TextBoxFor(expression, format, htmlAttributes);
}
public static IHtmlString HiddenForModel<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
RemoveStateFor(htmlHelper, expression);
return htmlHelper.HiddenFor(expression);
}
This solution removes the issue but doesn't require you to decompile, analyze, and rebuild whatever MVC is offering you normally (don't forget also managing changes over-time, browser differences, etc.).
I think the logic of "Model value unless validation error then ModelState" should have been by-design. If it was, it wouldn't have bitten so many people, but still covered what MVC was intended todo.
I just ran into same issue. Html helpers like TextBox() precedence for passed values appear to behave exactly opposite what I inferred from the Documentation where it says:
The value of the text input element. If this value is null reference
(Nothing in Visual Basic), the value of the element is retrieved from
the ViewDataDictionary object. If no value exists there, the value is
retrieved from the ModelStateDictionary object.
To me, I read that the value, if passed is used. But reading TextBox() source:
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter), isExplicitValue);
seems to indicate that the actual order is the exact opposite of what is documented. Actual order seems to be:
ModelState
ViewData
Value (passed into TextBox() by caller)
Heads-up - this bug still exists in MVC 3. I'm using the Razor markup syntax (like that really matters), but I encountered the same bug with a foreach loop that produced the same value for an object property every single time.
This would be the expected behavoir - MVC doesn't use a viewstate or other behind your back tricks to pass extra information in the form, so it has no idea which form you submitted (the form name is not part of the data submitted, only a list of name/value pairs).
When MVC renders the form back, it is simply checking to see if a submitted value with the same name exists - again, it has no way of knowing which form a named value came from, or even what type of control it was (whether you use a radio, text or hidden, it's all just name=value when its submitted through HTTP).
foreach (var s in ModelState.Keys.ToList())
if (s.StartsWith("detalleProductos"))
ModelState.Remove(s);
ModelState.Remove("TimeStamp");
ModelState.Remove("OtherOfendingHiddenFieldNamePostedToSamePage1");
ModelState.Remove("OtherOfendingHiddenFieldNamePostedToSamePage2");
return View(model);
This issue still exists in MVC 5, and clearly it's not considered a bug which is fine.
We're finding that, although by design, this is not the expected behavior for us. Rather we always want the value of the hidden field to operate similarly to other types of fields and not be treated special, or pull its value from some obscure collection (which reminds us of ViewState!).
A few findings (correct value for us is the model value, incorrect is the ModelState value):
Html.DisplayFor() displays the correct value (it pulls from Model)
Html.ValueFor does not (it pulls from ModelState)
ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model pulls the correct value
Our solution is to simply implement our own Extension:
/// <summary>
/// Custom HiddenFor that addresses the issues noted here:
/// http://stackoverflow.com/questions/594600/possible-bug-in-asp-net-mvc-with-form-values-being-replaced
/// We will only ever want values pulled from the model passed to the page instead of
/// pulling from modelstate.
/// Note, do not use 'ValueFor' in this method for these reasons.
/// </summary>
public static IHtmlString HiddenTheWayWeWantItFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object value = null,
bool withValidation = false)
{
if (value == null)
{
value = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;
}
return new HtmlString(String.Format("<input type='hidden' id='{0}' name='{1}' value='{2}' />",
htmlHelper.IdFor(expression),
htmlHelper.NameFor(expression),
value));
}
Example to reproduce the "design problem", and a possible workaroud.
There is no workaround for the 3 hours lost trying to find the "bug" though ...
Note that this "design" is still in ASP.NET MVC 2.0 RTM.
[HttpPost]
public ActionResult ProductEditSave(ProductModel product)
{
//Change product name from what was submitted by the form
product.Name += " (user set)";
//MVC Helpers are using, to find the value to render, these dictionnaries in this order:
//1) ModelState 2) ViewData 3) Value
//This means MVC won't render values modified by this code, but the original values posted to this controller.
//Here we simply don't want to render ModelState values.
ModelState.Clear(); //Possible workaround which works. You loose binding errors information though... => Instead you could replace HtmlHelpers by HTML input for the specific inputs you are modifying in this method.
return View("ProductEditForm", product);
}
If your form originally contains this: <%= Html.HiddenFor( m => m.ProductId ) %>
If the original value of "Name" (when the form was rendered) is "dummy", after the form is submitted you expect to see "dummy (user set)" rendered.
Without ModelState.Clear() you'll still see "dummy" !!!!!!
Correct workaround:
<input type="hidden" name="Name" value="<%= Html.AttributeEncode(Model.Name) %>" />
I feel this is not a good design at all, as every mvc form developer needs to keep that in mind.
This may be 'by design' but it's not what is documented:
Public Shared Function Hidden(
ByVal htmlHelper As System.Web.Mvc.HtmlHelper,
ByVal name As String, ByVal value As Object)
As String
Member of System.Web.Mvc.Html.InputExtensions
Summary: Returns a hidden input tag.
Parameters:
htmlHelper: The HTML helper.
name: The form field name and System.Web.Mvc.ViewDataDictionary key used to look up the value.
value: The value of the hidden input. If null, looks at the System.Web.Mvc.ViewDataDictionary and then System.Web.Mvc.ModelStateDictionary for the value.
This would seem to suggest that ONLY when the value parameter is null (or not specified) would the HtmlHelper look elsewhere for a value.
In my app, I've got a form where: html.Hidden("remote", True) is rendering as
<input id="remote" name="remote" type="hidden" value="False" />
Note the value is getting over-ridden by what is in the ViewData.ModelState dictionary.
Or am I missing something?
So in MVC 4 the "design problem" still there. Here's the code I had to use in order to set the correct hidden values in a collection since regardless of what I do in the controller, the view always showed incorrect values.
OLD code
for (int i = 0; i < Model.MyCollection.Count; i++)
{
#Html.HiddenFor(m => Model.MyCollection[i].Name) //It doesn't work. Ignores what I changed in the controller
}
UPDATED code
for (int i = 0; i < Model.MyCollection.Count; i++)
{
<input type="hidden" name="MyCollection[#(i)].Name" value="#Html.AttributeEncode(Model.MyCollection[i].Name)" /> // Takes the recent value changed in the controller!
}
Did they fixed this in MVC 5?
There is workaround:
public static class HtmlExtensions
{
private static readonly String hiddenFomat = #"<input id=""{0}"" type=""hidden"" value=""{1}"" name=""{2}"">";
public static MvcHtmlString HiddenEx<T>(this HtmlHelper htmlHelper, string name, T[] values)
{
var builder = new StringBuilder(values.Length * 100);
for (Int32 i = 0; i < values.Length;
builder.AppendFormat(hiddenFomat,
htmlHelper.Id(name),
values[i++].ToString(),
htmlHelper.Name(name)));
return MvcHtmlString.Create(builder.ToString());
}
}
As others have suggested, I went with using direct html code instead of using the HtmlHelpers (TextBoxFor, CheckBoxFor, HiddenFor etc.).
The problem though with this approach is that you need to put the name and id attributes as strings. I wanted to keep my model properties strongly-typed so I used the NameFor and IdFor HtmlHelpers.
<input type="hidden" name="#Html.NameFor(m => m.Name)" id="#Html.IdFor(m=>m.Name)" value="#Html.AttributeEncode(Model.Name)">
Update:
Here's a handy HtmlHelper extension
public static MvcHtmlString MyHiddenFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null)
{
return new MvcHtmlString(
string.Format(
#"<input id=""{0}"" type=""hidden"" value=""{1}"" name=""{2}"">",
helper.IdFor(expression),
helper.NameFor(expression),
GetValueFor(helper, expression)
));
}
/// <summary>
/// Retrieves value from expression
/// </summary>
private static string GetValueFor<TModel, TValue>(HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
object obj = expression.Compile().Invoke(helper.ViewData.Model);
string val = string.Empty;
if (obj != null)
val = obj.ToString();
return val;
}
You can then use it like
#Html.MyHiddenFor(m => m.Name)

Resources