The “template” mentioned in this article is ng-template. The hypothetical modal component only implements modal content; In order to reduce the length of the article, only important parts were kept. The full example is online.

During development, it is inevitable that a common component will require an Input template or Input component to increase the flexibility of the common component interaction or presentation.

Digression: The input component approach can be extended to rely on services to be configured in business modules so that the same common component used by each module has different interactions. That will be covered in the next article.

1. Use ngTemplateOutlet and ngComponentOutlet

NgTemplateOutlet: Inserts an embedded view based on a pre-prepared TemplateRef. ngComponentOutlet: Instantiates a single Component type and inserts its Host View into current View. NgComponentOutlet provides a declarative approach for dynamic component creation.
Suppose you want to write a table component called wTABLE that needs to customize the cell content. Component TS has the following content.

Online Code:

  • Usage scenarios
 <wtable [columns]="[' name ',' age ']" [rows]="[{name: 'ww', age: 11}, {name:'yy', age: 22}]" [cellContent]="custom"></wtable>

 <ng-template #custom let-data let-column="column" let-row="row" let-index="index"><! , where they can get the data to make things - > {{column}}, {{data}} < br > < br > {{index}} line row data: {{row | json}} < / ng - template >Copy the code
  • HTML for the WTABLE component
<tbody>
  <tr *ngFor="let row of rows; index as i;">
    <td *ngFor="let cell of row | keyvalue"> <! -- Template --> <ng-container *ngIf="tpl">
        <ng-container *ngTemplateOutlet="tpl; context:outCellContext(cell.key, cell.value, row, i);"></ng-container> </ng-container> <! -- Component not working well --> <ng-container *ngIf="comp">
        <ng-container *ngComponentOutlet="comp"></ng-container>
      </ng-container>
    <td>
  </tr>
</tbody>Copy the code
  • Ts wtable components
OutCellContext (cellKey, cellValue, row, index) {return {
      $implicitRow: row, // Row index: index // row index}}}Copy the code

2. Use ViewContainerRef

Represents a container that can attach one or more views to a component.
Suppose you want to write a modal box component wmodal, you need to display the template or component in a modal box. But I don’t want to use *ngIf in HTML to judge the display of content. Two or three are acceptable, but what about seven, eight or more? Let’s look at the following example.

Online code.

  • Usage scenarios
<! -- Component --> <wmodal [content]="comp" [compParams]="{data: 'I passed in the wmodal call '}" (compOut)="wmodalOut($event)"></wmodal> <! -- Template --> <wmodal [content]="modalTpl"></wmodal>
<ng-template #modalTpl let-data let-other="other">
  data: {{data | json}} <br>
  other: {{other}}
</ng-template>Copy the code
  • What do I need to do in WModal? The first is the HTML
<ng-template > <ng-template > <ng-template#container></ng-template>

Copy the code
  • And then wmodal’s TS
ngAfterContentInit() {// Still judge the content typeif(this.content instanceof Type) { const comp = this.container.createComponent(this._compFac.resolveComponentFactory(this.content)); // Merge the parameters required by the component into the component instanceif(this.compParams) { Object.assign(comp.instance, this.compParams); } // Subscribe componentfor (const prop in comp.instance) {
      if(comp.instance.hasOwnProperty(prop)) { const subject = comp.instance[prop]; // Filter the component output eventif(Subject instanceof EventEmitter) {this._compsubs. push(// Subscribe module output events subject.subscribe(data => { this.compOut.emit(data); })); }}}}elseConst _data = {a: 1, b: 2}; const _data = {a: 1, b: 2}; const _data = {a: 1, b: 2}; this.container.createEmbeddedView(this.content, {$implicit: _data, other: 2}); }}Copy the code

3. Use ApplicationRef

A reference to an Angular application running on a page.
Let’s say it’s a Modal component again

  • Usage scenarios
<wmodal2 [content]="comp" [compParams]="{data: 'I'm calling the value passed in by wmodal2 '}" (compOut)="wmodalOut($event)"></wmodal2>Copy the code
  • Convention, Wmodal2 HTML
<! -- Nothing -->Copy the code
  • wmodal2 ts
ngAfterContentInit() { const comp = this._compFaRes.resolveComponentFactory(this.content).create(this._injector); this._e.nativeElement.appendChild(comp.location.nativeElement); Const timeId =? // If (timeId = 0) {// If (timeId = 0)setTimeout(() => { this._appref.attachView(comp.hostView); clearTimeout(timeId); }}, 100)Copy the code

conclusion

This article does not compare the three methods, but just my understanding of the use of the three methods. A quick summary:

  • If 1 is used, the HTML code is too much to maintain. And the one is achieved through the two, the portal;
  • Both 1 and 2 require socket code (visible outlets). For template creation, context is required to pass variables. 3 does not require socket code.
  • 2 is the most common usage
  • Using the 3 approach is only possible to create components and is much more useful
  • Creating a component requires manually assigning an input value and subscribing to an output
You can also look at the Angular source code, where ngFor and ngIf are implemented in the second way.

References:

  • angular.cn
  • Deeper into Angular: Understand Component dynamic loading
  • Angular 4.x Path to the Fairy: Angular 2 TemplateRef & ViewContainerRef