1

我有一个在其父组件中使用两次的子组件,它使用 ngOnChages 来更新值;

这一切都很好,但现在我正在尝试根据通过@Input变量传递的信息在孩子内部操纵模板。

我发现的是;首次加载父组件时,模板变量在函数调用中未定义

这是有道理的,因为这个函数是在onChanges方法中调用的,并且没有给模板足够的时间来加载。

我需要重构我的代码,但是怎么做呢?

目前,如果我使用它可以工作setTimeout

所以简单地说:

@ViewChild('myContainer', {read: ElementRef}) myContainer: ElementRef;
@Input() myUpdatingVar

ngOnChanges(): void {
  if (this.myUpdatingVar === someValue) {
      this.myFunc(this.someValue1);
   } else {
      this.myFunc(this.someValue2);
   }
}

myFunc(param){
   do stuff....
   this.updateDom(anotherParam);
}

updateDom(param) {
// If I use setTimeout this works
this.myContainer.nativeElement.querySelector(`#someId`); // Undefined
}
4

5 回答 5

4

ngOnChanges您可以使用 检测更改,而不是使用setter

这是您需要做的

@Input()
set myUpdatingVar(value: any) {
   if(value) {
        this.myFunc(value);
   }
}

它不仅会在初始化视图时加载,而且每当在 中更改某些内容时myUpdatingVar,Angular 都会运行 setter 并执行您的函数。此外,ngOnChanges它是一个昂贵的生命周期钩子。如果您不小心使用它,它会在每次组件中发生更改时运行。

但是如果你想使用ngOnChanges,你应该使用它在变量中检测到的变化,而不是使用变量本身。

这是示例

ngOnChanges(changes: SimpleChanges): void {
  if (changes.myUpdatingVar.currentValue === someValue) {
      this.myFunc(changes.myUpdatingVar.currentValue);
   } else {
      this.myFunc(changes.myUpdatingVar.currentValue);
   }
}

您可以检查它是否是第一个更改,也可以获取currentValue并且previousValue在这种情况下很有用。

我希望我的回答对你有所帮助。快乐编码!

于 2019-05-08T20:37:54.497 回答
1

使用较新的角度(9.x)我通过将静态设置为true解决了这个问题:

@ViewChild('myContainer', {static: true})
于 2020-03-16T14:38:17.580 回答
1

正如其他人所说,onchanges 对于访问 viewchildren 来说运行得太早了,你需要这样的东西:

@ViewChild('myContainer', {read: ElementRef}) myContainer: ElementRef;
@Input() myUpdatingVar

ngOnChanges(): void {
  if (this.myContainer) {
    if (this.myUpdatingVar === someValue) {
       this.myFunc(this.someValue1);
     } else {
       this.myFunc(this.someValue2);
     }
   }
}

ngAfterViewInit() {
  this.ngOnChanges();
}

myFunc(param){
   do stuff....
   this.updateDom(anotherParam);
}

updateDom(param) {
// If I use setTimeout this works
this.myContainer.nativeElement.querySelector(`#someId`); // Undefined
}

这样,如果视图尚未初始化,您将跳过逻辑,并在视图初始化后手动触发运行 ngOnChanges。

综上所述,实现这一目标可能有一种更加角度的方式,除非您正在与一些集成不良的 3rd 方库进行交互。

于 2019-05-08T19:36:09.200 回答
1

查看本指南:https ://angular.io/guide/lifecycle-hooks

Angular 生命周期事件以特定顺序触发,有些事件在加载 dom 元素之前发生。

ngAfterViewInit 是让您知道 DOM(或至少您看到的抽象)已准备好被查询的钩子。这意味着模板变量和 viewchildren 在此事件触发之前将无法正常工作。

编辑:听起来你了解时机。为了解决这个问题,我建议在 onChanges 中使用它之前检查模板变量是否已定义(现在它将在所有后续调用 onChanges 时发生),然后如果您需要在开始时运行一次,则在 ngAfterViewInit 中执行相同的操作。

于 2019-05-08T19:36:27.913 回答
0

对于 DOM 操作,您应该使用ngAfterViewInit生命周期挂钩,以确保模板已加载到 DOM 中。

ngOnChanges早火一次,甚至早于ngOnInit. DOM 操作还为时过早。

您可以在 中使用isViewInitialized布尔值并将其设置为 true ngAfterViewInit,然后在 中的if条件中使用它ngOnChanges

于 2019-05-08T19:33:29.347 回答