Does MVC remember checkbox values after submit? - asp.net-mvc

I'm a php head and getting to grips with ASP.NET MVC 5.
In php, after submitting checkbox fields, in order to post back the form with the checkboxes you checked initially set to true, you have to run a if isset on em.
However reading up on model binding in mvc, it seems that this is done automatically for you, i.e checkboxes are returned after form submit checked, if originally selected, using either the HTML.CheckBox or HTML.CheckBoxFor helpers.
Is this the case, or am I expecting too much of MVC?

No, ASP.NET MVC doesn't remember checkbox values after they're submitted. Being an HTTP application as soon as ASP.NET MVC has rendered the HTML it ends the request and forgets everything about what it's just done. Then upon submitting a form ASP.NET MVC processes the incoming HTTP request and maps it to your model via its model binding (more on how it does this in a moment).
Having come from a PHP background myself this is one of those questions I always had when starting with ASP.NET MVC.
With ASP.NET MVC you have to remember that you're working within the context of a complete framework, and in order to ensure you're as productive as possible ASP.NET MVC will take care of a lot of the mundane work for you - ASP.NET MVC's model binding is a perfect example of this.
When submitting a form, the ASP.NET MVC framework will parse all incoming post data and attempt to automatically map it to the values you're providing it via your controller action.
So where as in PHP you'd normally do something along the lines of:
if(isset($_POST['checkboxValue'])) {
$checkboxVal = $_POST['checkboxValue'];
}
ASP.NET MVC will automaltically bind the incoming post data to your action parameter like so:
[HttpPost]
public ActionResult Submit(bool checkboxValue){
}
It does this by checking the parameter name (checkboxValue) matches that of the post data array key, and that the type also matches up. For instance, if you were to change the above checkboxValue from a boolean to a string and change the name, then ASP.NET MVC's model binding will be unable to match the property to the post data and will not automatically set the value for you.
It's also worth noting that ASP.NET MVC's model binding doesn't know how you created the checkbox.
The HTML.CheckBox and HTML.CheckBoxFor html helpers are purely a means to make it easier for you to create the HTML. If you were to manually write the HTML yourself then the model binder will still successfully bind the submitted data.
Edit:
As #DrinkBird has quite rightly pointed out, you're also able to access all of your form's post data by using the FormCollection instance like so:
[HttpPost]
public ActionResult Submit(FormCollection postData){
}
This collection represents all of the data posted to the Submit action.

Yes, model-binding should allow you to retrieve the value of a checkbox on submission.
if your model looks like:
public class myModel
{
public bool myBool {get; set;}
}
and in your HTML, you've used the helper
#Html.CheckBoxFor(m => m.myBool)
Then in your post action to handle the submission:
[HttpPost]
public ActionResult MyAction(myModel model)
{
var whatsThis = model.myBool;
}
...whatsThis will be true if the checkbox was checked, false if not.
Part of why this works is that when you use #html.CheckBoxFor, it also places a hidden form field that will pass false if the box is unchecked, to aid with model binding -- if it didn't, per HTTP there would be no varibalbe 'myBool' submitted in the post-vars collection.
If you return this model back into the form (say, if it didn't validate), then the form will re-present the checkbox in whatever state it was in on submission:
[HttpPost]
public ActionResult MyAction(myModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
else
{
//do success
}
}

Related

how to test form submission in mvc

I'm sending some param via form post from my template and the action in my controller is handling it accordingly.
Now I want to write a test case for that action. How should I make that dummy request so that Request.Form["selectedSuppliersHidden"] will work in controller action?
You shouldn't really need to use Request.Form in MVC
Give this a read: http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx
If you handle posting correctly then you'll have an Action that can accept variables and be tested a lot easier.
EDIT
You can use the FormCollection param in your Action, something like this
[HttpPost]
public ActionResult Index(string btnSubmit, FormCollection collection)
{
//btnSubmit this is the button that is clicked.
return View();
}
The FormCollection will have everything in it from the Request.Form collection. But you should still be able to post the right hand listbox in the normal MVC way

ASP.NET MVC auto-binds a refreshed model when ModelState is invalid on HttpPost

I'm working on an ASP.NET MVC2 app. I've come to realize a very surprising, yet amazing thing that MVC does behind the scenes having to do with the ModelState and model binding. I have a ViewModel which has a whole bunch of data - some fields being part of a form while others are simply part of the UI. On HttpPost, my Action method uses the DefaultModelBinder which attempts to bind the whole model, but only fields which were part of the form are successfully deserialized - all others remain null. That's fine and understandable. If the ModelState is invalid, I need to refresh the model from the db and bind those particular form fields before returning to the same edit view to display those associated ModelState validation errors.
Here's where my amazement and curiosity comes. It was my assumption that in order for me to bind the form fields with the refreshed model, I needed to make a call to either UpdateModel() or TryUpdateModel<>(), passing in the newly refreshed model. For example:
[HttpPost]
public ActionResult EditDetail(EditDetailItemModel model)
{
if (model.IsValid)
{
// Save the results to the db
return RedirectToAction(...)
}
// Can't simply "return View(model)". Not all fields in EditDetailItemModel
// were part of the form - thus they returned null. Have to refresh
// model from the db.
var refreshedModel = RefreshModelFromDB();
// Is this line necessary?????
TryUpdateModel<EditDetailItemModel>(refreshedModel);
return View(refreshedModel);
}
But, what I found was that if I simply returned refreshedModel to the view WITHOUT making a call to TryUpdateModel<>(), the refreshed model was automatically bound with the form field values posted!! Hence, the TryUpdateModel<>() is not needed here!
The only way I can make any sense of it is that since the ModelState is in an invalid state, once I returned the view with the refreshed model, the "MVC rendering engine" looped through the ModelState errors and bound those property values with my refreshed model. That is simply AWESOME! But, I want proof as to this assumption. I can't find documentation regarding this anywhere on the web. Can anyone either confirm my hypothesis of WHY/HOW this AWESOME auto binding behavior is occuring and/or educate me as to why/how it's happening, hopefully backed up with some online documentation links so I understand more fully what's going on under the covers?
public ActionResult EditDetail(EditDetailItemModel model)
That line will perform model binding. Think of ActionMethod parameters as always being populated by a call to UpdateModel.
You are not seeing refreshedModel's values in the view, you are seeing the ModelState entries and values from EditDetailItemModel.

Posting multiple values using MVC

I have a model with a property that points to a file that contains HTML. My strongly typed view to this model uses a custom HTML helper method to resolve and return the HTML from the file. Works great so far.
The HTML read from each file will contain various controls whose values I need to retrieve when the form is POSTed.
What would be the best way to have access to the POSTed control values in my controller method?
I would prefer a non jQuery solution, but I am not sure if the MVC framework can provide these values to me? Can it provide a list of key/value pairs to the controller somehow?
You could use the FormCollection in ASP.NET MVC.
public ActionResult SomeAction(FormCollection form) {
...
}
You have essentially two options.
1) Use the old fashioned Request variables as all we have done in ASP.NET web forms.
For example in your controller action method you can retrieve any value present on the form with the following method
public ActionResult SomeAction() {
var request = this.ControllerContext.HttpContext.Request;
bool boolParam = bool.Parse( request["boolParam"] ?? "false" );
}
2) Create a custom Model Binder to let the framework pack those values in a custom class object.
This method would be a little bit more difficult at the beginning because you have to create a custom Model Binder but it favour readability on your controller code. For further details on creating custom model binders give a look at the following links (you can find more with a simple search)
Custom Model Binder for Complex composite objects
Custom Model Binder and More UI Validation in ASP.NET MVC
A Custom ASP.NET MVC Model Binder for Repositories
Hope it helps
Is the content of the HTML files dynamic or known at design time? If you know it now, you could have each one post to it's own action and then strongly type the parameters.

ASP.NET MVC - GET with one ViewModel, POST with another

I'm kind of a noob so please forgive me if this is a dumb question.
I am loading a page successfully using Model Binding in ASP.NET MVC 2. Now I want to use Model Binding to submit the results of a form, but I want to use a different Model that the one I loaded with. Is this possible? Or should I just use the same ViewModel for both purposes?
Yes it's definitely possible.
The only thing to remember is the name attributes on your form inputs must be the same as the properties in the viewmodel.
Currently I have a hand crafted form (no strongly typed helpers) which once posted binds to a view model.
Yes, that is possible. Your details controller action and create controller action are different methods so you can make them accept whatever types you want.
//
// GET /Test/12
public ActionResult Details(int id)
{
return View(new ViewModel{/*properties init*/});
}
//
// POST: /Test/Update
[HttpPost]
public ActionResult Update(UpdateModel model)
{
//Do something with the model
return RedirectToAction("Index");
}

Can I return an edited object back to Controller from my strongly-typed View without having to use Request.Form?

Just wondering, I strongly type these views in ASP.NET MVC and then use Request.Form on the submit controller to get the data out, validate it, put it in an object, send to database. Is there a way I can just send the object back from the View page since it is strongly typed instead of doing all this crap to just end up with an object again since I just started with one anyways?
You mean, model binding?
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult UpdateUser (User user)
{
SaveUpdates ();
return View();
}
This will automatically initialize the User properties with the form values with the same names.
Look at this answer: ASP.Net MVC Custom Model Binding explanation
(source: odetocode.com)

Resources