我对角很陌生。我有一些关于角的工作。
我需要绑定来自服务器的Json
数据的嵌套下拉列表,调用Rest。
数据有一个属性级别,指定组层次结构中的级别。父级将具有立即的Child=1
、Grandchild=2
等。Child
和Grandchild
有“组”字段,该字段显示父菜单、子菜单将在其中。
我尝试过开发它,但是我发现了bootstrap
的所有示例,其中包含了html
文件中的静态数据和单独的CSS
文件,这对我来说很复杂。
我想使用TypeScript
动态地完成它。我怎么才能开始工作呢。
发布于 2020-02-24 08:10:09
这是一个示例编码,您需要根据json数据中嵌套的级别数据进行编码。现在,您可以使用模型数据循环DOM中的格式化的 json数据。我希望这能帮助你创建一个多层次的下拉列表。
groupBy(xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
}
var model;
getData() {
var sampleData = {
"ArrayOfLocationGroup": {
"LocationGroup": [
...
...//Server response data
],
"_xmlns:xsd": "http://www.w3.org/2001/XMLSchema"
}
}
var list = this.sampleData["ArrayOfLocationGroup"]["LocationGroup"];
var formattedList = [];
list.forEach(element => {
var obj = { //Make sure your server response data to like this structure
"Id": element.Id,
"Name": element.Name,
"GroupId": element.GroupId.__text,
"ParentLocationGroup": element.ParentLocationGroup.__text,
"LgLevel": element.LgLevel.__text,
"Child" : []
}
formattedList.push(obj);
});
var groupDataList = this.groupBy(formattedList, "LgLevel");
var parents = groupDataList[0];
var child = groupDataList[1];
var childOfChild = groupDataList[2];
child.forEach(c => {
c.Child = childOfChild.filter(x => x.ParentLocationGroup == c.Id);
})
parents.forEach(p => {
p.Child = child.filter(x => x.ParentLocationGroup == p.Id);
})
this.model = parents;
}
Html文件
<ul class="nav site-nav">
<li class=flyout>
<a href=#>Dropdown</a>
<!-- Flyout -->
<ul class="flyout-content nav stacked">
<li *ngFor="let parent of model" [class.flyout-alt]="parent.Child.length > 0"><a href=#>{{parent.Name}}</a>
<ul *ngIf="parent.Child.length > 0" class="flyout-content nav stacked">
<li *ngFor="let c of parent.Child" [class.flyout-alt]="c.Child.length > 0"><a href=#>{{c.Name}}</a>
<ul *ngIf="c.Child.length > 0" class="flyout-content nav stacked">
<li *ngFor="let cc of c.Child" [class.flyout-alt]="cc.Child.length > 0"><a href=#>{{cc.Name}}</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
根据您的服务器响应数据,组织模型数据。响应json格式将 (__text改为#text)
var obj = {
"Id": element.Id,
"Name": element.Name && element.Name.#text ? element.Name.#text : element.Name,
"GroupId": element.GroupId && element.GroupId.#text ? element.GroupId.#text : element.GroupId,
"ParentLocationGroup": element.ParentLocationGroup && element.ParentLocationGroup.#text ? element.ParentLocationGroup.#text : element.ParentLocationGroup,
"LgLevel": element.LgLevel && element.LgLevel.#text ? element.LgLevel.#text : element.LgLevel,
"Child" : []
}
发布于 2020-02-25 20:39:50
似乎你已经有了另一个符合你要求的答案。但这个解决方案花了我一段时间才想出。所以决定把它发出去。
下面的代码片段用于构造父-子层次数据的树状结构:
processData(data) {
let locationData = data.ArrayOfLocationGroup.LocationGroup;
let level0 = [];
let tempMap = {};
for (let i = 0; i < locationData.length; i++) {
let currItem = this.getDataObject(locationData[i]);
if (tempMap[currItem.id] == undefined) {
tempMap[currItem.id] = currItem;
if (tempMap[currItem.parentLocationGroup] == undefined) {
tempMap[currItem.parentLocationGroup] = { children: [] };
}
tempMap[currItem.parentLocationGroup].children.push(currItem);
} else {
if (tempMap[currItem.id]) {
currItem.children = tempMap[currItem.id].children;
}
tempMap[currItem.id] = currItem;
if (tempMap[currItem.parentLocationGroup] == undefined) {
tempMap[currItem.parentLocationGroup] = { children: [] };
}
tempMap[currItem.parentLocationGroup].children.push(currItem);
}
if (currItem.lgLevel == "0") {
if (level0.indexOf(currItem) == -1) {
level0.push(currItem);
}
}
}
this.levelData = level0;
}
聚合数据作为输入传递给dropdown
组件,该组件将其呈现为多级下拉菜单。
据推测,这一解决方案将适用于任何级别的儿童。可以修改dropdown
组件,以根据您的需求更改数据呈现的方式。
我从这里取html
和css
作为多级下拉菜单:
https://phppot.com/css/multilevel-dropdown-menu-with-pure-css/
从此答案单击外部时关闭菜单下拉菜单的代码:
https://stackoverflow.com/a/59234391/9262488
希望你觉得这个有用。
发布于 2020-02-26 16:07:14
为什么不创建一个树组件并递归地将输入绑定到它呢?
建议的解决方案是
O(n)
.中。
首先设计数据模型--它必须是一个树节点结构:
export interface GroupId { /* appropriate members... */ }
export interface ParentLocationGroup { /* other members... */ __text: string; }
export interface LgLevel { /* other members... */ __text: string; }
export interface DataModel {
Id: string,
Name: string,
GroupId: GroupId,
ParentLocationGroup: ParentLocationGroup,
LgLevel: LgLevel,
children: DataModel[]
}
然后,将数据聚合到顶层组件(或者更好的数据服务中;您应该能够很容易地将其抽象出来):
// dropdown.component.ts
@Component({
selector: 'app-dropdown',
template: `
<ul class="nav site-nav">
<li class=flyout>
<a href=#>Dropdown</a>
<app-dynamic-flyout [data]="data"></app-dynamic-flyout>
</li>
</ul>
`
})
export class DropdownComponent {
data: DataModel[];
constructor(dataService: YourDataService){
let data;
dataService.getYourData()
.pipe(map(d => d.ArrayOfLocationGroup.LocationGroup)))
// Make sure every item has the `children` array property initialized
// since it does not come with your data
.subscribe(d => data = d.map(i => ({...i, children: []})));
// Create a lookup map for building the data tree
let idMap = data.reduce((acc, curr) => ({...acc, [curr.Id]: curr}), {});
this.data = data.reduce(
(acc, curr) => curr.LgLevel.__text == 0 || !curr.ParentLocationGroup
// Either the level is 0 or there is no parent group
// (the logic is unclear here - even some of your lvl 0 nodes have a `ParentGroup`)
// -> we assume this is a top-level node and put it to the accumulator
? [...acc, curr]
// Otherwise push this node to an appropriate `children` array
// and return the current accumulator
: idMap[curr.ParentLocationGroup.__text].children.push(curr) && acc,
[]
);
}
}
并创建经常性的动态飞出组件:
// dynamic-flyout.component.ts
@Component({
selector: 'app-dynamic-flyout',
template: `
<ul *ngIf="!!data.length" class="flyout-content nav stacked">
<li *ngFor="let item of data" [class.flyout-alt]="!!item.children.length">
<a href=#>{{item.Name}}</a>
<app-dynamic-flyout [data]="item.children"></app-dynamic-flyout>
</li>
</ul>
`
})
export class DynamicFlyoutComponent {
@Input() data: DataModel[];
}
解决方案没有经过测试,但它将指出一个正确的方向.
希望这有一点帮助:-)
https://stackoverflow.com/questions/60318600
复制相似问题