Instantiate transcluded components depending on th

2019-04-20 16:54发布

Common menu usage case

<menu>
    <menu-item1></menu-item1>
    <menu-item2></menu-item2>
    <menu-item3></menu-item3>
</menu>

menu template

<div *ngIf="open$ | async">
    <ng-content></ng-content>
</div>

I was suprised to hear that all menu-item* components (and all their children) will be instantiated despite their presence in DOM and menu component *ngIf state. Their OnInit and AfterViewInit hooks will be called even if menu has never been opened and OnDestroy will never fires despite real adding-removing from DOM. Here is a closed issue about this https://github.com/angular/angular/issues/13921 (there is a plnkr with example) and an issue to angular documentation https://github.com/angular/angular.io/issues/3099.

But this issue is still here - how could i do so that menu items will be instantiated only when menu is opened and properly destroyed if closed? All hooks should fire only related to real DOM state.

2条回答
狗以群分
2楼-- · 2019-04-20 17:30

This is an exemple using ngTemplateOutlet

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <template #templateRef let-label="label" let-url="url">
      <div><a href="{{url}}">{{label}}</a></div>
    </template>

    <div [ngTemplateOutlet]="templateRef" [ngOutletContext]="menu[0]"></div>
    <div [ngTemplateOutlet]="templateRef" [ngOutletContext]="menu[1]"></div>
  `
})
export class App {
    menu:any = [{
           "id": 1,
           "label": "AngularJS",
           "url": "http:\/\/www.learn-angular.fr\/angularJS"
          }, {
           "id": 2,
           "label": "Angular",
           "url": "http:\/\/www.learn-angular.fr\/angular"
    }];

    constructor() {}
}
查看更多
对你真心纯属浪费
3楼-- · 2019-04-20 17:50

update Angular 5

ngOutletContext was renamed to ngTemplateOutletContext

See also https://github.com/angular/angular/blob/master/CHANGELOG.md#500-beta5-2017-08-29

original

You can use

<menu>
  <template>
    <menu-item1></menu-item1>
    <menu-item2></menu-item2>
    <menu-item3></menu-item3>
  <template>
</menu>
@Component({
  selector: 'menu',
  template: `
<div *ngIf="open$ | async">
  <template [ngTemplateOutlet]="templateRef"></template>
</div>
`
})
class MenuComponent {
  @ContentChild(TemplateRef) templateRef:TemplateRef;
}

You can also pass context to ngTemplateOutlet (there are some answers that show how to do that, I don't have time just not to look them up)

查看更多
登录 后发表回答