如何停止在 ngOnInit() 之前调用的 ngOnChanges

Posted

技术标签:

【中文标题】如何停止在 ngOnInit() 之前调用的 ngOnChanges【英文标题】:how to stop ngOnChanges Called before ngOnInit() 【发布时间】:2017-08-16 06:38:59 【问题描述】:

在我的 Angular 应用程序中,我遇到了一种情况,即 ngOnchanges 仅应在输入绑定更改时调用。那么,有没有办法在 ngOnInit 之前停止执行 ngOnChanges。有没有办法做到这一点。 提前致谢。

【问题讨论】:

这是正常行为。查看 Angular 2 文档中的 Lifecycle Hooks。而不是ngOnChange,你可以试试ngAfterViewInit(),例如(Angular初始化组件的视图和子视图后响应) 是的,我知道。 ngoninit 执行后,有什么方法可以监听我的输入变化? ngOnInit()之后,ngDoCheck()被执行(但它会被执行多次)。如果您使用的是响应式表单,您可以保留 ngOnChange 并检查是否设置了表单字段 (if(this.form.get('yourField').value) ...)。类似于你现在拥有的东西。 是的,我确实尝试过使用 ngdocheck,但它进入了一种无限循环。这不是一个表单,dataready 是我从另一个组件获得的输入,我想听听它的变化。 没有。但是,如果您提供有关您尝试解决的实际问题的信息,我们可能会提供其他方法来帮助您解决问题。 【参考方案1】:

您无法阻止这种行为,但您可以:

使用主题:

class Foo implements OnChanges,OnInit,OnDestroy

  onChanges = new Subject<SimpleChanges>();

  ngOnInit()
    this.onChanges.subscribe((data:SimpleChanges)=>
      // only when inited
    );
  
  ngOnDestroy()
    this.onChanges.complete();
  

  ngOnChanges(changes:SimpleChanges)
    this.onChanges.next(changes);
  


使用布尔属性:

class Foo implements OnChanges,OnInit

  initialized=false;

  ngOnInit()
    // do stuff
    this.initialized = true;
  

  ngOnChanges(changes:SimpleChanges)
    if(this.initialized)
      // do stuff when ngOnInit has been called
    
  


使用SimpleChanges API

你也可以查看SimpleChange.isFirstChange()方法:

isFirstChange() : boolean 检查新值是否是第一个分配的值。

class Foo implements OnChanges,OnInit

  @Input()
  bar:any;

  ngOnInit()
    // do stuff
  

  ngOnChanges(changes:SimpleChanges)
    if(!changes["bar"].isFirstChange())
      // do stuff if this is not the initialization of "bar"
    
  


【讨论】:

我可以使用自己的数据类型模型来代替SimpleChanges吗? 对不起,我不明白你的问题。 我的意思是:我有自己的模型公共数据:自己的;它模型与模板绑定。我怎样才能听到这个模型的任何变化? 此答案假定您有能力跳过第一个 ngOnChanges。这并不能解决问题。问题是如何在第一个 ngOnChanges 之前调用 ngOnInit。我认为这是一个设计错误,尤其是在使用可选参数时。 @cyberfly 这取决于您的需求,它并没有本质上更好。请注意,使用 ReplaySubject,您将获得初始化之前设置的数据,这不是我们在这里想要的。另请注意,您可以在常规的 Observable/Subject 上 publishReplay()connect()shareReplay() 获得相同的行为。【参考方案2】:

我发现一种可行的方法是基于输入值都具有先前值属性这一事实。如果之前未设置输入,则该值将为CD_INIT_VALUE(作为字符串)。因此,您可以设置一个条件,即您在ngOnChanges 中的代码块应该仅在前一个值不是CD_INIT_VALUE 时运行。这是您正在测试所有输入值的示例:

ngOnChanges(changes: SimpleChanges) 
  let initialized: boolean = true;
  for (let prop in changes) 
    if (changes[prop].previousValue.toString() === 'CD_INIT_VALUE') 
      initialized = false;
      //we can break here since if any item is not initialized
      //we will say the inputs are NOT initialized
      break;
    
  

  if (initialized) 
    //code you want to execute
      

可能有更优雅的解决方案,但我发现这是可行的。 这可能为时已晚,无法帮助您,但可能会帮助其他人,因为当我在谷歌上搜索时,我发现了这个问题。解决方案是我从调试中发现的。

【讨论】:

【参考方案3】:

如果它对任何人有帮助,这里是我如何将@n00dl3 建议的isFirstChange() 解决方案实施到我的 AngularJS 应用程序的示例:

this.$onChanges = (changes) => 
    if (!changes.value.isFirstChange()) 
        // do stuff
    
;

【讨论】:

以上是关于如何停止在 ngOnInit() 之前调用的 ngOnChanges的主要内容,如果未能解决你的问题,请参考以下文章

自学ng -生命周期钩子

Angular5服务调用在ngOnInit上不起作用

组件在 NgOnInit 完成之前渲染?

在 ngOnInit 函数中打开 ng-template 不起作用

为啥每次都重复调用 ngOnInit

Angular测试如何防止ngOnInit调用直接测试方法