DavidB
DavidB

Reputation: 2596

MVC Core - strange view rendering issue

I am using MVC to display a simple form in a view:

ViewModel:

public class CreateSaleViewModel
{
    public string OrderId { get; set; }

    public decimal TotalAmount { get; set; }

    public bool ShowInstoreConfirmDetails { get; set; }
}

Controller action:

[HttpGet]
public IActionResult CreateSale()
{
    return View(new CreateSaleViewModel());
}

View:

@model CreateSaleViewModel
<form asp-controller="Sales" asp-action="CreateSale" method="post">

  <input asp-for="OrderId" />
  <input asp-for="TotalAmount" />

  <button type="submit" name="CreateSale" id="CreateSale">
    button
  </button>

</form>

I then post to a new view, where the same details need to be entered. To do this I store the old values in hidden inputs and provide another form to re-enter the details.

ViewModel:

public class ConfirmDetailsViewModel
{
    public string OrderId { get; set; }

    public decimal TotalAmount { get; set; }

    public string ConfirmOrderId { get; set; }

    public decimal ConfirmTotalAmount { get; set; }
}

Controller:

[HttpPost("Confirmdetails")]
public IActionResult ConfirmDetails(CreateSaleViewModel model)
{
 var viewModel = new ConfirmDetailsViewModel
 {
    ConfirmOrderId = model.OrderId,
    ConfirmTotalAmount = model.TotalAmount,
    OrderId = string.Empty,
    TotalAmount = 0.0m
  };

  return View("ConfirmDetails", viewModel);
}

View:

@model ConfirmDetailsViewModel

<form asp-controller="Sales" asp-action="Summary" method="post">
  <input type="hidden" value="@Model.ConfirmOrderId" id="OrderIdConfirm" />

  <input type="hidden" value="@Model.ConfirmTotalAmount" id="TotalAmountConfirm" />

  <input type="hidden" value="@Model.OrderId" id="banana" />


  <input asp-for="OrderId" />

  <input asp-for="TotalAmount" />

  <button  type="submit" name="CreateSale" id="CreateSale">
    button
  </button>
</form>

My problem is on the confirmdetails view orderId and TotalAmount retain the values that were posted from the previous page.

I have debugged the controller and can see the ConfirmOrderId and ConfirmTotalAmount properties have the correct values, and also OrderId and TotalAmount are empty strign and 0 respectively.

Even stranger is that

<input type="hidden" value="@Model.OrderId" id="banana" />

Has the correct value of "".

Does anyone know what is causing this issue?

Upvotes: 1

Views: 136

Answers (1)

user1023602
user1023602

Reputation:

MVC stores the posted back values in ModelState.

These values are used by default in @Html helpers - as a convenience. This allows the values of hidden form fields to be preserved through postbacks, even if they don't have properties in the view-model.

Unfortunately what is usually a convenience turns into a headache, if you try to modify the model's properties within the action. Helpers take their values from ModelState, ignoring the updated view-model.

To solve this, call ModelState.Clear()

  • removes all the posted back values from ModelState
  • the helpers will now use the values from the view-model.

Controller:

    [HttpPost]
    public IActionResult ConfirmDetails(CreateSaleViewModel model)
    {
        var viewModel = new ConfirmDetailsViewModel
        {
            ConfirmOrderId = model.OrderId,
            ...
        };

        ModelState.Clear();        // force asp-helpers to use the updated model's values

        return View("ConfirmDetails", viewModel);
    }

Upvotes: 2

Related Questions