首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ngAfterViewInit未在ng-content内触发

ngAfterViewInit未在ng-content内触发
EN

Stack Overflow用户
提问于 2019-11-15 06:07:47
回答 2查看 1.1K关注 0票数 3

对于使用如下<ng-content>转换为另一个组件的组件,不会调用ngAfterViewInit生命周期挂钩:

代码语言:javascript
复制
<app-container [showContent]="showContentContainer">
    <app-input></app-input>
</app-container>

然而,它在没有<ng-content>的情况下工作良好。

代码语言:javascript
复制
<app-input *ngIf="showContent"></app-input>

容器组件定义为:

代码语言:javascript
复制
@Component({
  selector: 'app-container',
  template: `
        <ng-container *ngIf="showContent">
              <ng-content></ng-content>
        </ng-container>
  `
})
export class AppContainerComponent {
  @Input()
  showContentContainer = false;

  @Input()
  showContent = false;
}

输入组件定义为:

代码语言:javascript
复制
@Component({
  selector: 'app-input',
  template: `<input type=text #inputElem />`
})
export class AppInputComponent implements AfterViewInit {
  @ViewChild("inputElem")
  inputElem: ElementRef<HTMLInputElement>;

  ngAfterViewInit() {
    console.info("ngAfterViewInit fired!");
    this.inputElem.nativeElement.focus();
  }
}

在这里看一个活生生的例子:https://stackblitz.com/edit/angular-playground-vqhjuh

EN

回答 2

Stack Overflow用户

发布于 2019-11-16 05:10:53

这里有两个问题:

  1. 子组件与父组件一起实例化,而不是在<ng-content>实例化以包括它们时实例化。(参见https://github.com/angular/angular/issues/13921)
  2. ngAfterViewInit并不表示组件已附加到DOM,只是表示视图已实例化。(请参阅https://github.com/angular/angular/issues/13925)

在这种情况下,问题可以通过解决它们中的任何一个来解决:

  1. 容器指令可以重写为结构化指令,仅在适当的时候实例化内容。请看这里的示例:可以重写https://stackblitz.com/edit/angular-playground-mrcokp
  2. The输入指令,以响应实际附加到DOM的情况。要做到这一点,一种方法是编写一个指令来处理这个问题。请看这里的示例:https://stackblitz.com/edit/angular-playground-sthnbr

在许多情况下,两者都可能是合适的。

但是,选项#2使用自定义指令非常容易处理,为了完整起见,我将其包含在这里:

代码语言:javascript
复制
@Directive({
    selector: "[attachedToDom],[detachedFromDom]"
})
export class AppDomAttachedDirective implements AfterViewChecked, OnDestroy {
  @Output()
  attachedToDom = new EventEmitter();

  @Output()
  detachedFromDom = new EventEmitter();

  constructor(
    private elemRef: ElementRef<HTMLElement>
  ) { }

  private wasAttached = false;

  private update() {
    const isAttached = document.contains(this.elemRef.nativeElement);

    if (this.wasAttached !== isAttached) {
      this.wasAttached = isAttached;

      if (isAttached) {
        this.attachedToDom.emit();
      } else {
        this.detachedFromDom.emit();
      }
    }
  }

    ngAfterViewChecked() { this.update(); }
  ngOnDestroy() { this.update(); }
}

它可以像这样使用:

代码语言:javascript
复制
<input type=text 
       (attachedToDom)="inputElem.focus()"
       #inputElem />
票数 3
EN

Stack Overflow用户

发布于 2019-11-15 07:01:41

如果你检查你的stackblitz的控制台,你会看到事件在按下任何按钮之前就被触发了。我只能认为所有被投影的东西都会在你声明它的地方初始化/构造。

所以在你的例子中,就在这几行之间

代码语言:javascript
复制
<app-container [showContent]="showContentContainer">
      {{test()}}
      <app-input></app-input>
</app-container>

如果你在app容器中添加了一个测试函数,它会被立即调用。因此,<app-input>也将立即构建。因为ngAfterVieWInit只会被调用一次(https://angular.io/guide/lifecycle-hooks),这是它已经被调用的地方。

但是,在AppInputComponent中添加以下代码有点奇怪

代码语言:javascript
复制
ngOnDestroy() {
    console.log('destroy')
}

该组件实际上将被立即销毁,并且永远不会再次初始化(添加构造函数或onInit日志进行检查)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58867263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档