If You want to do Sorting At Any Grid at Admin side....
You just have to Write This Two lines
Ordering = true,
ServerSide = false,
After LengthMenu Property And Before <Filter> Property
public partial record ProductSearchModel : BaseSearchModel
{
public ProductSearchModel()
{
........
AvailableProductTypes = new List<SelectListItem>();
AvailablePublishedOptions = new List<SelectListItem>();
//add
OrderByOptions = new List<SelectListItem>();
}
[NopResourceDisplayName("Admin.Catalog.Products.List.SearchProductName")]
public string SearchProductName { get; set; }
............................
[NopResourceDisplayName("Admin.Catalog.Products.List.GoDirectlyToSku")]
public string GoDirectlyToSku { get; set; }
//add
[NopResourceDisplayName("Admin.Catalog.Products.List.OrderBy")]
public int OrderBy { get; set; }
...................
public IList<SelectListItem> AvailableProductTypes { get; set; }
public IList<SelectListItem> AvailablePublishedOptions { get; set; }
//add
public IList<SelectListItem> OrderByOptions { get; set; }
}
Task PrepareProductOrdersAsync(IList<SelectListItem> items, bool withSpecialDefaultItem = true, string defaultItemText = null);
public virtual async Task PrepareProductOrdersAsync(IList<SelectListItem> items, bool withSpecialDefaultItem = true, string defaultItemText = null)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
//prepare available product orders
var availableProductOrderItems = await ProductSortingEnum.Position.ToSelectListAsync(false);
foreach (var productOrderItem in availableProductOrderItems)
{
items.Add(productOrderItem);
}
//insert special item for the default value
await PrepareDefaultItemAsync(items, withSpecialDefaultItem, defaultItemText);
}
public virtual async Task<ProductSearchModel> PrepareProductSearchModelAsync(ProductSearchModel searchModel)
{
if (searchModel == null)
throw new ArgumentNullException(nameof(searchModel));
......................
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//add
//prepare available product orders
await _baseAdminModelFactory.PrepareProductOrdersAsync(searchModel.OrderByOptions, false);
//prepare available warehouses
await _baseAdminModelFactory.PrepareWarehousesAsync(searchModel.AvailableWarehouses);
....................
return searchModel;
}
public virtual async Task<ProductListModel> PrepareProductListModelAsync(ProductSearchModel searchModel)
{
if (searchModel == null)
throw new ArgumentNullException(nameof(searchModel));
....................
if (searchModel.SearchIncludeSubCategories && searchModel.SearchCategoryId > 0)
{
var childCategoryIds = await _categoryService.GetChildCategoryIdsAsync(parentCategoryId: searchModel.SearchCategoryId, showHidden: true);
categoryIds.AddRange(childCategoryIds);
}
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: categoryIds,
manufacturerIds: new List<int> { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
warehouseId: searchModel.SearchWarehouseId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize,
orderBy: (ProductSortingEnum)searchModel.OrderBy,
overridePublished: overridePublished);
.........................
<div class="form-group row" @(Model.AvailableManufacturers.SelectionIsNotPossible() ? Html.Raw("style=\"display:none\"") : null)>
<div class="col-md-4">
<nop-label asp-for="SearchManufacturerId" />
</div>
<div class="col-md-8">
<nop-select asp-for="SearchManufacturerId" asp-items="Model.AvailableManufacturers" />
</div>
</div>
<div class="form-group row" @(Model.AvailableVendors.SelectionIsNotPossible() || Model.IsLoggedInAsVendor ? Html.Raw("style='display: none;'") : null)>
<div class="col-md-4">
<nop-label asp-for="SearchVendorId" />
</div>
<div class="col-md-8">
<nop-select asp-for="SearchVendorId" asp-items="Model.AvailableVendors" />
</div>
</div>
<div class="form-group row">
<div class="col-md-4">
<nop-label asp-for="OrderBy" />
</div>
<div class="col-md-8">
<nop-select asp-for="OrderBy" asp-items="Model.OrderByOptions" />
</div>
</div>
.......................................
<div class="card-body">
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.Products", Docs.Products + Utm.OnAdmin)" />
@await Html.PartialAsync("Table", new DataTablesModel
{
Name = "products-grid",
UrlRead = new DataUrl("ProductList", "Product", null),
SearchButtonId = "search-products",
Length = Model.PageSize,
LengthMenu = Model.AvailablePageSizes,
Filters = new List<FilterParameter>
{
new FilterParameter(nameof(Model.SearchProductName)),
new FilterParameter(nameof(Model.SearchCategoryId)),
new FilterParameter(nameof(Model.SearchIncludeSubCategories), typeof(bool)),
new FilterParameter(nameof(Model.SearchManufacturerId)),
new FilterParameter(nameof(Model.SearchStoreId)),
new FilterParameter(nameof(Model.SearchWarehouseId)),
new FilterParameter(nameof(Model.SearchVendorId)),
new FilterParameter(nameof(Model.SearchProductTypeId)),
new FilterParameter(nameof(Model.SearchPublishedId)),
new FilterParameter(nameof(Model.OrderBy))
},
....................................