Angular2 在 Subchild 中传递指令
Angular2 pass directive in Subchild
我构建了一个简单的列表 UI 组件,其中包含项目,这些项目也是组件:
AppComponent -> ListComponent -> ListItemComponent
我希望此列表可视化不同类型的列表项组件。
例如 2 种类型的列表项:
@Component({
selector: 'list-item',
template: 'This is a PRODUCT!'
})
export class ProductListItemComponent { }
@Component({
selector: 'list-item',
template: 'This is a PERSON!'
})
export class PersonListItemComponent { }
所以,当我初始化我的应用程序组件时:
import {ListComponent} from '...';
import {ProductListItemComponent} from '...';
@Component({
selector: 'list-item',
template: `
<list></list>
`,
directives: [
ListComponent,
ProductListItemComponent
]
})
export class AppComponent { }
它不起作用(当然),因为我的 ListComponent 没有从应用程序组件接收项目组件(指令)。
@Component({
selector: 'item',
template: `
<ul><li *ngFor=...>
<list-item></list-item>
</li></ul>
`
})
export class ListComponent { }
我该怎么办,怎么办?
提前致谢!
首先 - 它是您的真实代码还是复制粘贴?因为我看到,几乎所有组件都有相同的选择器 'list-item',这是错误的。它应该是 uniq。
第二,关于问题本身 - 如果您希望它们在列表中呈现,您应该将 ProductListItemComponent
和 PersonListItemComponent
dep 添加到 ListComponent
中。像这样:
import {PersonListItemComponent} from '...';
import {ProductListItemComponent} from '...';
@Component({
selector: 'list',
template: `
<ul><li *ngFor=...>
<list-item></list-item>
</li></ul>
`,
directives: [
PersonListItemComponent,
ProductListItemComponent
]
})
export class ListComponent { ...}
并且对于您的 AppComponent
,您只需要为 'directives' prop 添加 ListComponent
所以,这是我基于 构建的最终版本(谢谢 Gunter!)
解决方案是使用动态组件作为不同类型的列表和列表项之间的中间。
import {
Component,
ComponentFactory,
ComponentRef,
Input,
ViewContainerRef,
ComponentResolver,
ViewChild} from '@angular/core';
@Component({
selector: 'dynamic-list-item',
template: `<div #target></div>`
})
export class DynamicListItem {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() Type: any;
@Input() Item: any;
cmpRef: ComponentRef<any>;
private isViewInitialized: boolean = false;
constructor(private resolver: ComponentResolver) { }
updateComponent() {
if(!this.isViewInitialized) return;
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.Type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.instance.Item = this.Item;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
我构建了一个简单的列表 UI 组件,其中包含项目,这些项目也是组件:
AppComponent -> ListComponent -> ListItemComponent
我希望此列表可视化不同类型的列表项组件。
例如 2 种类型的列表项:
@Component({
selector: 'list-item',
template: 'This is a PRODUCT!'
})
export class ProductListItemComponent { }
@Component({
selector: 'list-item',
template: 'This is a PERSON!'
})
export class PersonListItemComponent { }
所以,当我初始化我的应用程序组件时:
import {ListComponent} from '...';
import {ProductListItemComponent} from '...';
@Component({
selector: 'list-item',
template: `
<list></list>
`,
directives: [
ListComponent,
ProductListItemComponent
]
})
export class AppComponent { }
它不起作用(当然),因为我的 ListComponent 没有从应用程序组件接收项目组件(指令)。
@Component({
selector: 'item',
template: `
<ul><li *ngFor=...>
<list-item></list-item>
</li></ul>
`
})
export class ListComponent { }
我该怎么办,怎么办? 提前致谢!
首先 - 它是您的真实代码还是复制粘贴?因为我看到,几乎所有组件都有相同的选择器 'list-item',这是错误的。它应该是 uniq。
第二,关于问题本身 - 如果您希望它们在列表中呈现,您应该将 ProductListItemComponent
和 PersonListItemComponent
dep 添加到 ListComponent
中。像这样:
import {PersonListItemComponent} from '...';
import {ProductListItemComponent} from '...';
@Component({
selector: 'list',
template: `
<ul><li *ngFor=...>
<list-item></list-item>
</li></ul>
`,
directives: [
PersonListItemComponent,
ProductListItemComponent
]
})
export class ListComponent { ...}
并且对于您的 AppComponent
,您只需要为 'directives' prop 添加 ListComponent
所以,这是我基于
解决方案是使用动态组件作为不同类型的列表和列表项之间的中间。
import {
Component,
ComponentFactory,
ComponentRef,
Input,
ViewContainerRef,
ComponentResolver,
ViewChild} from '@angular/core';
@Component({
selector: 'dynamic-list-item',
template: `<div #target></div>`
})
export class DynamicListItem {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() Type: any;
@Input() Item: any;
cmpRef: ComponentRef<any>;
private isViewInitialized: boolean = false;
constructor(private resolver: ComponentResolver) { }
updateComponent() {
if(!this.isViewInitialized) return;
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.Type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.instance.Item = this.Item;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}