【问题标题】:Angular2: Input setter not picking up set event if value does not changeAngular2:如果值没有改变,输入设置器不会拾取设置事件
【发布时间】:2017-05-02 16:08:23
【问题描述】:

在此处参考 Angular2 文档文件:[https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter] (Parent to child setter),我有以下子组件代码:

import { Component, Input } from '@angular/core';
@Component({
  selector: 'name-child',
  template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
  private _name = '';
  @Input()
  set name(name: string) {
    console.log("name change");
    this._name =  name;
  }
  get name(): string { return this._name; }
}

而父级很简单:

import { Component } from '@angular/core';
@Component({
  selector: 'name-parent',
  template: `
  <h2>Parent </h2>
  <name-child [name]="name"></name-child>
  `
})
export class NameParentComponent {
   // somewhere on ngOnInit, set name without changing value
    ngOnInit() { 

        // get pending paged only and so on
        setTimeout(() => {
            this.name = "a";
            setTimeout(() => {
                this.name = "a";
                setTimeout(() => {
                    this.name = "a";
                },1000);

            },1000);

        },1000);
   }
}

您希望控制台在 3 秒内注销“名称更改”三次。它没有,它只记录一次,并忽略后续集合(仅当值不变时才会发生这种情况)。无论值是否改变,如何让输入拾取设置事件?

【问题讨论】:

  • 您不会更改输入,而是一遍又一遍地发送相同的值。
  • 我知道,那为什么“setter”不起作用?
  • 我猜它会检查值是否发生了变化,因为没有,所以什么都没有发生
  • 这不是它与普通 setter 和 getter 的行为方式,只有当它附加到子组件时,我希望有办法以某种方式将该行为传递给子组件,我需要捕获集合事件,即使值没有改变
  • 这没有任何意义。如果输入没有改变,监听器不会触发。也许你应该传递另一个标志或其他东西作为输入。

标签: angular angular-components


【解决方案1】:

虽然 yurzui 的回答已经足够解释了,但如果它是一个可以使用的对象

let newObj = JSON.parse(JSON.stringify(oldObj))

它会触发setter事件

【讨论】:

    【解决方案2】:

    如果使用输入设置器是一项严格的要求,则不是肯定的,但是您是否尝试过使用 OnChanges?

    import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
    @Component({
      selector: 'name-child',
      template: '<h3>"{{name}}"</h3>'
    })
    export class NameChildComponent implements OnChanges {
      @Input() name;
    
      ngOnChanges(changes: SimpleChanges) {
        if (changes['name']) {
          console.log(`Is First Change: ${changes['name'].isFirstChange}`)
          console.log(`name change from ${changes['name'].previousValue} to ${changes['name'].currentValue}`);
        }
      }
    
    }
    

    【讨论】:

    • 我不知道您的角度版本是否与我的有所不同,但 isFirstChange 是一个函数,因此您必须调用 isFirstChange()
    【解决方案3】:

    你给出的文章明确说

    使用 setter 拦截输入属性更改

    当您想要实现的目标根本不是跟踪更改。它是关于从父母向孩子发送事件,这就是 RX Subject(其中 4 个中的任何一个)或 Angular2 EventEmitter 非常好的地方。

    您可以在父级中创建其中一个并将其传递给子级。然后,订阅后,您可以跟踪所有事件,无论其值如何。

    【讨论】:

    • 明白了,如果我只想抓属性设置怎么办?
    • 我想要的东西很多。但这并不意味着它是好的,也不意味着它是正确的。在 setter 中捕捉变化并不是传递事件的明显方式。但当然你是你应用程序的老板
    • 这就是重点,我不是试图捕捉变化,只是在原型设置时触发一个事件
    • 这就是重点:如果值相同,则 angular 不会设置它,因为 angular 仅用于更改。这样做是出于性能原因
    • 如果 Angular 传递了它,它触发了一个不必要的子组件change,这意味着它将被重新渲染。再次这样做是为了性能。这就是 angular 不设置属性的原因。你用new String() 选择的方式是一个丑陋的黑客,因为你不传递字符串而是传递一个对象String,当在JS 中比较时new String('1') === new String('1') 给出false,因为它是另一个对象'1' === '1'true。这是它起作用的唯一原因。
    【解决方案4】:

    我看到了两种解决方法:

    1) 使用不可变值

    setTimeout(() => {
      this.name = new String("a");
        setTimeout(() => {
          this.name =  new String("a");
          setTimeout(() => {
           this.name =  new String("a");
        }, 1000);
      }, 1000);
    }, 1000);
    

    2) 直接更改输入属性

    @ViewChild(NameChildComponent) child: NameChildComponent;
    
    setTimeout(() => {
      this.child.name = "a";
      setTimeout(() => {
        this.child.name = "a";
        setTimeout(() => {
          this.child.name = "a";
        }, 1000);
      }, 1000);
    }, 1000);
    

    【讨论】:

    • new String() 工作,很遗憾这是要走的路。如果您需要多次重用组件,则第二种方式有点过于突兀,它需要是无缝的。另一种方法是在进入可能再次设置它的过程之前简单地重置字符串。悲伤悲伤的故事。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多