简体   繁体   中英

Angular list with generic component as list item

Suppose I have a "ParentComponent" that has a list of items (let's say taken as an input) and needs to render the elements in the list. I need this parent component to be reusable however and one of the customizations it would support would be choosing the template (or component) it uses for rendering the list items. The component used for the child list items could be anything as long as it can render the list item given to it as an input (the template can correctly reference properties of the item). This is possible in frameworks such as React, so my question would be if it is possible as well in Angular and how one would do it?

I imagine the parent component taking the custom component as an input, along with the items

@Input()
items: Array<ItemType>;

@Input()
componentForRenderingStuff: ?;

And the template being something like this

<div class="wrapper">
  <!-- ...stuff -->
  <div class="list-item" *ngFor="let i of items">
    <component-for-rendering-stuff [item]="i"></component-for-rendering-stuff>
  </div>
</div>

Which would mean that using the parent component in another template would be like

<app-parent-component [items]="items" [componentForRenderingStuff]="SomeComponent"></app-parent-component>

Is something like this possible? I looked at ng-content but I couldn't make it work with *ngFor .

As Edward suggested in his comment the behavior can be achieved using dynamic component loading.

I found a few third party libraries on npm which solved that and due to time and simplicity I used the one which had the most appealing user statistics: https://www.npmjs.com/package/ng-dynamic-component

In short a generic list component would look like this

@Component({
  selector: 'app-list',
  template: `
    <div *ngFor="let item of items">
      <ndc-dynamic
        [ndcDynamicComponent]="listItemComponent"
        [ndcDynamicInputs]="{ input: item.data }"
      ></ndc-dynamic>
    </div>
  `,
  styleUrls: ['...'],
})
export class ClickableVerticalListComponent {
  @Input()
  listItemComponent: any;

  @Input()
  items: Array<any>;

  constructor() {}
}

If we want to use the list with a specific custom component for a list item we would do it in this way:

@Component({
  selector: '...',
  template: `
    <app-list 
      [items]="items" 
      [listItemComponent]="ExampleComponent"
    ></app-list>
  `,
  styleUrls: ['...'],
})
export class ParentComponent {
  ExampleComponent = ExampleComponent;

  items: [{ data: ... }, { data: ... }];

  constructor() {}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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