angular 4 个带有各种列表项模板的通用列表
angular 4 generic list with various list item templates
我正在尝试构建一个通用组件,该组件显示具有 angular 4 和 Material 设计的项目列表。
目标是有一个列表,我只向其提供子组件,如下所示:
<generic-list
title="My name list title"
[items]="names"
(change)="handleNameChanged($event)">
<some-child let-item="name"></some-child>
</generic-list>
@ViewChild(GenericListItem)
childItem: GenericListItem;
或者这个:
<generic-list ... [type]="simpleListItem"></generic-list>
@Input() type: Type<GenericListItem>;
export class GenericListItem {
@Input() value: any;
}
因此,任何子组件都应从 GenericListItem
扩展,并且能够按其需要显示 value
的属性。
我需要的一些示例组件:
@Component({
selector: 'app-simple-list-item',
template: '<p>{{value?.name}}</p>'
})
export class SimpleListItem extends GenericListItem {
}
@Component({
selector: 'app-chechbox-list-item',
template: '<md-checkbox [(ngModel)]="value?.enabled">{{value?.name}} &
{{value?.email}}</md-checkbox>'
})
export class CheckboxListItem extends GenericListItem {
}
generic-list
组件如下所示:
<md-list>
<h2 md-subheader>{{title}}</h2>
<md-list-item #outlet
*ngFor="let item of items; let i = index"
(click)="change.emit(item)">
// in here should go the content for each item
</md-list-item>
</md-list>
我已经寻找实现此目的的方法,但是,none 已经存在的解决方案不再有效或已弃用。此外,关于该主题的一些备用文档也无济于事...
我找到了 post,我试图对其进行改编,结果在 generic-list
:
中生成了这段代码
export class GenericListComponent implements OnInit, AfterViewInit {
//inputs, outputs and other properties here
@ViewChildren('outlet', {read: ViewContainerRef})
outlets: QueryList<ViewContainerRef>;
ngOnInit() {
}
ngAfterViewInit() {
console.log(this.outlets); // prints '3', since I've declared 3 items
this.isViewInitialized = true;
this.updateChildren();
}
updateChildren() {
if (!this.isViewInitialized) {
return;
}
this.outlets.forEach((outlet, index) => {
const factory = this.cfr.resolveComponentFactory(this.type);
const componentRef = outlet.createComponent(factory);
componentRef.instance.value = this.items[index];
});
}
这会导致有关 ChangeDetection
的错误
Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'Hi1V'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?
我的测试组件:
<app-generic-list
title="AppTitle"
[items]="names"
[type]="simpleListItem"
(change)="handleItemChanged($event)"></app-generic-list>
export class AppComponent {
simpleListItem = SimpleListItemComponent;
names = [
{value: 'Hi1V', desc: 'Hello1'},
{value: 'Hi2V', desc: 'Hello2'},
{value: 'Hi3V', desc: 'Hello3'}
];
handleItemChanged(item: string) {
console.log(item);
}
}
看来我可能已经接近解决方案了,但现在我不知道在什么时候需要实例化组件。
此外,子组件中的自定义输出是否有效并且可以从 generic-list
外部调用?
https://github.com/elgervb/ngx-components/blob/master/src/app/list/list.component.ts 不是更好的解决方案吗?您可以创建一个列表并提供一个模板来呈现项目。在模板中您可以使用自己的自定义组件
所有内容都非常通用。
用法示例如下:
<evb-list [items]="items" [filterEnabled]="true">
<ng-template let-item>
<md-checkbox [(ngModel)]="item?.enabled">{{item?.name}} &&
{{value?.email}}</md-checkbox>
</ng-template>
其中 item in ng-template 将是列表中的每个项目。
我认为此组件以通用方式完成您想要的一切。
希望这对您有所帮助
;-)
我正在尝试构建一个通用组件,该组件显示具有 angular 4 和 Material 设计的项目列表。 目标是有一个列表,我只向其提供子组件,如下所示:
<generic-list
title="My name list title"
[items]="names"
(change)="handleNameChanged($event)">
<some-child let-item="name"></some-child>
</generic-list>
@ViewChild(GenericListItem)
childItem: GenericListItem;
或者这个:
<generic-list ... [type]="simpleListItem"></generic-list>
@Input() type: Type<GenericListItem>;
export class GenericListItem {
@Input() value: any;
}
因此,任何子组件都应从 GenericListItem
扩展,并且能够按其需要显示 value
的属性。
我需要的一些示例组件:
@Component({
selector: 'app-simple-list-item',
template: '<p>{{value?.name}}</p>'
})
export class SimpleListItem extends GenericListItem {
}
@Component({
selector: 'app-chechbox-list-item',
template: '<md-checkbox [(ngModel)]="value?.enabled">{{value?.name}} &
{{value?.email}}</md-checkbox>'
})
export class CheckboxListItem extends GenericListItem {
}
generic-list
组件如下所示:
<md-list>
<h2 md-subheader>{{title}}</h2>
<md-list-item #outlet
*ngFor="let item of items; let i = index"
(click)="change.emit(item)">
// in here should go the content for each item
</md-list-item>
</md-list>
我已经寻找实现此目的的方法,但是,none 已经存在的解决方案不再有效或已弃用。此外,关于该主题的一些备用文档也无济于事...
我找到了 generic-list
:
export class GenericListComponent implements OnInit, AfterViewInit {
//inputs, outputs and other properties here
@ViewChildren('outlet', {read: ViewContainerRef})
outlets: QueryList<ViewContainerRef>;
ngOnInit() {
}
ngAfterViewInit() {
console.log(this.outlets); // prints '3', since I've declared 3 items
this.isViewInitialized = true;
this.updateChildren();
}
updateChildren() {
if (!this.isViewInitialized) {
return;
}
this.outlets.forEach((outlet, index) => {
const factory = this.cfr.resolveComponentFactory(this.type);
const componentRef = outlet.createComponent(factory);
componentRef.instance.value = this.items[index];
});
}
这会导致有关 ChangeDetection
的错误Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'Hi1V'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?
我的测试组件:
<app-generic-list
title="AppTitle"
[items]="names"
[type]="simpleListItem"
(change)="handleItemChanged($event)"></app-generic-list>
export class AppComponent {
simpleListItem = SimpleListItemComponent;
names = [
{value: 'Hi1V', desc: 'Hello1'},
{value: 'Hi2V', desc: 'Hello2'},
{value: 'Hi3V', desc: 'Hello3'}
];
handleItemChanged(item: string) {
console.log(item);
}
}
看来我可能已经接近解决方案了,但现在我不知道在什么时候需要实例化组件。
此外,子组件中的自定义输出是否有效并且可以从 generic-list
外部调用?
https://github.com/elgervb/ngx-components/blob/master/src/app/list/list.component.ts 不是更好的解决方案吗?您可以创建一个列表并提供一个模板来呈现项目。在模板中您可以使用自己的自定义组件
所有内容都非常通用。
用法示例如下:
<evb-list [items]="items" [filterEnabled]="true">
<ng-template let-item>
<md-checkbox [(ngModel)]="item?.enabled">{{item?.name}} &&
{{value?.email}}</md-checkbox>
</ng-template>
其中 item in ng-template 将是列表中的每个项目。
我认为此组件以通用方式完成您想要的一切。
希望这对您有所帮助
;-)