Tom
Tom

Reputation: 984

MVC ViewModel with editable and readonly data best practice

I'm wondering what is the best practice for dealing with editable/read only field in the same viewModel. I'm facing this problem for a bigger ViewModel but let's assume I have a very simple ViewModel:

public class BaseListViewModel
{
    public int Id { get; set; }
    public bool IsCheckedForAction { get; set; }
    public string DisplayName { get; set; }
}

My PartialView:

@model Wims.Website.ViewModels.Shared.BaseModelListViewModel
@using Wims.Website.Classes.Helpers.ExtentionMethods
<div class="dataDetail">
        <div>
            <div class="float-left">
                @Html.CheckBoxFor(model => model.IsCheckedForAction)
            </div>

            <div class="float-left">
                @Html.LabelFor(model => model.IsCheckedForAction, Model.DisplayName)


                @Html.GenerateSecureDataControls(w => w.Id)
            </div>
        </div>
    </div>
<div style="clear: both"></div>

Obviously, when i Post my data, DisplayName will not be filled. Let's assume some validation fails, and I just return the data i recieved the DisplayName would be missing.

    [HttpPost]

public ActionResult Edit(BaseListViewModel stuff)
{
    if (ModelState.IsValid)
    {
        ...
        return View("Index");
    }
    return View(stuff);
}

I know there is several way to fix this:

1) add

  @Html.HiddenFor(model => model.DisplayName)

in the view, which is ok if it's just 1 field, but, what happens if i do have 10 display only field?

2) requery data if (!Model.isValid) in [HttpPost].

3) I guess I could cache it in TempData ?

What is the best way to go for this? Thanks!

Edit: I am trying to avoid having to requery the data if validation fails

Upvotes: 2

Views: 2830

Answers (2)

Monstieur
Monstieur

Reputation: 8102

The POST action should perform the same initialisation of the viewmodel as the GET action. You could move the initialisation code into a common private function in the controller. The reason for this is if validation fails because of some concurrent change to the same data, the validation errors would be displayed to the user along with the new data. You could use the PRG pattern as well if the views allow for it.

Upvotes: 0

GraemeMiller
GraemeMiller

Reputation: 12253

I'd use the PRG pattern. It is more DRY as you only build ViewModel in the GET action. If validation fails then redirect to GET and get the model state out of tempdata.

The attributes on from this article, http://www.jefclaes.be/2012/06/persisting-model-state-when-using-prg.html, or from MVC Contrib https://github.com/mvccontrib/MvcContrib/blob/master/src/MVCContrib/Filters/ModelStateToTempDataAttribute.cs, make it easy to pass the Modelstate between the POST and the GET

Upvotes: 3

Related Questions