Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiate transcluded components depending on their DOM state in angular 2

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.

like image 515
drow Avatar asked Jan 14 '17 17:01

drow


1 Answers

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)

like image 130
Günter Zöchbauer Avatar answered Nov 09 '22 08:11

Günter Zöchbauer