Reputation: 493
I am new to ASP.NET Core MVC, and I want to see if it ok to implement sorting and to filter this way. I have seen Microsoft tutorials about it, but I could not implement it like them. The context will be changed later with View Model.
Index view:
@model ProductListVM
@{
}
<h2>All Products</h2>
<hr />
<form class="row form-inline" onsubmit="onSubmit()" asp-action="Index" method="get" id="productsForm">
<div class="col-sm-2">
<select class="form-select" asp-for="CategoryId" onchange="filterAndSortProducts()" asp-items="ViewBag.Categories" style="width: 100%;">
<option>Select Category</option>
</select>
</div>
<div class="col-sm-2">
<select asp-for="SortParam" onchange="filterAndSortProducts()" class="form-select" style="width: 100%;" asp-items="ViewBag.SortItems">
<option value="">Sort By</option>
</select>
</div>
<div class="col-sm-3">
<div class="input-group">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="SearchString" value="@ViewData["CurrentFilter"]" />
<button class="btn btn-outline-primary my-2 my-sm-0" type="submit" onsubmit="onsubmit()">Search</button>
</div>
</div>
</form>
<hr />
<div class="row">
@foreach(var item in Model.Products) {
<div class="col-md-3 col-sm-6">
<div class="product-grid">
<div class="product-image">
<a href="#" class="image">
<img class="pic-1" src="~/images/@item.ImagePath">
</a>
@if(item.IsOnSale) {
<span class="product-sale-label">Sale!</span>
}
<ul class="product-links">
<li><a href="#"><i class="fa fa-shopping-bag"></i> Add to cart</a></li>
<li><a href="#"><i class="fa fa-search"></i>Quick View</a>
</li>
</ul>
</div>
<div class="product-content">
<h3 class="title"><a href="#">@item.Name</a></h3>
<div class="price">@if (item.IsOnSale)
{
<span>[email protected]</span>
} [email protected]</div>
</div>
</div>
</div>
}
</div>
<script>
function filterAndSortProducts(e) {
var form = document.getElementById("productsForm");
form.submit();
}
function onSubmit(e) {
e.preventDefault();
}
</script>
View Model:
namespace ECommerce.Common.Models
{
public class ProductListVM
{
public string? SortParam { get; set; }
public int CategoryId { get; set; }
public List<ProductVM>? Products { get; set; }
}
}
Controller, Index action:
public async Task<IActionResult> Index(string searchString, ProductListVM model)
{
var sortParam = model.SortParam;
var categoryFilterId = model.CategoryId;
ViewData["CurrentFilter"] = searchString;
var products = new List<Product>();
if (!string.IsNullOrEmpty(searchString))
{
products = await productRepository.GetAllWithSearchStringAsync(searchString);
}
else
{
products = await productRepository.GetAllAsync();
};
switch (sortParam)
{
case "price_desc":
products = products.OrderByDescending(s => s.Price).ToList();
break;
case "price_asc":
products = products.OrderBy(s => s.Price).ToList();
break;
case "date_desc":
products = products.OrderByDescending(s => s.DateCreated).ToList();
break;
case "date_asc":
products = products.OrderBy(s => s.DateCreated).ToList();
break;
default:
products = products.OrderBy(s => s.DateCreated).ToList();
break;
}
if(categoryFilterId != 0)
products = products.Where(q => q.ProductCategoryId == categoryFilterId).ToList();
ViewBag.SortItems = new List<SelectListItem>()
{
new SelectListItem() { Text = "Price: Highest to Lowest", Value = "price_desc"},
new SelectListItem() { Text = "Price: Lowest to Highest", Value = "price_asc"},
new SelectListItem() { Text = "Date: Newest to Oldest", Value = "date_desc"},
new SelectListItem() { Text = "Date: Oldest to Newest", Value = "date_asc"},
};
ViewBag.Categories = new SelectList(context.Categories, "Id", "Name");
model = new ProductListVM
{
Products = mapper.Map<List<ProductVM>>(products)
};
return View(model);
}
Dates also will be changed, it is just an example at the moment. Any suggestion, critique, or tip is helpful. I am in learning progress.
Upvotes: 0
Views: 1634
Reputation: 11
I think your using EF and the productRepository is a DBContext. This gives you back a IEnumerable which is only evaluatet if you use the Data. My Tipp for you to call .ToList() just in the End. It makes a big difference in performance.
List<Product> products = productRepository.Products;
if (!string.IsNullOrEmpty(searchString))
{
products = await products.WhereAsync(p = p.Where(s => s.Name.Contains(searchString)));
}
if (categoryFilterId != 0)
{
products = products.Where(q => q.ProductCategoryId == categoryFilterId);
}
switch (model.SortParam)
{
case SortOrder.price_desc:
products = products.OrderByDescending(s => s.Price);
break;
case SortOrder.price_asc:
products = products.OrderBy(s => s.Price);
break;
case SortOrder.date_desc:
products = products.OrderByDescending(s => s.DateCreated);
break;
default:
products = products.OrderBy(s => s.DateCreated);
break;
}
I would also use a Enum for you SortParam.
public enum SortOrder
{
price_desc,
price_asc,
date_desc,
date_asc
}
Hope that helps
Upvotes: 1