简体   繁体   中英

Angular 7 Dynamic Content Projection

I need to be able to tell an angular component to render another angular component based on dynamic data. I think this needs content projection, but I can only make content projection work in simple cases.

Example scenario

I have the following table data in vanilla TypeScript:

const headings = [
  { id: 'cat', label: 'Cat' },
  { id: 'nameIt', label: 'Type the name' }
]

const data = [
  { cat: 'Tabby', nameIt: (name) => updateTabbysName(name) },
  { cat: 'Ginger', nameIt: (name) => updateGingersName(name) },
]

I also have four Angular components:

  • simple-span which renders text in a span. In this case, it will render the cat field.
  • text-input which renders a text input. In this case, it will render a basic HTML input which will call the nameIt callback when the user inputs text.
  • my-special-cat-table which will provide the headings and data variables and is allowed to know about text-input and simple-span
  • generic-table which is responsible for rendering table DOM elements. It is not allowed to know that text-input or simple-span exist.

The aim is to have generic-table completely blind to the cell render components

Is it possible to achieve this in Angular 7?

There is *ngComponentOutlet directive for declarative dynamic components: https://angular.io/api/common/NgComponentOutlet

Keep in mind you need to have them all in entryComponents so Injector would know about them and their factories. If you post more code, we can try to figure out the exact solution.

Basically, what it does is resolves a factory then creates it with injector and adds to the view:

    const componentFactory = this.componentFactoryResolver
        .resolveComponentFactory(component);

    this.componentRef = this.viewContainerRef.createComponent(componentFactory);

You can write your own abstraction with similar idea and have it work with any component you want. Strange that people here say that it's impossible now.

You can evaluate creating Reusable Components with NgTemplateOutlet. Just a suggestion.

Take a look at this example .

What you want to acomplish is to use content projection in a loop. Here is an example for Angular Material:

…
<ng-container *ngFor=”let column of displayedColumns” matColumnDef=”{{column.id}}”>
   <th mat-header-cell *matHeaderCellDef mat-sort-header>{{column.name}}</th>
   <td mat-cell *matCellDef=”let row”>
      {{row[column.id]}}
   </td>
</ng-container>
…

As you can see by usage code, you can create multiple templates and combine them in whatever way you want:

<my-component …
[itemTemplate]=”itemTemplate”>
   <ng-template let-item #itemTemplate>
      column id: {{item.column.id}}
      value: {{item.value}}
   </ng-template>
</my-component>

source

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