如何在 primeng 自动完成中对建议嵌套列表进行分组 angular 8
How to group suggestions nested list in the primeng autocomplete angular 8
我正在尝试对自动完成建议进行分组,并希望在 primeng 中呈现它们。
我们如何在 primeng 中添加自定义模板?
我的数据
data = [{"id":"m1","name":"menu1","val":"D","items":[{"id":"d1","name":"datanested1","val":"D","items":[{"id":"1","name":"direct Data","val":"E"},{"id":"2","name":"test","val":"E"}]}]},{"id":"d2","name":"menu2","val":"D","items":[{"id":"21","name":"test21","val":"E"},{"id":"22","name":"test23","val":"E"}]},{"id":"d3","name":"menu3","val":"D","items":[{"id":"31","name":"test data 3","val":"E"},{"id":"32","name":"test data 4","val":"E"}]}]
angular8 中是否有任何其他库支持此功能?
当用户开始在自动完成中搜索时,我想实现这样的事情...
Menu1 - header
datanested1 -subheader
direct Data -values
test -values
Menu2 - header
test21-values
test23-values
Menu3 - header
test data 3-values
test data 4-values
1. if the user types "direct" in the input box...
Menu1 - header
datanested1 -subheader
direct Data -values
2. if the user types "data" in the input box...
Menu3 - header
test data 3-values
test data 4-values
3. if the user types "menu" in the input box...
Menu1 - header
datanested1 -subheader
direct Data -values
test -values
Menu2 - header
test21-values
test23-values
Menu3 - header
test data 3-values
test data 4-values
我在 stackblitz 中尝试了以下示例。
在您的 primeng 版本 (7.1.2) 中,不支持分组自动完成。但它在最新版本(11.3.0)中受支持。请看下图并关注https://www.primefaces.org/primeng/showcase/#/autocomplete
Patel , 是的,你可以在 Primeng
中添加 Group Header
.到
adminentrylistSearch = [
{
Grp_Header:'THIS IS Header 1' ,
cdsid: "0121",
firstname: "FirstName1",
lastname: "LastName1",
fullname: "LastName1, FirstName1"
},
{
cdsid: "0122",
firstname: "FirstName1",
lastname: "LastName2",
fullname: "LastName2, FirstName2"
},
{
cdsid: "0123",
firstname: "FirstName3",
lastname: "LastName3",
fullname: "LastName3, FirstName3"
},
{
Grp_Header:'THIS IS Header 2',
cdsid: "0124",
firstname: "FirstName4",
lastname: "LastName4",
fullname: "LastName4, FirstName4"
},
{
cdsid: "0125",
firstname: "FirstName5",
lastname: "LastName5",
fullname: "LastName5, FirstName5"
},
{
cdsid: "0126",
firstname: "FirstName6",
lastname: "LastName6",
fullname: "LastName6, FirstName6"
},
{
cdsid: "0127",
firstname: "FirstName7",
lastname: "LastName7",
fullname: "LastName7, FirstName7"
}
];
.html
<p-autoComplete [(ngModel)]="cdsidvalue" [suggestions]="filteredCountriesSingle" [dropdown]="true"
(completeMethod)="filterCountrySingle($event)" field="firstname" [size]="16" placeholder="CDSID">
<ng-template let-adminentrylistSearch [ngIf]="adminentrylistSearch.index" pTemplate="text">
<div class='unclickable-header'>
<span [style.font-weight]="adminentrylistSearch.Grp_Header ? 'bold' : null"> {{adminentrylistSearch.Grp_Header ? adminentrylistSearch.Grp_Header : adminentrylistSearch.firstname}} </span>
</div>
</ng-template>
</p-autoComplete>
在此处检查结果...
Demo
在下面的方法中,我们会将数组简化为一个简单的结构
[
{
"id": "m1",
"name": "menu1",
"val": "D",
"search": ["m1", "d1", "1", "2", "menu1", "datanested1", "direct Data", "test"],
"depth": 2
},
{
"id": "d1",
"name": "datanested1",
"val": "D",
"search": ["d1", "1", "2", "datanested1", "direct Data", "test"],
"depth": 1
},
{
"id": "1",
"name": "direct Data",
"val": "E",
"search": ["1", "direct Data"
],
"depth": 0
},
...
]
思路是这样的,我们将使用depth
格式化文本,而search
进行搜索。
maxDepth = 0;
reducedArray = (arr, depth = 0, parentSearch = []) => {
this.maxDepth = Math.max(this.maxDepth, depth);
if (!arr) {
return [];
}
return arr.reduce((prev, { items, ...otherProps }) => {
// const depth = this.findDepth({ items, ...otherProps });
const search = [
...this.getProps({ items, ...otherProps }, "id"),
...this.getProps({ items, ...otherProps }, "name")
];
const newParentSearch = [...parentSearch, otherProps.name, otherProps.id];
return [
...prev,
{ ...otherProps, search, depth, parentSearch },
...this.reducedArray(items, depth + 1, newParentSearch)
];
}, []);
};
getProps = (item, prop) => {
if (!item.items) {
return [item[prop]];
} else {
return [
item[prop],
...item.items.map(x => this.getProps(x, prop))
].flat();
}
};
我们可以应用如下样式
getStyle(depth) {
return {
color: depth === 0 ? "darkblue" : depth === 1 ? "green" : "black",
paddingLeft: depth * 7 + "px",
fontWeight: 800 - depth * 200
};
}
我将使用响应式编程,因此我会将对象转换为 Observable usinf of
运算符
data$ = of(this.reducedArray(this.data));
filteredData$ = combineLatest([this.data$, this.filterString$]).pipe(
map(([data, filterString]) =>
data.filter(
({ search, parentSearch }) =>
!![...search, ...parentSearch].find(x => x.includes(filterString))
)
)
);
大功告成,剩下的就是更新html
<p-autoComplete [(ngModel)]="cdsidvalue" [suggestions]="filteredData$ | async"
(completeMethod)="filterString$.next($event.query)" field="name" [size]="16" placeholder="Menu" [minLength]="1">
<ng-template let-menu pTemplate="item">
<span
[ngStyle]="getStyle(menu.depth)" >{{ menu.name }}</span>
</ng-template>
</p-autoComplete>
更新
由于我们使用的是响应式编程,因此重构以接受 http 请求非常容易,只需将 observable 替换为 http 请求即可
data$ = this.http.get<any[]>("my/api/url");
filteredData$ = combineLatest([this.data$, this.filterString$]).pipe(
map(([data, filterString]) =>
this.reducedArray(data).filter(
({ search, parentSearch }) =>
!![...search, ...parentSearch].find(x => x.includes(filterString))
)
)
);
我也更新了 html 以添加加载消息,我们不想显示没有数据的表单
我正在尝试对自动完成建议进行分组,并希望在 primeng 中呈现它们。
我们如何在 primeng 中添加自定义模板?
我的数据
data = [{"id":"m1","name":"menu1","val":"D","items":[{"id":"d1","name":"datanested1","val":"D","items":[{"id":"1","name":"direct Data","val":"E"},{"id":"2","name":"test","val":"E"}]}]},{"id":"d2","name":"menu2","val":"D","items":[{"id":"21","name":"test21","val":"E"},{"id":"22","name":"test23","val":"E"}]},{"id":"d3","name":"menu3","val":"D","items":[{"id":"31","name":"test data 3","val":"E"},{"id":"32","name":"test data 4","val":"E"}]}]
angular8 中是否有任何其他库支持此功能?
当用户开始在自动完成中搜索时,我想实现这样的事情...
Menu1 - header
datanested1 -subheader
direct Data -values
test -values
Menu2 - header
test21-values
test23-values
Menu3 - header
test data 3-values
test data 4-values
1. if the user types "direct" in the input box...
Menu1 - header
datanested1 -subheader
direct Data -values
2. if the user types "data" in the input box...
Menu3 - header
test data 3-values
test data 4-values
3. if the user types "menu" in the input box...
Menu1 - header
datanested1 -subheader
direct Data -values
test -values
Menu2 - header
test21-values
test23-values
Menu3 - header
test data 3-values
test data 4-values
我在 stackblitz 中尝试了以下示例。
在您的 primeng 版本 (7.1.2) 中,不支持分组自动完成。但它在最新版本(11.3.0)中受支持。请看下图并关注https://www.primefaces.org/primeng/showcase/#/autocomplete
Patel , 是的,你可以在 Primeng
中添加 Group Header.到
adminentrylistSearch = [
{
Grp_Header:'THIS IS Header 1' ,
cdsid: "0121",
firstname: "FirstName1",
lastname: "LastName1",
fullname: "LastName1, FirstName1"
},
{
cdsid: "0122",
firstname: "FirstName1",
lastname: "LastName2",
fullname: "LastName2, FirstName2"
},
{
cdsid: "0123",
firstname: "FirstName3",
lastname: "LastName3",
fullname: "LastName3, FirstName3"
},
{
Grp_Header:'THIS IS Header 2',
cdsid: "0124",
firstname: "FirstName4",
lastname: "LastName4",
fullname: "LastName4, FirstName4"
},
{
cdsid: "0125",
firstname: "FirstName5",
lastname: "LastName5",
fullname: "LastName5, FirstName5"
},
{
cdsid: "0126",
firstname: "FirstName6",
lastname: "LastName6",
fullname: "LastName6, FirstName6"
},
{
cdsid: "0127",
firstname: "FirstName7",
lastname: "LastName7",
fullname: "LastName7, FirstName7"
}
];
.html
<p-autoComplete [(ngModel)]="cdsidvalue" [suggestions]="filteredCountriesSingle" [dropdown]="true"
(completeMethod)="filterCountrySingle($event)" field="firstname" [size]="16" placeholder="CDSID">
<ng-template let-adminentrylistSearch [ngIf]="adminentrylistSearch.index" pTemplate="text">
<div class='unclickable-header'>
<span [style.font-weight]="adminentrylistSearch.Grp_Header ? 'bold' : null"> {{adminentrylistSearch.Grp_Header ? adminentrylistSearch.Grp_Header : adminentrylistSearch.firstname}} </span>
</div>
</ng-template>
</p-autoComplete>
在此处检查结果... Demo
在下面的方法中,我们会将数组简化为一个简单的结构
[
{
"id": "m1",
"name": "menu1",
"val": "D",
"search": ["m1", "d1", "1", "2", "menu1", "datanested1", "direct Data", "test"],
"depth": 2
},
{
"id": "d1",
"name": "datanested1",
"val": "D",
"search": ["d1", "1", "2", "datanested1", "direct Data", "test"],
"depth": 1
},
{
"id": "1",
"name": "direct Data",
"val": "E",
"search": ["1", "direct Data"
],
"depth": 0
},
...
]
思路是这样的,我们将使用depth
格式化文本,而search
进行搜索。
maxDepth = 0;
reducedArray = (arr, depth = 0, parentSearch = []) => {
this.maxDepth = Math.max(this.maxDepth, depth);
if (!arr) {
return [];
}
return arr.reduce((prev, { items, ...otherProps }) => {
// const depth = this.findDepth({ items, ...otherProps });
const search = [
...this.getProps({ items, ...otherProps }, "id"),
...this.getProps({ items, ...otherProps }, "name")
];
const newParentSearch = [...parentSearch, otherProps.name, otherProps.id];
return [
...prev,
{ ...otherProps, search, depth, parentSearch },
...this.reducedArray(items, depth + 1, newParentSearch)
];
}, []);
};
getProps = (item, prop) => {
if (!item.items) {
return [item[prop]];
} else {
return [
item[prop],
...item.items.map(x => this.getProps(x, prop))
].flat();
}
};
我们可以应用如下样式
getStyle(depth) {
return {
color: depth === 0 ? "darkblue" : depth === 1 ? "green" : "black",
paddingLeft: depth * 7 + "px",
fontWeight: 800 - depth * 200
};
}
我将使用响应式编程,因此我会将对象转换为 Observable usinf of
运算符
data$ = of(this.reducedArray(this.data));
filteredData$ = combineLatest([this.data$, this.filterString$]).pipe(
map(([data, filterString]) =>
data.filter(
({ search, parentSearch }) =>
!![...search, ...parentSearch].find(x => x.includes(filterString))
)
)
);
大功告成,剩下的就是更新html
<p-autoComplete [(ngModel)]="cdsidvalue" [suggestions]="filteredData$ | async"
(completeMethod)="filterString$.next($event.query)" field="name" [size]="16" placeholder="Menu" [minLength]="1">
<ng-template let-menu pTemplate="item">
<span
[ngStyle]="getStyle(menu.depth)" >{{ menu.name }}</span>
</ng-template>
</p-autoComplete>
更新
由于我们使用的是响应式编程,因此重构以接受 http 请求非常容易,只需将 observable 替换为 http 请求即可
data$ = this.http.get<any[]>("my/api/url");
filteredData$ = combineLatest([this.data$, this.filterString$]).pipe(
map(([data, filterString]) =>
this.reducedArray(data).filter(
({ search, parentSearch }) =>
!![...search, ...parentSearch].find(x => x.includes(filterString))
)
)
);
我也更新了 html 以添加加载消息,我们不想显示没有数据的表单