2

BACKGROUND

I'm working in ASP.NET MVC 5. I have a list of products and want to filter them by name. I have a created a small form that sits above the product list.

CODE

Here is the Razor form

@using (Html.BeginForm("Page", "Inventory", routeValues: new { showDeleted = false }, method: FormMethod.Get))
{
  <div class="row">
    <div class="col-md-12">
      <div class="form-group">
        @Html.LabelFor(model => model.Search.SearchTerm, new { @class = "form-label" })
        <div class="controls">
          @Html.EditorFor(m => m.Search.SearchTerm, new { htmlAttributes = new { @class = "form-control" } })
          @Html.ValidationMessageFor(model => model.Search.SearchTerm, "", new { @class = "text-danger" })
        </div>
      </div>
    </div>
    <div class="col-md-12">
      <button type="submit" class="btn btn-primary pull-right filter">Filter Results</button>
    </div>
  </div>
}

And here is the controller method it is suppose to hit:

public ActionResult Page(SearchViewModel search, bool showDeleted, int page = 1)
{
  var viewModel = _productService.GetPagedProducts(search, showDeleted, page);
  return View(viewModel);
}

Submitting the filter with whatever search terms breaks the application and gives the following error:

The parameters dictionary contains a null entry for parameter 'showDeleted' of non-nullable type 'System.Boolean' for method 'System.Web.Mvc.ActionResult Page(Proj.ViewModels.Shared.SearchViewModel, Boolean, Int32)' in 'Proj.Controllers.InventoryController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

I know why it is failing, it is because the showDeleted I've set up is getting ignored and thrown away! But I do not know how to fix this.

halfer
  • 19,824
  • 17
  • 99
  • 186
J86
  • 14,345
  • 47
  • 130
  • 228
  • 1
    The answer is here https://stackoverflow.com/questions/891603/html-beginform-loses-routevalues-with-formmethod-get – lyz Nov 07 '17 at 14:12
  • I think hidden field can help you, @Html.Hidden("showDeleted", false) – Edward N Nov 07 '17 at 14:16
  • Thanks @lyz, I understand what to do now. :) – J86 Nov 07 '17 at 14:17
  • Create a specific route for that method - `url: "Inventory/Page/{showDeleted}` so that its added as a route value, not a query string and then you do not need a hidden input –  Nov 07 '17 at 21:00

1 Answers1

3

Your code will generate the correct form action url with the querystring for the showDeleted parameter

action="/Inventory/Page?showDeleted=False"

But since you are using GET as the form submit method, when the form is submitted, browser will read the input element values from the form and build a querystring and append it to the form action url. This will overwrite your existing querystrings you had there.

If you want to send this in querystring with GET as the form method, you should have an input element in the form with the same name

@using (Html.BeginForm("Page", "Inventory", FormMethod.Get))
{
    @Html.EditorFor(m => m.Search.SearchTerm, 
                          new { htmlAttributes = new { @class = "form-control" } })
    <input type="hidden" name="showDeleted" value="false" />
    <button type="submit" class="btn btn-primary filter">Filter Results</button>

}
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • Is that the only way? Why does my `routeValues` get ditched? – J86 Nov 07 '17 at 14:04
  • Because you are doing a form submit using GET which will overwrite the querystring items with the form input elements. – Shyju Nov 07 '17 at 14:23