2

I need feature that is something similar to Laravel's old input helper but in MVC 5. https://laravel.com/docs/5.6/requests#old-input

If validation fails, I need to reload all my model data as it was in the previous request except those inputs where user entered something wrong.

The problem is that my form has many disabled inputs and fields that program is fetching within [HttpGet] method, and they're getting lost during submission. So I need to store them in session.

The code below seems to work but is there any more efficient and beautiful way to do so with a less amount of code within each controller?

[HttpGet]
[Route(@"TaskManagement/Edit/{guid}")]
public async Task<ActionResult> Edit(Guid guid)
{
    var model = new EditTaskViewModel(); 
    model.Guid = guid;

    await model.GetTaskFromRemoteService(new UserInfo(User));

    ControllerHelpers.DisplayAlerts(model, this);

    TempData["OldModel"] = model;

    return View(model);                
}


[HttpPost]
[ValidateAntiForgeryToken]
[Route(@"TaskManagement/Edit/{guid}")]
public async Task<ActionResult> Edit(EditTaskViewModel model, Guid guid, string submit)
{
    model.Guid = guid;

    if (ModelState.IsValid) {
        await model.UpdateTaskInRemoteService(new UserInfo(User), submit);
        ControllerHelpers.DisplayAlerts(model, this, "Task successfully updated");

        if (model.ErrorCode == null)
            return RedirectToAction("Edit", new { guid = model.Guid });

        return RedirectToAction("Index");
    }


    if (TempData["OldModel"] != null) {
        model = (EditTaskViewModel)TempData["OldModel"];
    }
    return View(model);

}
Liam Kernighan
  • 2,335
  • 1
  • 21
  • 24
  • Could you show us the view and EditTaskViewModel? – Win May 13 '18 at 13:05
  • @Win https://pastebin.com/YSLt4d9h . The ViewModel is simple, just a list of fields, some of them are required. (Not Author and Date for sure) GetTask and UpdateTask are reading and writing the fields from\to the remote service (or it can be any database, doesn't matter). – Liam Kernighan May 13 '18 at 13:19

2 Answers2

2

Using session state (including TempData) like this may break when you have multiple copies of the page open. You can work around this by generating a unique ID for the session key and storing it in a hidden field.

However, I would try to avoid using session altogether.

A simple approach is to use hidden fields to store the values that aren't sent to the server because they are in disabled fields.

A more robust approach is a separate class (or at least a private method) that knows how to setup your model for the first time and in transition (e.g. failed server validation). I call these classes "composers" and I describe the approach here.

Pseudocode for how an action method with a composer might look:

if( ModelState.IsValid ){
    return Redirect();
}

var rebuiltModel = _composer.ComposeEdit( incomingModel );
return View( rebuiltModel );
Tim M.
  • 53,671
  • 14
  • 120
  • 163
  • 1
    The easiest way seems to retrieve the object from the database once more) Hidden inputs do not work on complex data like tables and so on. – Liam Kernighan May 13 '18 at 19:39
  • @Восилей - Getting the data again from the database is often easiest. In my answer, the controller or the composer could go to the database again to rebuild the model. – Tim M. May 14 '18 at 00:13
0

I think the answer was quite simple. The shortest and easiest way is to populate the object from the database\remote service once more.

The fields that user entered whether they're valid or not will stay as they were before. The rest of them will load once again.

Liam Kernighan
  • 2,335
  • 1
  • 21
  • 24