Skip to content

#7515 allowing search feature by 'Name' on the product attribute page… #7524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ public partial interface IProductAttributeService
/// <summary>
/// Gets all product attributes
/// </summary>
/// <param name="searchModelName">search model name</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the product attributes
/// </returns>
Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(int pageIndex = 0, int pageSize = int.MaxValue);
Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(string searchModelName=null,int pageIndex = 0, int pageSize = int.MaxValue);

/// <summary>
/// Gets a product attribute
Expand Down
15 changes: 9 additions & 6 deletions src/Libraries/Nop.Services/Catalog/ProductAttributeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,28 @@ public virtual async Task DeleteProductAttributesAsync(IList<ProductAttribute> p
/// <summary>
/// Gets all product attributes
/// </summary>
/// <param name="searchModelName">search model name </param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the product attributes
/// </returns>
public virtual async Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(int pageIndex = 0,
public virtual async Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(string searchModelName = null,int pageIndex = 0,
int pageSize = int.MaxValue)
{
var productAttributes = await _productAttributeRepository.GetAllPagedAsync(query =>
Func<IQueryable<ProductAttribute>, IQueryable<ProductAttribute>> func = query => searchModelName switch
{
return from pa in query
orderby pa.Name
select pa;
}, pageIndex, pageSize);
null => query.OrderBy(pa => pa.Name),
_ => query.Where(pa => pa.Name.Contains(searchModelName)).OrderBy(pa => pa.Name)
};
var productAttributes = await _productAttributeRepository.GetAllPagedAsync(func, pageIndex, pageSize);

return productAttributes;
}



/// <summary>
/// Gets a product attribute
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ public virtual async Task<ProductAttributeListModel> PrepareProductAttributeList

//get product attributes
var productAttributes = await _productAttributeService
.GetAllProductAttributesAsync(pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
.GetAllProductAttributesAsync(
searchModelName: searchModel.Name,
pageIndex: searchModel.Page - 1,
pageSize: searchModel.PageSize
);

//prepare list model
var model = new ProductAttributeListModel().PrepareToGrid(searchModel, productAttributes, () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nop.Web.Framework.Models;
using Nop.Web.Framework.Mvc.ModelBinding;

namespace Nop.Web.Areas.Admin.Models.Catalog;

Expand All @@ -7,4 +8,6 @@ namespace Nop.Web.Areas.Admin.Models.Catalog;
/// </summary>
public partial record ProductAttributeSearchModel : BaseSearchModel
{
[NopResourceDisplayName("Admin.Catalog.Attributes.ProductAttributes.Fields.Name")]
public string Name { get; set; }
}
193 changes: 120 additions & 73 deletions src/Presentation/Nop.Web/Areas/Admin/Views/ProductAttribute/List.cshtml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
@model ProductAttributeSearchModel

@{
//page title
ViewBag.PageTitle = T("Admin.Catalog.Attributes.ProductAttributes").Text;
//active menu item (system name)
NopHtml.SetActiveMenuItemSystemName("Product attributes");
//page title
ViewBag.PageTitle = T("Admin.Catalog.Attributes.ProductAttributes").Text;
//active menu item (system name)
NopHtml.SetActiveMenuItemSystemName("Product attributes");
}

@{
const string hideSearchBlockAttributeName = "ProductAttributesListPage.HideSearchBlock";
var hideSearchBlock = await genericAttributeService.GetAttributeAsync<bool>(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName);
}

<div class="content-header clearfix">
<h1 class="float-left">
Expand All @@ -28,75 +32,118 @@

<section class="content">
<div class="container-fluid">
<div class="cards-group">
<div class="card card-default">
<div class="card-body">
<p>
@T("Admin.Catalog.Attributes.ProductAttributes.Description")
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.ProductAttributes", Docs.ProductAttributes + Utm.OnAdmin)" asp-add-wrapper="false"/>
</p>
@await Html.PartialAsync("Table", new DataTablesModel
{
Name = "products-grid",
UrlRead = new DataUrl("List", "ProductAttribute", null),
Length = Model.PageSize,
LengthMenu = Model.AvailablePageSizes,
ColumnCollection = new List<ColumnProperty>
{
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
IsMasterCheckBox = true,
Render = new RenderCheckBox("checkbox_productattributes"),
ClassName = NopColumnClassDefaults.CenterAll,
Width = "50"
},
new ColumnProperty(nameof(ProductAttributeModel.Name))
{
Title = T("Admin.Catalog.Attributes.ProductAttributes.Fields.Name").Text
},
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
Title = T("Admin.Common.Edit").Text,
Width = "100",
ClassName = NopColumnClassDefaults.Button,
Render = new RenderButtonEdit(new DataUrl("~/Admin/ProductAttribute/Edit"))
}
}
})
<div class="form-horizontal">
<div class="cards-group">
<!-- here to put search box -->
<div class="card card-default card-search">
<div class="card-body">
<div class="row search-row @(!hideSearchBlock ? "opened" : "")" data-hideAttribute="@hideSearchBlockAttributeName">
<div class="search-text">@T("Admin.Common.Search")</div>
<div class="icon-search"><i class="fas fa-magnifying-glass" aria-hidden="true"></i></div>
<div class="icon-collapse"><i class="far fa-angle-@(!hideSearchBlock ? "up" : "down")" aria-hidden="true"></i></div>
</div>

<script>
$(function() {
$('#delete-selected-action-confirmation-submit-button').bind('click', function () {
var postData = {
selectedIds: selectedIds
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@(Url.Action("DeleteSelected", "ProductAttribute"))",
data: postData,
error: function (jqXHR, textStatus, errorThrown) {
showAlert('deleteSelectedFailed', errorThrown);
},
complete: function (jqXHR, textStatus) {
if (jqXHR.status === 204)
{
showAlert('nothingSelectedAlert', '@T("Admin.Common.Alert.NothingSelected")');
return;
}
updateTable('#products-grid');
}
});
$('#delete-selected-action-confirmation').modal('toggle');
return false;
});
});
</script>
<nop-alert asp-alert-id="deleteSelectedFailed" />
<nop-alert asp-alert-id="nothingSelectedAlert" />
</div>
</div>
</div>
<div class="search-body @(hideSearchBlock ? "closed" : "")">
<div class="row">
<div class="col-md-5">
<div class="form-group row">
<div class="col-md-4">
<nop-label asp-for="Name" />
</div>
<div class="col-md-8">
<nop-editor asp-for="Name" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="text-center col-12">
<button type="button" id="search-productAttributes" class="btn btn-primary btn-search">
<i class="fas fa-magnifying-glass"></i>
@T("Admin.Common.Search")
</button>
</div>
</div>
</div>
</div>
</div>

<!--end of search box -->
<div class="card card-default">
<div class="card-body">
<p>
@T("Admin.Catalog.Attributes.ProductAttributes.Description")
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.ProductAttributes", Docs.ProductAttributes + Utm.OnAdmin)" asp-add-wrapper="false" />
</p>
@await Html.PartialAsync("Table", new DataTablesModel
{
Name = "products-grid",
UrlRead = new DataUrl("List", "ProductAttribute", null),
SearchButtonId = "search-productAttributes",
Length = Model.PageSize,
LengthMenu = Model.AvailablePageSizes,
Filters = new List<FilterParameter>
{
new FilterParameter(nameof(Model.Name)),
},
ColumnCollection = new List<ColumnProperty>
{
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
IsMasterCheckBox = true,
Render = new RenderCheckBox("checkbox_productattributes"),
ClassName = NopColumnClassDefaults.CenterAll,
Width = "50"
},
new ColumnProperty(nameof(ProductAttributeModel.Name))
{
Title = T("Admin.Catalog.Attributes.ProductAttributes.Fields.Name").Text
},
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
Title = T("Admin.Common.Edit").Text,
Width = "100",
ClassName = NopColumnClassDefaults.Button,
Render = new RenderButtonEdit(new DataUrl("~/Admin/ProductAttribute/Edit"))
}
}
})

<script>
$(function() {
$('#delete-selected-action-confirmation-submit-button').bind('click', function () {
var postData = {
selectedIds: selectedIds
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@(Url.Action("DeleteSelected", "ProductAttribute"))",
data: postData,
error: function (jqXHR, textStatus, errorThrown) {
showAlert('deleteSelectedFailed', errorThrown);
},
complete: function (jqXHR, textStatus) {
if (jqXHR.status === 204)
{
showAlert('nothingSelectedAlert', '@T("Admin.Common.Alert.NothingSelected")');
return;
}
updateTable('#products-grid');
}
});
$('#delete-selected-action-confirmation').modal('toggle');
return false;
});
});
</script>
<nop-alert asp-alert-id="deleteSelectedFailed" />
<nop-alert asp-alert-id="nothingSelectedAlert" />
</div>
</div>
</div>
</div>

</div>
</section>