【问题标题】:How to trigger a change event manually - angular2如何手动触发更改事件 - angular2
【发布时间】:2017-12-10 00:45:46
【问题描述】:

给定以下组件:

@Component({
    selector: 'compA',
    template:  template: `<compB [item]=item></compB>`
})
export class CompA {
    item:any;
    updateItem():void {
        item[name] = "updated name";
    }
}

@Component({
    selector: 'compB',
    template:  template: `<p>{{item[name]}}</p>`
})
export class CompB implements OnInit{
    @Input() item: any;
    someArray: any[];

    ngOnInit():void {
        someArray.push("something");
    }
}

据我了解,除非更改完整的 item 对象,否则 angular2 无法识别 item 上的更改。因此,我想在调用updateItem 方法时为item 手动发出更改事件。然后,重新渲染子组件,即CompB,就好像 Angular 以常规方式检测到变化一样。

目前,我所做的是实现CompBngOnInit 方法,并通过ViewChild 链接在updateItem 方法中调用该方法。故事的另一部分是我的实际来源有像someArray 这样的对象,我想在每次渲染中重置它们。我不确定重新渲染是否会重置someArray。目前,我正在ngOnInit 方法中重置它们。

所以,我的问题是:如何触发对父对象的更深元素的更改进行重新渲染?

谢谢

【问题讨论】:

标签: angular typescript angular2-template angular2-directives


【解决方案1】:

据我了解,除非完整的 item 对象是 已更改,angular2 无法识别项目上的更改。

事情并不是那么简单。您必须区分对象发生变异时触发ngOnChanges 和子组件的DOM 更新。 Angular 无法识别 item 已更改并且不会触发 ngOnChanges 生命周期挂钩,但如果您在模板中引用 item 的特定属性,DOM 仍将更新。这是因为对对象的引用被保留了。因此要有这种行为:

然后,使子组件,即 CompB 重新渲染,好像 angular 以常规方式检测到变化。

您不必特别做任何事情,因为您仍然会在 DOM 中进行更新。

手动变更检测

您可以插入一个更改检测器并像这样触发它:

@Component({
    selector: 'compA',
    template:  template: `<compB [item]=item></compB>`
})
export class CompA {
    item:any;
    constructor(cd: ChangeDetectorRef) {}

    updateItem():void {
        item[name] = "updated name";
        this.cd.detectChanges();
    }
}

这会触发当前组件及其所有子组件的更改检测。

但是,它不会对您的情况产生任何影响,因为即使 Angular 没有检测到 item 的变化,它 仍然会为孩子运行变化检测 B 组件并更新 DOM

除非您使用ChangeDetectionStrategy.OnPush。在这种情况下,一种适合您的方法是手动检查 CompBngDoCheck 钩子:

import { ChangeDetectorRef } from '@angular/core';

export class CompB implements OnInit{
    @Input() item: any;
    someArray: any[];
    previous;

    constructor(cd: ChangeDetectorRef) {}

    ngOnInit():void {
        this.previous = this.item.name;
        someArray.push("something");
    }

    ngDoCheck() {
      if (this.previous !== this.item.name) {
        this.cd.detectChanges();
      }
    }
}

您可以在以下文章中找到更多信息:

【讨论】:

  • 您好,我已经尝试过您的示例代码,但是 ngDoCheck() 方法在应用程序中执行了多次,您能解释一下如何克服这个问题
  • 不确定,但我想您还需要changeDetection: ChangeDetectionStrategy.OnPush 或脱离变更检测?
【解决方案2】:

您可以在 CompB 中放置另一个输入,因此当您想要更改 CompA 中项目的属性时,只需更改此输入的值。

@Component({
    selector: 'compA',
    template:  template: `<compB [item]=item [trigger]=trigger></compB>`
})
export class CompA {
    item:any;
    trigger: any;
    updateItem():void {
        item[name] = "updated name";
        trigger = new Object();
    }
}

@Component({
    selector: 'compB',
    template:  template: `<p>{{item[name]}}</p>`
})
export class CompB implements OnInit{
    @Input() item: any;
    @Input() trigger: any;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 2016-08-06
    • 2021-09-16
    相关资源
    最近更新 更多