hidden form element problem - asp.net mvc - asp.net-mvc

I create a strongly typed form like this in my controller:
return View("BlaForm", Bla);
In the view I use something like this:
(1)
<%= Model.Version %>
(2)
<%= Html.Hidden("Version", Model.Version)%>
Here (1) is just for debugging purposes.
After a successive update of my object this produces something like this:
(1)
10
(2)
<input id="Version" name="Version" type="hidden" value="9" />
The hidden value is out of synch for some strange reason ???!!! The Version value was definitely 10 in this case as established by the debugger. Why is this? Are hidden value somehow cached?
Thanks.
Christian
PS:
I also do:
if (TempData["ViewData"] != null)
{
ViewData = TempData["ViewData"] as ViewDataDictionary;
}
in the controller action to maintain form values in case validation errors happen. This seems to be the reason. But still I explicitely do: <%= Html.Hidden("Version", Model.Version)%> .... ???? Maybe I missunderstand the lif cycle a bit?

Html helper will always use the value in the GET or POST request before the value in your model or ViewData. This means that if you post Version=9 to a controller action and inside this action you try to modify its value to 10, when you return the View, the Html.Hidden helper will use the POSTed value and not the one in your Model. The only workaround is a custom HTML helper or simply:
<input id="Version" name="Version" type="hidden" value="<%= Model.Version %>" />

HTML helper will always look for values in ModelStateDictionary, then in ViewData and after this use the value parameter given into helper method.
The 2 other places are in your case.
ModelState state = this.ViewData.ModelState["Version"];
state.Value; // this is the value out of the ModelStateDictionary
object value = this.ViewData["Version"]; // this is the value if set
// out of the ViewData Collection
The ModelStateDictionary gets its entries, while model binding. If you have the Version as a action method parameter, the Modelbinder (in your case the DefaultModelBinder) will enter the key version with the supplied value of get or post request.
If you change the value, put it in your model, you have to update the ModelStateDictionary too.

Related

Misbehaving Asp.net MVC helper methods (ie: Html.TextBox() and Html.Hidden())

I've been trying to debug an issue and I pinned pointed it down to this scenario:
When the statement Html.TextBox("ID", "What the heck..") is executed, I expect it to render:
<input id="ID" name="ID" type="text" value="What the heck.." />
But I get a Guid as its TextBox value such as so:
<input id="ID" name="ID" type="text" value="2e369d2c-071d-4733-8382-cc9e77d0b912" />
Why is Asp.net MVC outputting Guids? I'm not overriding asp.net mvc's framework methods. Please refer to the screenshot.
Update:
Here's another screenshot using Html.Hidden() instead of Html.TextBox(). I couldn't use Html.HiddenFor() directly into the Watch window because HiddenFor() uses lambdas.
#Eric Petroelje and #TLS: You two are correct. TextBox() and Hidden() is retrieving ID's value from the POST variables and not from the current Model or the function's value parameter. Though, I've expected different from HiddenFor() and TextBoxFor(). I expected it to get its value from the POST'ed variables only if it cant get it from the current Model. How can I achieve this?
Maybe you have a POST variable named ID that is a GUID? If that's the case, the HTML Helper method will use that POST value. If no POST value is present, it will fall back to the value in the model.
You are correct that Html.TextBox("ID", "What the heck..") is expected to output the attribute values that you give in your first example; however, if you are using the Html.TextboxFor method, then you're using a MVC Helper that dynamically loads the value of the ID property and places that into the value attribute in the HTML. When you use the Html.TextboxFor method, your second example is the expected HTML output if your ID property is a Guid.

MVC #Html.Display()

I have something like:
<input type="text" name="TerrMng" id="TerrMng"/>
in HTML. What is the equivalent of the above using #Html.Display?
I tried using: #Html.Display("TerrMng", TerrMng)
but was not successful. Note that I like to use #Html.Display but not sure how to translate the ID value so that it shows up.
The Display method is not for creating input boxes. You'd want to use:
#Html.TextBoxFor(m => m.TerrMng);
or the templated helper method:
#Html.EditorFor(m => m.TerrMng);
I'm assuming that you want to use modelbinding. If not, if you really just want to use a helper to simply make an input tag, use:
#Html.TextBox("TerrMng");
This would be sent to the client:
<input id="TerrMng" type="text" value="" name="TerrMng">
The first 2 methods above would result in the exact same html, if model.TerrMng was "" or String.Empty. If for some reason you don't want the value attribute, you'll need to type it out yourself.
This should do the trick if you are just wanting to display the data and not allow the user to edit the information.
#Html.DisplayFor(m => m.TerrMng);
Edit:
what-is-the-html-displayfor-syntax-for is another question on stackoverflow that may give you some more guidance.
Edit:
TerrMng does not exist on PageLoad so you cannot use the Html.Display in that way. You need to create it and fill its value with the value received from the jQuery. In this case where you would have to do the following:
HTML
#Html.Display("TerrMng"); // This creates the label with an id of TerrMng
jQuery
$("#TerrMng").val(TerrMng); // This puts the value of the javascript variable into the label
You could try something based on this. This is not exact but you could get some idea.
#Html.TextBoxFor(yourmodel => model.yourModelFieldname, null)
#Html.Display() is used instead of #Html.DisplayFor() when your model is not known at compile time, or if you prefer to work with strings, rather than with strong types. For example, these 2 are equivalents (given that your model is some class):
#Html.DisplayFor(m => m.MyProperty)
and
#Html.Display("MyProperty")
But the additional cool feature of the Display() method is that it can also do the lookup in the ViewData, and not just in your Model class. For example, here is a way to display the HTML for the property on a random object, given that we know it has a property named "Blah" (the type of the object doesn't really matter):
#{ ViewData["itsawonderfullife"] = SomeObject; }
<div>#Html.Display("itsawonderfullife.Blah")</div>
This way, we are telling HtmlHelper to look into the ViewData, instead of our Model, and to display the property Blah of a given SomeObject.

ASP.NET MVC 3 and HTML Helper Extensions

I am trying to work out whether I am misunderstanding something about ASP.NET MVC or whether I have found some sort of bug in ASP.NET MVC Beta 3. I am having a problem with a PartialView picking up the wrong model when using HTML Helper extensions
My controller code looks like this:
public ActionResult EditGeneral(MapGeneralViewModel vm)
{
var query = MapGeneralViewModel.ToModel(vm, svcMaps);
return PartialView("General", MapGeneralViewModel.FromModel(query));
}
In the case of this being an insert, the property vm.Id starts out as -1 and after the call to MapGeneralViewModel.ToModel it has been persisted the database and query.Id has a proper value.
The call to MapSettingsViewModel.FromModel returns a new viewmodel and I have checked that the Id property correct contains the newly created id value.
The relevant bits of the view look like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AdminWebRole.Models.Map.MapGeneralViewModel>" %>
<%: Model.Id %>
<%= Html.Hidden("IdTest", Model.Id) %>
<%= Html.HiddenFor(model => model.Id) %>
If I put a breakpoint in the view, Model.Id is correctly set to the right value.
The actual output of the controller (when Model.Id == 70) looks like this:
70
<input id="IdTest" name="IdTest" type="hidden" value="-1" />
<input id="Id" name="Id" type="hidden" value="-1" />
So the value output without using the HTML helpers is correct, but the values output by the helpers somehow is picking up the viewmodel that was passed into the controller !
I have no idea how this is happening. I have tried various things:
Using View() rather than PartialView()
assigning the results of MapGeneralViewModel.FromModel() to vm and then passing vm to the view
using <%: and <%=
setting vm to null (the old view model somehow still gets used)
changing the value of the incoming id to 0 (results in 0 being output in the view instead of -1)
the problem isn't specific to properties called "Id", I have also tested other fields with the same result
Am I confused over how this is supposed to work or have I hit a beta bug ? If it makes any difference, this is running inside my local Azure runtime on a Win7 64 bit machine.
There is no way that MVC is just picking up a variable that you haven't explicitly passed to your view or have hanging around in Session or TempData.
Since you're setting that Id to -1 I'm start there for problems.
The other possibility is that -1 is hanging around in your ModelState someplace. The HTML helpers look to ModelState first before deciding to use any values you pass in.
I have just come across a similar issue in a partial view that I use for displaying the items in an order.
I was using the following to render a hidden input.
#Html.Hidden("salesorderlineid", orderLine.SalesOrderLineID)
This works fine until I delete an item, when the ID of the wrong (deleted) item is used. I double-checked the model, this was correct and rendered correctly in other usages on the same view.
I coded the hidden input directly as html and it works fine - looks like an MVC3 bug perhaps?
<input type="hidden" name="salesorderlineid" value="#orderLine.SalesOrderLineID"/>

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])

How do you handle the output of a dynamically generated form in ASP.NET MVC?

Say you create a form using ASP.NET MVC that has a dynamic number of form elements.
For instance, you need a checkbox for each product, and the number of products changes day by day.
How would you handle that form data being posted back to the controller? You can't set up parameters on the action method because you don't know how many form values are going to be coming back.
Just give each checkbox a unique name value:
<input class="approveCheck" id="<%= "approveCheck" + recordId %>"
name="<%= "approveCheck" + recordId %>" type="checkbox" />
Then parse the list of form values in the Action, after submit:
foreach (var key in Request.Form.Keys)
{
string keyString = key.ToString();
if (keyString.StartsWith("approveCheck", StringComparison.OrdinalIgnoreCase))
{
string recNum = keyString.Substring(12, keyString.Length - 12);
string approvedKey = Request.Form["approveCheck" + recNum];
bool approved = !String.IsNullOrEmpty(approvedKey);
// ...
You don't need to pass form values as arguments; you can just get them from Request.Form.
One other option: write a model binder to change the list into a custom type for form submission.
Per Craig's answer.. that is safer. There are quirks to posting multiple form elements with the same name. I would add that it would be wise to wrap the logic that makes the "collection" of controls in a way similar to WebForms. Web Forms prepend the container control's name and adds an index. For example, in a Repeater the form elements inside would be named (something like) RepeaterName_Element1, RepeaterName_Element2. When you go to get the elements out, you have to use FindControl or something of the sort.
Depending on the binders you are using, this should work:
<%var i = 0;
foreach (var product (IList<ProductSelection>)ViewData["products"]) {%>
<%=Html.Hidden(string.Format("products[{0}].Id", i), product.Id)%>
<%=Html.Checkbox(string.Format("products[{0}].Selected", i))%>
<%=product.Name%><br/>
<%}%>
...which will result in HTML something like this (notice the array notation on the names):
<input name="products[0].Id" type="hidden" value="123">
<input name="products[0].Selected" type="checkbox">
Widget
<input name="products[1].Id" type="hidden" value="987">
<input name="products[1].Selected" type="checkbox">
Gadget
...and the controller method that handles the post:
public ActionResult SelectProducts(IList<ProductSelection> products)
{
...
}
Upon binding, products parameter will contain two instances of ProductSelection.
One caveat is that I have not used the new default binding for complex objects. Rather I am using either the NameValueDeserializer or CastleBind, both from MvcContrib. They both behave this way. I am guessing binding in the Beta will work the same way.
Depending on your data, you could either output a 'CheckboxList' (which is not possible in the newer versions any more) and use a string[] parameter, or you could set up multiple forms and just modify the action.

Resources