나는 Angular를 처음 접했습니다. Angular에 대한 작업이 있습니다.
Json
Rest Api를 호출하여 서버에서 오는 데이터에 대해 Nested 드롭 다운 목록을 바인딩해야합니다 .
데이터에는 하나의 속성이 LgLevel
있습니다. 그룹의 계층 구조에서 레벨을 지정합니다. 부모는 것 level=0
, 즉각적인를 Child=1
, Grandchild=2
등등합니다. Child
그리고 Grandchild
이 ParentLocationGroup
쇼가있는 내부 부모 메뉴, 하위 메뉴가있을 것입니다 필드.
이것은 내 json
데이터입니다. 거대한 데이터가 있지만 모두 표시하지는 않습니다.
{
"ArrayOfLocationGroup": {
"LocationGroup": [
{
"Id": "628",
"Name": "TEST1",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources"
},
"ParentLocationGroup": {
"_uuid": "bdce4396-9c60-4831-90f2-6f793becb362",
"__text": "570"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "0"
}
},
{
"Id": "630",
"Name": "TEST2",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "PAM-TEST"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "631",
"Name": "TEST3",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "PAA-TEST"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "697",
"Name": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "TEST4"
},
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "PAE-TEST"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "700",
"Name": "TEST5",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "cuba"
},
"ParentLocationGroup": {
"_uuid": "704af4cf-9feb-4f1b-aa00-d1c7926f7901",
"__text": "694"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "2"
}
},
{
"Id": "706",
"Name": "TEST5",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "VOIP-Test"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "718",
"Name": "TEST7",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "719",
"Name": "TEST8",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "MEM_RS"
},
"ParentLocationGroup": {
"_uuid": "52073e2b-48b5-41a9-9c2b-d793835cf285",
"__text": "718"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "2"
}
},
{
"Id": "752",
"Name": "TEST9",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "ELDIT"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "753",
"Name": "TEST10",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "GXYA"
},
"ParentLocationGroup": {
"_uuid": "52073e2b-48b5-41a9-9c2b-d793835cf285",
"__text": "718"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "2"
}
},
{
"Id": "760",
"Name": "TEST11",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "STAGE2"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "761",
"Name": "TEST12",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "INIT"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
},
{
"Id": "762",
"Name": "TEST13",
"GroupId": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "USIT"
},
"ParentLocationGroup": {
"_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
"__text": "628"
},
"LgLevel": {
"_xmlns": "http://www.air-watch.com/servicemodel/resources",
"__text": "1"
}
}
],
"_xmlns:xsd": "http://www.w3.org/2001/XMLSchema"
}
}
나는 그것을 개발하기 위해 노력했지만 파일과 bootstrap
정적 html
파일에 정적 데이터가있는 모든 예제를 찾았 CSS
습니다.
을 사용하여 동적으로하고 싶습니다 TypeScript
. 어떻게 작업을 시작할 수 있습니까?
답변
이것은 json 데이터의 중첩 레벨 데이터에 따라 필요한 샘플 코딩입니다. 이제 모델 데이터를 사용하여 DOM에서 형식 이 지정된 JSON 데이터를 for 루프 할 수 있습니다 . 이것이 멀티 레벨 드롭 다운을 만드는 데 도움이되기를 바랍니다.
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" : []
}
답변
귀하의 요구 사항을 충족시키는 다른 답변이 이미있는 것 같습니다. 그러나이 솔루션은 언젠가 생각해 냈습니다. 어쨌든 게시하기로 결정했습니다.
아래 코드 스 니펫은 부모-자식 계층 데이터의 트리 구조를 구성하는 데 사용됩니다.
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
이 정보가 도움이 되길 바랍니다.
답변
트리 컴포넌트를 작성하고 입력을 재귀 적으로 바인딩하지 않는 이유는 무엇입니까?
제안 된 해결책은
- 심도에 구애받지 않음-데이터 트리의 여러 수준에서 작동합니다 (임시 변경하더라도).
- 매우 효율적-데이터를 집계합니다
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[];
}
솔루션은 테스트되지 않았지만 올바른 방향으로 안내합니다 …
희망이 조금 도움이되기를 바랍니다 🙂