How to do data sorting and filtering at the same time?

I have a code like this

public async Task<IActionResult> Index(string[] searchString, string sortOrder)
    {
        
        ViewBag.CurrentFilter = searchString;
        ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
        ViewBag.PriceSortParm = sortOrder == "Price" ? "Price desc" : "Price";

        var cosmetics = from s in db.Cosmetics
                       select s;
        //Sorting logic
        switch (sortOrder)
        {
            case "Name desc":
                cosmetics = cosmetics.OrderByDescending(s => s.Name);
                break;
            case "Price":
                cosmetics = cosmetics.OrderBy(s => s.Price);
                break;
            case "Price desc":
                cosmetics = cosmetics.OrderByDescending(s => s.Price);
                break;
            default:
                cosmetics = cosmetics.OrderBy(s => s.Name);
                break;
        }
        //Filter data logic
        if (searchString.Length != 0)
        {
            var li = new List<Cosmetic>();

            foreach (string ss in searchString)
            {
                List<Cosmetic> ll = cosmetics.Where(c => c.Name.Contains(ss)).ToList();
               
                li.AddRange(ll);

            }
            return View(li);
        }

        return View(await cosmetics.ToListAsync());
    }

I want data filtering and sorting to work together. I tried to connect them, but the result was such that all products were displayed regardless of what I passed to “string [] searchString”

Update

Filter data:

<form asp-action="Index" method="get">
<input class="form-control col-md-8 d-inline-block align-middle" type="checkbox" name="searchString" placeholder="Find" value="A" />
<input class="form-control col-md-8 d-inline-block align-middle" type="checkbox" name="searchString" placeholder="Find" value="B" />
<input class="btn btn-info" type="submit" value="Search" />
</form>

Sorting:

<a class="m-1" asp-action="Index" asp-route-sortOrder="@ViewBag.NameSortParm" asp-route-searchString="@ViewBag.CurrentFilter">Name</a>

<a class="m-1" asp-action="Index" asp-route-sortOrder="@ViewBag.PriceSortParm" asp-route-searchString="@ViewBag.CurrentFilter">Price</a>

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The searchString is a string array, which can not be regonized in asp-route-searchString. I suggest you could receive the two searchString separately.

Filter:

<form id="my_form" asp-action="Index" method="get">
    <input class="form-control col-md-8 d-inline-block align-middle" type="checkbox" name="searchString1" placeholder="Find" value="A" />
    <input class="form-control col-md-8 d-inline-block align-middle" type="checkbox" name="searchString2" placeholder="Find" value="B" />
    <input class="btn btn-info" type="submit" value="Search" />
</form>

Sorting:

<a class="m-1" asp-action="Index" asp-route-sortOrder="@ViewBag.NameSortParm" asp-route-searchString1="@ViewBag.CurrentFilter1" asp-route-searchString2="@ViewBag.CurrentFilter2">Name</a>

<a class="m-1" asp-action="Index" asp-route-sortOrder="@ViewBag.PriceSortParm" asp-route-searchString1="@ViewBag.CurrentFilter1" asp-route-searchString2="@ViewBag.CurrentFilter2">Price</a>

Controller:

public IActionResult Index(string searchString1, string searchString2, string sortOrder)
{
    ViewBag.CurrentFilter1 = searchString1;
    ViewBag.CurrentFilter2 = searchString2;
    ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
    ViewBag.PriceSortParm = sortOrder == "Price" ? "Price desc" : "Price";

    //filter and sort 

}

Update:

If you have different filter conditions, I think javasript can meet it. You could get the filter and sort condition in js then append them as querstring to url manually.

I have made an example based on this, you can refer to below codes:

Model:

public class Car
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
    public string Manufacturer { get; set; }
    public string Price { get; set; }
}

View:

@model IEnumerable<Car>

@{
    ViewData["Title"] = "Home Page";
}


<form id="my_form" asp-action="Index" method="get">
    <label>Color:</label>
    <input type="checkbox" name="color" value="black" /><span>Black</span>
    <input type="checkbox" name="color" value="white" /><span>White</span>
    <br />
    <label>Manufacturer:</label>
    <input type="checkbox" name="manufacturer" value="A" /><span>A</span>
    <input type="checkbox" name="manufacturer" value="B" /><span>B</span>
    <input type="checkbox" name="manufacturer" value="C" /><span>C</span>
    <input type="checkbox" name="manufacturer" value="D" /><span>D</span>

    <input class="btn btn-info float-right" type="submit" value="Search" />
</form>

<table class="table">
    <thead>
        <tr>
            <th>
                <a class="sort" id="sortname" data-sortorder="@ViewBag.NameSortParm" href="javascript:void(0)" >@Html.DisplayNameFor(model => model.Name)</a>
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Color)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Manufacturer)
            </th>
            <th>
                <a class="sort" id="sortprice" data-sortorder="@ViewBag.PriceSortParm" href="javascript:void(0)" >@Html.DisplayNameFor(model => model.Price)</a>
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Color)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Manufacturer)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Price)
                </td>
            </tr>
        }
    </tbody>
</table>

@section scripts{ 
    <script>
        var color = @Html.Raw(Json.Serialize(ViewBag.color));
        var manufacturer = @Html.Raw(Json.Serialize(ViewBag.manufacturer));

        $(function () {
            var checkoptions = [];
            checkoptions = color.concat(manufacturer);
            $('input[type=checkbox]').each(function () {
                if (checkoptions.includes(this.value)) {
                    $(this).prop("checked", true);
                }
            });
        })

        $(".sort").click(function () {
            var sortorder = $(this).data('sortorder');
            var link = "/Home/Index?";
            color.forEach(function (value) {
                link += "color=" + value + "&";
            });
            manufacturer.forEach(function (value) {
                link += "manufacturer=" + value + "&";
            });
            link += "sortOrder=" + sortorder;
            window.location.href = link;
        })
    </script>
}

Controller:

public IActionResult Index(string[] color, string[] manufacturer, string sortOrder)
{
    ViewBag.color = color;
    ViewBag.manufacturer = manufacturer;
    ViewBag.NameSortParm = string.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
    ViewBag.PriceSortParm = sortOrder == "Price" ? "Price_desc" : "Price";

    var cars = _context.Car.ToList();
    var co_cars = new List<Car>();
    var ma_cars = new List<Car>();

    if (color.Length != 0)
    {
        foreach (string co in color)
        {
            var colorfiltercars = _context.Car.Where(c => c.Color.Contains(co)).ToList();
            co_cars.AddRange(colorfiltercars);
        }
    }
    else
    {
        co_cars = cars;
    }

    if (manufacturer.Length != 0)
    {
        foreach (string ma in manufacturer)
        {
            var manufacturerfiltercars = _context.Car.Where(c => c.Manufacturer.Contains(ma)).ToList();
            ma_cars.AddRange(manufacturerfiltercars);
        }
    }
    else
    {
        ma_cars = cars;
    }

    var filtercars = co_cars.Intersect(ma_cars);

    switch (sortOrder)
    {
        case "Name_desc":
            filtercars = filtercars.OrderByDescending(s => s.Name);
            break;
        case "Price":
            filtercars = filtercars.OrderBy(s => int.Parse(s.Price));
            break;
        case "Price_desc":
            filtercars = filtercars.OrderByDescending(s => int.Parse(s.Price));
            break;
        default:
            filtercars = filtercars.OrderBy(s => s.Name);
            break;
    }
       
    return View(filtercars.ToList());
}

And the Datasource:

How to do data sorting and filtering at the same time?

Result:

How to do data sorting and filtering at the same time?

Method 2

Try to debug it by checking if searchString is passed to your controller. Also, check the updated code to make it easier to read.

public async Task<IActionResult> Index(string[] searchString, string sortOrder)
    {
        
        ViewBag.CurrentFilter = searchString;
        ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
        ViewBag.PriceSortParm = sortOrder == "Price" ? "Price desc" : "Price";

        var cosmetics = from s in db.Cosmetics
                        select s;
     
        //Filter data logic
        if (searchString.Length != 0)
        {
          cosmetics = cometics.Where(c => searchString.Any(s => s.Contains(c.Name)));    
        }
 
        //Sorting logic
        switch (sortOrder)
        {
            case "Name desc":
                cosmetics = cosmetics.OrderByDescending(s => s.Name);
                break;
            case "Price":
                cosmetics = cosmetics.OrderBy(s => s.Price);
                break;
            case "Price desc":
                cosmetics = cosmetics.OrderByDescending(s => s.Price);
                break;
            default:
                cosmetics = cosmetics.OrderBy(s => s.Name);
                break;
        }

      return View(await cosmetics.ToListAsync());
    }


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x