0

So I have this CSHTML:

@using (Html.BeginForm("DeleteProduct", "Shop", FormMethod.Post))
{
    @Html.Hidden("productId", product.ProductId);
    @Html.Hidden("productVariantId", product.ProductVariantId);
    @Html.Hidden("quantity", product.Quantity);
    <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
}

That calls this backend:

[HttpPost]
public ActionResult DeleteProduct(int productId, int? productVariantId, int quantity)
{
    //...product gets deleted, etc. Not important for this question

    //regenerate the view, same as when loading the 'Order' view initially
    OrderWrapperViewModel model = GenerateOrderWrapperModel();
    return View("Order", model);
}

loading Order view in controller looks like this:

[HttpGet]
public ActionResult Order()
{
    OrderWrapperViewModel model = GenerateOrderWrapperModel();
    return View(model);
}

When I first call delete, I delete a product with ID: 7 and a product variant ID: 8. All goes fine. But after the page is returned, product with ID 7 is not listed anymore, only product with ID 1. So the second time it should be product ID: 1 and product variant ID: 4.

When returning from DeleteProduct, the url is currently showing /Shop/DeleteProduct. When I debug through the razor code:

generate form

Seems correct, right?

Well, the html is different:

different html

Of course, clicking the button passes those incorrect parameters as well. I can assure you that this is the same button, there is only 1 product shown at that time.

I solved it by simply redirecting to Order view again, so I am more interested in why this happens. Reason is, because for others I am returning a error message (using ModelState). That of course doesn't work when I redirect.

It also happens in production environment.

CularBytes
  • 9,924
  • 8
  • 76
  • 101
  • The correct approach is to follow the PRG pattern so just do it. But for an explanation of the behavior, refer [TextBoxFor displaying initial value, not the value updated from code](http://stackoverflow.com/questions/26654862/textboxfor-displaying-initial-value-not-the-value-updated-from-code/26664111#26664111) –  Apr 17 '17 at 09:22

2 Answers2

2

this is expected behavior this happens when you try to change values of Model just like you did in DeleteProduct the reason it was getting the old values because when you return to the same view, values from ModelState are rendered first so if ModelState is empty it will populate values from Model so thats why we use

ModelState.Clear();

if you are changing the values in Model you have to clear values from ModelState first. You can place a breakpoint and check the value of key it will look like this

enter image description here

Usman
  • 4,615
  • 2
  • 17
  • 33
1

The usual way of performing such operations as DeleteProduct is to redirect to another action after the deletion is completed:

[HttpPost]
public ActionResult DeleteProduct(int productId, int? productVariantId, int quantity)
{
    //...product gets deleted, etc. Not important for this question

    return RedirectToAction("Order");
}

This way you get a fresh ModelState in your Order method so that it doesn't conflict with any Model parameters you're passing to the view, and the user sees a 'more correct' URL in their browser after the product is deleted (e.g. /Shop/Order instead of /Shop/DeleteProduct).

holdenmcgrohen
  • 1,031
  • 2
  • 9
  • 30