Betsq9
Betsq9

Reputation: 145

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>

Upvotes: 0

Views: 950

Answers (2)

mj1313
mj1313

Reputation: 8459

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:

enter image description here

Result:

enter image description here

Upvotes: 1

Sunny
Sunny

Reputation: 4809

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());
    }

Upvotes: 0

Related Questions