Создание включенных компонентов в зависимости от их состояния DOM в angular 2

Общий случай использования меню

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

шаблон меню

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

Я был удивлен, узнав, что все компоненты menu-item* (и все их дочерние элементы) будут созданы, несмотря на их присутствие в DOM и состояние *ngIf компонента menu. Их хуки OnInit и AfterViewInit будут вызываться, даже если меню никогда не открывалось, а OnDestroy никогда не сработает, несмотря на реальное добавление-удаление из DOM. Вот закрытая проблема об этом https://github.com/angular/angular/issues/13921 (есть plnkr с примером) и вопрос к документации angular https://github.com/angular/angular.io/issues/3099.

Но эта проблема все еще здесь - как я могу сделать так, чтобы элементы меню создавались только при открытии меню и должным образом уничтожались при закрытии? Все хуки должны срабатывать только в связи с реальным состоянием DOM.


person drow    schedule 14.01.2017    source источник


Ответы (2)


обновить Angular 5

ngOutletContext был переименован в ngTemplateOutletContext

См. также https://github.com/angular/angular/blob/master/CHANGELOG.md#500-beta5-2017-08-29

исходный

Вы можете использовать

<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;
}

Вы также можете передать контекст ngTemplateOutlet (есть несколько ответов, которые показывают, как это сделать, у меня нет времени просто не искать их)

person Günter Zöchbauer    schedule 14.01.2017
comment
Хм, похоже, это самый простой способ добиться ожидаемого включения, спасибо. В документации по ng2 большой пробел про <template>/TemplateRef/ngTemplateOutlet и другие вещи, которые выглядят странно и неочевидно. Можете ли вы порекомендовать какой-нибудь текстовый/видео контент на эту тему? - person drow; 15.01.2017
comment
Я собрал информацию из различных комментариев. Я не знаю о документах. - person Günter Zöchbauer; 15.01.2017
comment
Прочитав всю соответствующую информацию по теме, я чувствую, что это неожиданное поведение очень разочаровывает. Команда Angular может сказать: это задумано, но нигде в документации Angular нет ни ясности, ни ясности. Я уверен, что есть тысячи пользователей Angular, которые предполагают, что ngIf будет работать везде одинаково, и реализовали много логики в ngOnInit(), как говорится в рекомендациях Angular, это какое-то противоречие. Просто разглагольствование, спасибо за обходной путь Гюнтер! - person Dani P.; 25.11.2020

Это пример использования 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() {}
}
person William Koza    schedule 16.01.2017