angular - 递归组件数据引用问题
问题描述
我正在尝试构建一个类别选择器组件,该组件将类别树作为第一手的输入,如下所示:
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')
}
}
当我执行以下操作时会出现问题:
选择'main cat1'然后选择它的子类别(sub cat 1)
选择另一个主要类别“main cat2”,然后切换回“main cat1”
结果:“main cat1”被突出显示,但之前已选择(步骤 1。)“sub cat1”也被突出显示
输出正确,日志显示选择了“main cat1”
所以,问题是“sub cat1”芯片在被选中时仍然突出显示。只应突出显示“main cat1”。
似乎插入的组件以某种方式保存了它的数据。我无法弄清楚如何。
解决方案
同时找到了解决办法。
问题是我使递归元素的组件保持活动状态,因此它保留在内存中,因为它存在于模板中,如下所示:
<ng-template #tpl>
<span class="divider"> / </span>
<category [data]="copyOFChildren"
(selected)="emitSelected($event)"
></category>
</ng-template>
解决方案:<ng-template>
我没有使用ComponentFactoryResolver
手动创建子组件并将输入和输出绑定到它。
查看演示:StackBlitz
推荐阅读
- javascript - 如何在不使用 Promise 和 async/await 的情况下在 while 循环内异步发出后续 http 请求?
- flutter - 删除 SliverAppBar 底部边框 - Flutter
- php - Woocommerce - 更改 2 Checkout 标签文本不起作用
- ios - Xamarin IOS:当应用程序不在后台时如何处理通知点击?(杀死状态)
- java - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure ,关于mybatis
- javascript - 如何使用 bitcoinjs-lib 发送和接收比特币?
- android - 在颤振中,如何在 pubspec.yaml 文件中添加 tflite 作为依赖项?
- javafx - 上下文菜单中的第一个选项突出显示,而无需从 javafx 9 悬停鼠标
- stackblitz - stackblitz -> 因为它的 MIME 类型 ('text/html') 不可执行,并且启用了严格的 MIME 类型检查
- ios - 尝试使用无效网桥在“Networking”(NativeModule 名称)上调用(方法 ID)