我有一个可以拥有未知数量的项目和无限嵌套的数组。我需要能够为每个父母添加一个按钮来切换孩子的显示,每个孩子都可以有一个按钮来切换孩子。此外,每个孩子都有一个可以切换父母的按钮。
我无法让切换工作。我现在的方式是基于数组的索引,对于每组子项,它从0开始,如果它们具有相同的索引,可能导致多个项目同时打开。
我在Stackblitz上有一个关于我的问题的例子:https://stackblitz.com/edit/angular-nested-menu-toggle?file=src%2Fapp%2Fapp.component.html
您可以通过单击“五”按钮,然后按“five.two”按钮来查看问题。你可以看到它打开“five.two”以及“two”和“two.two”,因为它们都有相同的索引。
所以我需要的是能够切换一个项目,它只影响其直接的父母或孩子,而不是同时影响其他所有项目。
这是我的阵列:
myArray = [
{
'title': 'one'
},
{
'title': 'two',
'children': [
{
'title': 'two.one'
},
{
'title': 'two.two',
'children': [
{
'title': 'two.two.one'
},
{
'title': 'two.two.two'
}
]
},
{
'title': 'two.three',
'children': [
{
'title': 'two.three.one'
},
{
'title': 'two.three.two'
}
]
}
]
},
{
'title': 'three',
'children': [
{
'title': 'three.one'
},
{
'title': 'three.two',
'children': [
{
'title': 'three.two.one'
},
{
'title': 'three.two.two'
}
]
},
{
'title': 'three.three',
'children': [
{
'title': 'three.three.one'
},
{
'title': 'three.three.two'
}
]
}
]
},
{
'title': 'four'
},
{
'title': 'five',
'children': [
{
'title': 'five.one'
},
{
'title': 'five.two'
}
]
},
{
'title': 'six',
'children': [
{
'title': 'six.one'
},
{
'title': 'six.two',
'children': [
{
'title': 'six.two.one'
},
{
'title': 'six.two.two'
}
]
},
{
'title': 'six.three',
'children': [
{
'title': 'six.three.one'
},
{
'title': 'six.three.two'
}
]
}
]
}
];
然后我在构造函数中有一个toggle变量:
constructor() {
this.toggle = this.myArray.map(i => false);
}
最后,我的HTML
<ul>
<li *ngFor="let item of myArray; let i = index">
<button (click)="toggle[i] = !toggle[i]">{{item.title}}</button>
<div *ngIf="item.children && toggle[i]">
<ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: i }"></ng-container>
</div>
</li>
</ul>
<ng-template #tree let-allItems let-idx="idx">
<ul>
<li *ngFor="let item of allItems; let n = index">
<button (click)="toggle[idx] = !toggle[idx]">X</button>
<button (click)="toggle[n] = !toggle[n]">{{item.title}}</button>
<div *ngIf="item.children && toggle[n]">
<ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: n }"></ng-container>
</div>
</li>
</ul>
</ng-template>
谢谢!
答案 0 :(得分:2)
一种可能的解决方案是创建普通的javascript对象:
toggle: any = {};
并利用组合索引获取树中特定项的状态,使其看起来像:
如您所见,所有指数都是独一无二的。
您需要做的一件事是传递正确的索引:
<ul>
<li *ngFor="let item of myArray; let i = index">
<button (click)="toggle[i] = !toggle[i]">{{item.title }} - {{i}}</button>
<div *ngIf="item.children && toggle[i]">
<ng-container *ngTemplateOutlet="tree; context: { $implicit: item.children, idx: i }">
</ng-container>
</div>
</li>
</ul>
<ng-template #tree let-allItems let-idx="idx">
<ul>
<li *ngFor="let item of allItems; let n = index">
<button (click)="toggle[idx] = !toggle[idx]">X - {{idx}}</button>
^^^^
Parent index
<button (click)="toggle[idx + '.' + n] = !toggle[idx + '.' + n]">{{item.title}} - {{ idx + '.' + n}}</button>
^^^^^^^^^^^^^
Child index
<div *ngIf="item.children && toggle[idx + '.' + n]">
<ng-container
*ngTemplateOutlet="tree; context: { $implicit: item.children, idx: idx + '.' + n }"></ng-container>
^^^^^^^^^^^^^
Child index becomes parent in next iteration
</div>
</li>
</ul>
</ng-template>
请注意我如何通过
生成新索引idx + '.' + n
<强> Stackblitz Example 强>
答案 1 :(得分:1)
创建一个接收项目作为输入的项目组件。现在每个项目只对自己负责。组件模板将是这样的:
<p>
<span>{{item.title}}</span>
<button *ngIf="hasChildren" type="button" class="toggleBtn" (click)="toggleChildren()">Toggle Children</button>
<button *ngIf="hasParent" type="button" class="toggleBtn" (click)="toggleParent()">Toggle Parent</button>
</p>
<ul *ngIf="areChildrenOpen">
<li *ngFor="let child of item.children">
<app-item [item]="child" [hasParent]="true" (toggleClicked)="toggleChildren()"></app-item>
</li>
</ul>
这是处理它的更清洁的方式。
<强> A full Stackblitz example 强>
答案 2 :(得分:0)
我实现了以下递归树的基本解决方案;
技巧是在父模板中定义变量并将其用于所有子对象。如果单击父对象,然后将showChilds变量更改为反转,则所有子对象将被隐藏或显示。
<ng-container *ngTemplateOutlet="tree; context: { $implicit: myArray, idx: 1 , isChildOpen = false }">
</ng-container>
<ng-template #tree let-allItems let-idx="idx" let-showChilds="isChildOpen">
<ul>
<li *ngFor="let item of allItems; let n = index">
<button (click)="showChilds = !showChilds">X - {{idx}}</button>
Parent index
<button (click)="showChilds = !showChilds">{{item.title}} - {{ idx + '.' + n}}</button>
Child index
<div *ngIf="item.children && showChilds">
<ng-container
*ngTemplateOutlet="tree; context: { $implicit: item.children, idx: idx + '.' + n, isChildOpen:showChilds }"></ng-container>
Child index becomes parent in next iteration
</div>
</li>
</ul>
</ng-template>