4

My project has several models, some with 1:many relationships with other models. A user has a profile page, this is split up into several partial views - each grouping/representing specific attributes of the given model.

If for example, I want to display 5 of the 10 properties of a given model in a partial view, and want to persist the properties that aren't shown to the user I'm using Html.HiddenFor like so

@Html.HiddenFor(x => x.IsInGroup)

This works for single entry properties as above. Of the 5 hidden member attributes, one of these may be a list. I understand that a list cannot be persisted using HiddenFor. I've come across the Mvc Futures package and the Html.Serialize helper extension, but I'm not totally sure how to use it and havn't been able to find much good information on it.

  • Once a model is passed to a view everything associated with it (properties, collections) is available for us to access e.g. Model.Username. If for example we don't use HiddenFor with Username, does that mean it will be reset to a default value, or null? Is this the same for collections?
  • Is using HiddenFor the only/best way to persist a model's properties that are not shown to the user?
  • Is using Html.Serialize the only way persist a model's collection that is not shown to the user? Other options?
  • Could someone provide/link to a simple example of how to persist a collection in a situation similar to what I've described?
  • If I was to use Html.Serialize, does the whole model need to be serialised or can I just serialise the collection?

Feedback appreciated.

MattSull
  • 5,354
  • 5
  • 43
  • 66

1 Answers1

2

You don't need to "persist" any data from your model by creating all the fields (hidden or not) from the model. In controller, when updating the record in the database you will just update what you need, the rest will not be affected.

Let's say this is your Product model

class Product { 
    public int ID {get; set;}
    public string Name {get; set;} 
    public string Description {get; set;}
    public decimal Price {get; set;}
    public virtual ICollection<Category> Categories { get; set; }
}

If you only want to edit Name and Description in your view, then you can only put those fields, and skip the rest (the ID would be in a hidden field). When the form is submitted, in your controller you would reference the Product record by the ID that got passed in and then you can update Name and Description to what you received from the form. Categories and the price will not be affected.

Somewhat more straight forward way to do this is to use a ViewModel specific to the view without non-editable properties. I found this post that gives more details how to do this:

Successful Model Editing without a bunch of hidden fields

On a smaller project you don't have use any kind of library (AutoMapper, InjectValues, ...), but you can do it yourself in places where you need to copy the values from a ViewModel into an actual record from DB.

Community
  • 1
  • 1
Floremin
  • 3,838
  • 12
  • 19
  • What does Html.HiddenFor for actually do? According to the following link it is used for persisting model data in a view - http://stackoverflow.com/questions/3866716/what-does-html-hiddenfor-do – MattSull Mar 11 '13 at 19:45
  • I wouldn't call it "persisting data", because the data is persisted in the database/storage, and you control what gets updated from the controller. It's not like the data will be deleted from the database once you "send" it to the view, in which case you'd need to persist it in the view so it doesn't get lost ;) Html.HiddenFor simply renders a hidden field, which you can use for (control) values you need submitted back to the controller, like an ID of original record that you want to update. – Floremin Mar 11 '13 at 19:56
  • Okay, thanks for clearing that up. I was lead into thinking I needed to do more than I actually did. – MattSull Mar 11 '13 at 20:39
  • I've unselected your answer as correct. When I comment out Html.HiddenFor helpers in my view, the model state is not valid. As I uncomment each helper, one by one, the model state error for each uncommented helper is resolved, but the model state error goes to the next helper that is commented out. Maybe I'm still a bit confused - are you saying (as in your answer) that I need to retrieve modified model in my controller and update the modified properties in there? Is it not easier to use Html.HiddenFor - because in my controller I'd have to set all properties to those retrieved from the view? – MattSull Mar 13 '13 at 12:29
  • If those properties, stored in hidden fields, are not nullable types, then you'd get invalid model state. Because, controller didn't get the values submitted from the form, they are null. If you want to use simple updates like that, then hidden fields are the ways to go. But if you want to actually prevent users from changing any of the hidden values, then you need to retrieve the original record and update only certain/allowed values. In this case you might want to create a model specific to that view/action which is not mapped to the DB table. – Floremin Mar 13 '13 at 16:10
  • Did you look at why the model state is invalid? – Floremin Mar 13 '13 at 16:11
  • It was because the Required annotation was not being satisfied for the property, so I'm guessing using Html.HiddenFor 'sets' the property in the view again, allowing for the model's state to be valid. Is it better practice to do this in the view? Or in the model as you explained in your answer? I've also figured out how to use Html.Hidden in a view for a collection - I'll post the code shortly. – MattSull Mar 13 '13 at 16:23
  • You could try to just remove "Required" if the field is not required. However, I updated my original answer with a clarification which includes a link to a post with more details about creating/using a ViewModel. – Floremin Mar 13 '13 at 16:30