简体   繁体   English

带有各种列表项模板的angular 4通用列表

[英]angular 4 generic list with various list item templates

I am trying to build up a generic component which displays a list of items with angular 4 and Material Design. 我正在尝试建立一个通用组件,该组件显示带有angular 4和Material Design的项目列表。 The goal is, to have a list to which I only provide the child component like this: 目的是要有一个清单,我仅向其提供子组件,如下所示:

<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;

or this: 或这个:

<generic-list ... [type]="simpleListItem"></generic-list>

@Input() type: Type<GenericListItem>;

export class GenericListItem {
  @Input() value: any;
}

So, any child component should extend from GenericListItem and would be able to display the properties of value like it wants to. 因此,任何子组件都应该从GenericListItem扩展而来,并且能够像期望的那样显示value的属性。 Some example components I'm in need of: 我需要一些示例组件:

@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 {
}

The generic-list component looks like this: 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>

I've searched for ways to achieve this, however, none of the already present solutions are valid anymore or deprecated. 我一直在寻找实现这一目标的方法,但是,已经存在的解决方案都不再有效或不建议使用。 Also the somewhat spare documentation on this topic does not help either... 同样,关于该主题的一些备用文档也无济于事...

I found this post which I tried to adapt, resulting in this code in generic-list : 我发现这个职位,我努力去适应,造成这种代码在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];
  });
}

which results in an error about ChangeDetection 导致有关ChangeDetection的错误

Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. 错误:ExpressionChangedAfterItHasBeenCheckedError:检查表达式后,表达式已更改。 Previous value: 'undefined'. 上一个值:“未定义”。 Current value: 'Hi1V'. 当前值:“ 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 ? 它是在变更检测挂钩中创建的吗?

My test component: 我的测试组件:

<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);
  }
}

It seems like I may be close to a solution already, but now I don't know at which point I need to instanciate the components. 看来我可能已经接近解决方案,但是现在我不知道该在什么时候实例化这些组件。 Also, will custom outputs in the child components work and can be called from outside of generic-list ? 另外,子组件中的自定义输出是否可以正常工作,并且可以从generic-list外部调用?

Wouldn't https://github.com/elgervb/ngx-components/blob/master/src/app/list/list.component.ts be a better solution. https://github.com/elgervb/ngx-components/blob/master/src/app/list/list.component.ts不会是更好的解决方案。 You can create a list and supply a template to render the items. 您可以创建列表并提供模板以呈现项目。 In the template you can use your own custom components 在模板中,您可以使用自己的自定义组件

All in a very generic way. 全部以非常通用的方式进行。

An example of usage would be: 用法示例如下:

<evb-list [items]="items" [filterEnabled]="true">

<ng-template let-item>
  <md-checkbox [(ngModel)]="item?.enabled">{{item?.name}} &&
  {{value?.email}}</md-checkbox>
</ng-template>

Where item in ng-template will be each item in the list. 凡在NG-模板 项目将出现在列表中的每个项目。

I think this component does everything you want in a generic way. 我认为该组件以通用的方式完成了您想要的一切。

Hope this is any help 希望这对您有帮助

;-) ;-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM