递归组件数据引用问题



我正在尝试构建一个类别选择器组件,该组件可以直接获得类别树作为输入,如下所示:

mockData: Category[] = [
{ id: 1, name: 'main cat1', children: [
{ id: 3, name: 'sub cat1', children: []},
{ id: 4, name: 'sub kat2', children: []}
]},
{ id: 2, name: 'main cat2', children: [
{ id: 5, name: 'sub cat5', children: []},
]},
]

模板:该组件显示ngFor中的主要类别。如果选择了一个类别,它会手动将#tpl标记的模板插入#vc视图容器中。这是对我认为这将解决问题的一种尝试。

<mat-chip-list aria-label="Category selection" [multiple]="false">
<mat-chip *ngFor="let chip of data"
[selected]="chip.id === selectedCategory?.id"
(click)="clickChip($event, chip)">{{ chip.name }}</mat-chip>
</mat-chip-list>
<ng-container #vc></ng-container>

<ng-template #tpl>
<span class="divider"> / </span>
<category [data]="copyOFChildren"
(selected)="emitSelected($event)"
></category>
</ng-template>

组件:

export class CategorySelectorComponent implements AfterViewInit, OnInit {
@Input() data: Category[];
@Output() selected: EventEmitter<Category> = new EventEmitter();
selectedCategory: Category;
copyOFChildren: Category[];
@ViewChild("vc", {read: ViewContainerRef, static: true}) vc: ViewContainerRef;
@ViewChild('tpl', {static:true}) tpl: TemplateRef<any>;
childViewRef: ViewRef;
ngAfterViewInit(){
this.childViewRef = this.tpl.createEmbeddedView(null);
}
clickChip(event, category) {
this.removeChildView();
this.selectedCategory = (this.selectedCategory && this.selectedCategory.id === category.id) ? null : {...category};
this.selected.emit(this.selectedCategory);
this.insertChildView();
}
emitSelected(category: Category | null):void {
if (category) {
this.selected.emit(category)
} else {
this.selected.emit(this.selectedCategory)
}
}
insertChildView(){
if (this.selectedCategory && this.selectedCategory.children.length) {
this.copyOFChildren = [ ...this.selectedCategory.children ];
this.vc.insert(this.childViewRef);
}
}
removeChildView(){
this.copyOFChildren = undefined;
this.vc.detach();
console.log('detach')
}
}

当我执行以下操作时会出现问题:

  1. 选择"主类别1",然后选择其子类别(子类别1(

  2. 选择另一个主要类别"主要类别2",然后切换回"主要类别1">

  3. 结果:突出显示了"主cat1",但之前选择了(步骤1("子cat1"也突出显示了

输出正确,日志显示选择了"主cat1">

因此,问题是"sub-cat1"芯片在被选中时仍然突出显示。只应突出显示"main cat1"。

似乎插入的组件以某种方式保存了它的数据。我不知道怎么回事。

STACKBLITZ

同时找到了解决方案。

问题是,我让递归元素的组件保持活动,所以它保持在内存中,因为它在模板中如下所示:

<ng-template #tpl>
<span class="divider"> / </span>
<category [data]="copyOFChildren"
(selected)="emitSelected($event)"
></category>
</ng-template>

解决方案:代替使用CCD_ 2,我使用ComponentFactoryResolver手动创建子组件并绑定输入&

查看演示:StackBlitz

最新更新