Why do my viewmodel properties end up null or zero? - asp.net-mvc

I'm working on my first MVC application, still figuring it all out.
I have a viewmodel which, at this point, is identical to my domain object. My controller builds the viewmodel and passes it to a view. The view only displays a some of the properties because I don't want primary and/or foreign keys displayed for the user yet, in the case of a primary key, I need to have the data in order to update / delete the database.
It appears that unless I use a viewmodel property in the view, it is set to default values (0 for numeric value types and null for reference types) when I pass the viewmodel back. Is this correct behavior?
I confirmed the viewmodel passed to the Edit view does contain all the properties (as I would expect).
The question - Once a view is rendered, what happens to the viewmodel? If my viewmodel contains properties that are not used in the view, do their values just disappear? For example, when I click the Edit actionlink to fire the Edit action on the controller, the viewmodel that gets passed to the action does not contain any properties unless they are visible on the screen. Why?
BTW, this is ASP.NET MVC 4 RC.

It appears that unless I use a viewmodel property in the view, it is
set to default values (0 for numeric value types and null for
reference types) when I pass the viewmodel back. Is this correct
behavior?
Yes, when you invoke a controller action you need to pass all the properties that you want to be bound in the request. So for example if you are using a html <form> to call the action you need to use input fields. You could use hidden fields but they must be present, otherwise nothing is sent to the controller action
The question - Once a view is rendered, what happens to the viewmodel?
It falls out of scope and is eligible for garbage collected.
If my viewmodel contains properties that are not used in the view, do their values just disappear?
Absolutely. But even if you use those properties inside the view they disappear. For example if you only display the values inside the view but do not use input fields to send them back to the server when the form is submitted they will be gone as well.
For example, when I click the Edit actionlink to fire the Edit action
on the controller, the viewmodel that gets passed to the action does
not contain any properties unless they are visible on the screen. Why?
Because the view model no longer exists. It's gone and garbage collected. That's how the HTTP protocol works. It's stateless. Nothing is persisted between the requests. You will have to include whatever properties you want to be populated in the request either as POST form values or as query string parameters if you are using action links or whatever.
If the user is not supposed to modify those values inside the view you could then simply pass an id to the controller action which will allow for this controller action to retrieve the model from wherever it is stored (a database or something) using this id.

If your properties are in any helper methods which generates the input HTML element inside a form, It will be available in your HTTPost action method when you submit the form. If you are simply displaying it in a div/span , it is not going to get you the property values. That is how MVC model binding works.
Expect the values in your HttpPOST action if you use these HTML helpers
#Html.TextBoxFor
#Html.DropDownFor
#Html.EditorFor
#Html.HiddenFor
Dont expect the values if you use these
#Html.DisplayFor

Related

Why are my dotnet 5.0 mvc form fields retaining their input values on post?

I have an dot net 5.0 mvc page which takes a model object (ClassFoo) which when constructed generates an instance of (classBar). ClassBar has various properties (FieldA, FieldB, FieldC) all are strings.
The Views content is all in a form and the form's input fields are all from ClassFoo.ClassBar's various properties. Initially, when the page is accessed, all form input values are empty. However when I put data into them and then submit the form, the form values are still there when the page loads. However I don't understand why this is because I'm explicitly creating a new model during the controller operation but I am not actually populating the Model.ClassBar with the content from the post before I return model to the View for generation.
What I would expect is that all of the form fields would be empty however that is not the case. I know if asp.net the form values are stored and restored automatically but I didn't think that happened in mvc.
After looking into ModelState recommended by Nick Albrech in the comments I reviewed the hint associated w/ the HtmlHelper.TextBoxFor() which states the following:
... Adds a "value" attribute to the element containing the first non-null value found in: the ActionContext.ModelState entry with full name, or the expression evaluated against ViewDataDictionary.Model. See [IHtmlHelper.NameFor] for more information about a "full name".
So effectively what's happening is similar to what I thought asp.net mvc wasn't doing in that it populates the ModelState from a get/post request with the name and values of the form being submitted. Then based on the use of these helper functions (and also asp-for attributes used in razor views views), it either provides values from the saved model state form values OR the model passed to the view. Note: this does not seem to work if you set the value of an input element = #Model.[someProperty]
The take away from this is that you do not necessarily need to update your model object with content from the previous form submit in order to have the page populate the form contents back to the screen. Allow asp.net mvc to do the manual tasks by making use of these razor helpers.
Shoutout to Nick for the assist on this one. A solid member of the stackOverflow community.

How to prevent view from passing its model to the partial view, but instead pass null?

In ASP.NET MVC and using Razor, I have a View (parent) calling another View (child) as partial. Both are strongly typed but they have a different Model type.
Normally, in these situations, we pass a Model explicitly from the parent View to the child View.
#Html.Partial("Child", Model)
We can also choose not to specify explicitly a Model to be passed and, in those cases, the parent View will attempt to pass its own Model to the child View. This works if the types match and it is desirable in most cases.
#Html.Partial("Child")
In my case, however, I really want the parent View not to try to pass anything to the child View. How would I do that?
I thought of attempting to pass null explicitly:
#Html.Partial("Child", null)
But this still passes the parent's Model to the child View, resulting in an error: The model item passed into the dictionary is of type 'A', but this dictionary requires a model item of type 'B'.
(As a side note, the child View is a Create View for its model, that's why I don't have an instance to pass to it.)
Try this:
#Html.Partial("Child", null, new ViewDataDictionary<ChildType>(childInstance/*this can be null*/))
I understand the reason you want to not pass the model is so that your inputs are emptied out?
If this is the case, you can rather pass a new Model to this partial:
#Html.Partial("Child", new Model())
Since the Model is new, it won't have any values populated.
You could have your create form not strongly typed... craft your inputs in order to once posted you will have a model binded in your controller action.
Now... for me it doesn't worth the work just for the conceptual subtlety of "Model not existing yet" (AKA not in database yet).
In my case I create dummy models just to set default values in certain fields (for instance: setting today date, default values in dropdownlists, etc.)

ASP MVC3 Pass additional params with "return View(model)"

I'm in serious need of passing url params with View class. Here's code:
if (!ModelState.IsValid)
{
return View(model);
}
This should not only return model based view, but also add specific param to URL (param won't change view details, but is needed as it's one of few automatically generated SessionKeys (one for each tab/window used to view app) and I know no other way to get to it, different than passing as param (it can't be generated everytime, 'cos params will change; it can't be global variable because it'll reset its value each refresh; it can't be static, because static is evul).
Oh this action is called with use of form and submit button, not actionLink or something like this.
EDIT1: I need params to stay in URL after refresh, or I need some other form of keeping data that persists through refresh/validation fail.
If I understand you correctly you have data that you need to use in generating Urls on your page? This just forms part of your ViewModel - or at least it should, since it's data that the View needs in order to render.
You can use ViewData to add any extra data that isn't part of your view model. Or, better still, add the data as members to it. Equally, if different views with different View Models require this data, add a ViewModel base class and derive from that so you can share that data.
use
RedirectToAction("actionName","controller",
new RouteValueDictionary(new {param1="value",param2="value2"});
or you can use hidden field to store the values in your page and then pass this down as and when you need them..

I have a ViewModel strongly bound to my View in my ASP.NET MVC app, now what about the controller

So like the title says, I created a view model in my asp.net mvc application so it would be strongly typed to my view. My view model is a combination of two of my model classes. Now when the user hits the save button on that view, it goes to a controller. How does it know what controller to go to? I built my controller 1 - 1 so to speak with my models and views so controller A knows about Model A and controller B knows about Model B. But if I have a view model that is AB how does it know on subit to go to A or B. Do I need a controller called AB Controller?
The controller and action invoked do not depend on the viewmodel object you used to bind the page during initial view rendering. The controller (and action) invoked is determined by the URL of the request sent. (One of the routes you have defined will be matched based on the URL string of the request or a 404 not found error will be returned.)
A submit button in an HTML form (usually a POST) will have an action attribute that determines its url target, an anchor tag will have an href, etc.
In your situation where you have a custom viewmodel object you can define an action to expect and to attempt to parse that specific type of object by specifying it as the parameter to your action:
public ActionResult SaveSystemSetting(SystemAdminVM item) {
An Action Method doesn't receive a model. It receives parameters.
Anyway I think I know where you come from: One of the parameters of your action has the type of the ViewModel used in the View. That is a common layout and makes a lot of sense. In lots of projects it is so widely used that after some time you start to think that an action actually receives a model.
Just remenber that the parameters of your action can by anything that can by filled by the ModelBinder. You could pass both Models as parameters, you could pass a ViewModel that agregates Model a and b or you could pass a ViewModel that has properties of a + b.
Agregation ist the most common approach.
Generally we overload our action methods in the controller so if you have an action called edit that renders the view with your viewmodel object, you will have an overloaded edit action method with the HttpPost specified for that method.
The data to this method will be passed as form value collection values or you can bind it to your viewmodel object if you like and process it further.

Where do form fields in ASP.Net MVC take their values from?

I understand that fields such as Html.TextBox() accept two values, the first one being the name and the second one being the value. And so does Html.TextArea(). But in a case where the form is submitted as AJAX and the div where the form is placed is replaced with a view from the server, the form fields insist on taking the previous values. An image is worth a thousand words:
image http://img132.imageshack.us/img132/4171/aspnetmvcbug.png
I've checked everything on the controller and the model and the image is from debugging the view itself. The model is empty but the fields generated from it take the value of the previous submission.
The postback data is held in the ModelState. The built in HtmlHelper methods will look for values stored in the model state based on the name of the form element when rendering their content.
Check the View.ModelState property. Forms can grab values from there in certain circumstances.
Do you have an entry ViewData["Body"]? MVC will also attempt to bind a control to a ViewData item based on the name.

Resources