简体   繁体   中英

Implementing Checkbox Product Filters ASP.NET MVC - How Can I Pass Data in Collection through URL?

I am trying to find a good way to implement product filtering in my ASP.NET MVC application.

在此处输入图像描述

When a user selects a checkbox value, I want to send a key/value pair (or some other type of collection) to my controller where I can then lookup products in my DB that have the filter (like screen size) and value (say 50") and return that list.

Can someone please recommend a good approach for this? I would like to do this by passing URL parameters so our marketing folks can link to pre-filtered product listing pages.

I've been researching how to pass an object or collection through the URL but haven't had luck implementing it.

Here is a small example of what I'm trying to accomplish:

  1. User selects "Screen Size - 50"
  2. Pass key "size" and value "50" to MVC controller

     public ActionResult subcategory(string brand, string cat, string cat2, Dictionary<string, string> filters)
  3. Return list of products that have screen size of 50", and have checkbox for "Screen Size - 50" checked in View.

  4. Allow user to select multiple filters

Note that new products and associated filters (and their categories) will be added in the future. Ideally, the query string will consist of name/value pairs consisting of the category ID and the selected ID, for example

products/brand/NEC/Pro-Displays/LCD-Monitors?234=43&343=21

where 234 is the ID for the 'Screen Size' category and 43 is the ID for the '50"' monitor, and 343 is for the 'Brightness' category and 21 is the ID '450 Nit'

For reference, here is how I am rendering the checkbox filters in my View:

@for (int x = 0; x < Model.Count(); x++)
{

    <div class="filter-cat" data-target="#list-@x">@Model.ElementAt(x).getName() <i class="fa fa-angle-down"></i></div>
    <ul id="list-@x">
        @for (int y = 0; y < Model.ElementAt(x).getFilterList().Count; y++)
        {
            <li>
                <input type="checkbox" id="@Model.ElementAt(x).getFilterList().ElementAt(y).getDescription()" name="@Model.ElementAt(x).getFilterList().ElementAt(y).getDescription()" />
                <label for="@Model.ElementAt(x).getFilterList().ElementAt(y).getDescription()">@Model.ElementAt(x).getFilterList().ElementAt(y).getDescription()</label>
            </li>
        }
    </ul>
}

In order to bind back to your Dictionary<string, string> filters parameter, you will need to generate inputs in the format

<input type="checkbox" name="filters[xxx]" value="yyy" />

where xxx is the ID of the filter category, and yyy is the ID of the selected filter.

Note that since your submitting only the ID values (typeof int ), then your parameter can be Dictionary<string, int> filters (the Key still needs to be string ).

But since you have checkboxes meaning that a user can make multiple selections in a category (and dictionary keys must be unique), you will need a (say) suffix in the name attribute to make them unique.

The code in your view is ugly and difficult to read, debug and unit test, so I recommend you start with a view model(s) to represent what you want to display in the view

public class ProductFilterVM
{
    public string Name { get; set; }
    ... // other properties relating to a product that you may want to display the view - e.g. Description
    public IEnumerable<FilterCategoryVM> FilterCategories { get; set; }
}
public class FilterCategoryVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<FilterSelectionVM> Selections { get; set; }
}
public class FilterSelectionVM
{
    public int ID { get; set; }
    public string Name { get; set; }
}

and in your GET method, initialize an instance of ProductVM and populate it based on the product being displayed, and return that to the view. The view then becomes

@model ProductFilterVM
....
<h2>@Model.Name</h2>
...
<h3>Filters</h3>
@using (Html.BeginForm("subcategory", "yourControllerName", FormMethod.Get))
{
    foreach(var category in Model.FilterCategories)
    {
        int counter = 1; // used to generate unique keys
        <h4>@category.Name</h4>
        foreach (var selection in category.Selections)
        {
            string name = String.Format("filters[{0}-{1}]", category.ID, counter++);
            <label>
                <input type="checkbox" name="@name" value="@selection.ID" />
                <span>@selection.Name</span>
            </label>
        }
    }
    <input type="submit" />
}

When you submit, the checked checkboxes will be bound to your filters parameter, and you will need to parse the Key back to an int after removing the suffix

public ActionResult subcategory(string brand, ..., Dictionary<string, string> filters)
{
    foreach(KeyValuePair<string, int> item in filters)
    {
        int category = Convert.ToInt32(item.Key.Split('-')[0]);
        int filter = item.Value;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM