【问题标题】:Why *Change EventEmitter listeners are emitted two times in Angular (custom two-way data binding property)?为什么 *Change EventEmitter 监听器在 Angular 中被发射两次(自定义双向数据绑定属性)?
【发布时间】:2018-09-08 00:11:06
【问题描述】:

这是在 Angular 中创建双向数据绑定的方法:https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html#creating-custom-two-way-data-bindings

例如我在一个组件中创建了counter 双向数据绑定属性。有用。现在我还想收到有关使用组件的counterChange 输出更改属性的通知。

这里是组件的代码:

export class CustomCounterComponent {

  counterValue = 0;
  @Output() counterChange = new EventEmitter();

  @Input()
  get counter() {
    return this.counterValue;
  }

  set counter(val) {
    this.counterValue = val;
    this.counterChange.emit(this.counterValue);
  }

  decrement() {
    this.counter--;
  }

  increment() {
    this.counter++;
  }
}

这是我的使用方法:

@Component({
  selector: 'my-app',
  template: `
    <custom-counter [(counter)]="counterValue" (counterChange)="onChange($event)"></custom-counter>
    <p><code>counterValue = {{counterValue}}</code></p>
  `
})
export class AppComponent {
  onChange(value) {
    console.log('onChange!', value)
  }
  counterValue = 5;
}

期望的行为:我希望 onChange 在值更改时被调用 1 次。

具体问题:onChange 每次值变化时都会被调用两次。

任何想法为什么它被称为 2 次?

另外,我有完整的 plunkr 示例:https://plnkr.co/edit/8HGXNhhYQRoLVJeDlqWK?p=preview。只需打开控制台并查看那里。

【问题讨论】:

    标签: angular


    【解决方案1】:

    编辑

    在深入挖掘之后,我发现了真正的问题。

    如果您在set counter 方法中设置断点并单击+ 按钮,您会看到它会触发两次。这就是为什么,它会发出两次事件,onChange 方法会被调用两次。

    另外,我检查了调用堆栈,看看set counter 是从哪里调用的。

    第一个,您可能会怀疑是this.counter++,这是预期的。

    看看第二个

    当您更改counter 时,它会触发角度和角度调用中的更改检测

    .counter = currVal_2
    

    再次触发set counter

    所以,我将 this.counterChange.emit(this.counterValue);set counter 移动到 decrementincrement 方法的内部。

      set counter() {
        return this.counterValue;
      }
    
      @Input()
      set counter(val) {
        this.counterValue = val;
      }
    
      decrement() {
        this.counter--;
        this.counterChange.emit(this.counterValue);
      }
    
      increment() {
        this.counter++;
        this.counterChange.emit(this.counterValue);
      }
    

    看看this

    ---------旧(部分错误)答案 -------------

    因为你已经在使用双向绑定和自己绑定方法了。

    [(counter)]="counterValue"[counter]="counterValue" (counterChange)="counterValue = $event" 的糖语法。所以,如果你想要自定义counterChange 方法,只需从[(counter)]="counterValue" 中删除()

    欲了解更多信息,take a look at the docs

    所以,改变

    <custom-counter [(counter)]="counterValue" (counterChange)="onChange($event)"></custom-counter>
    

    <custom-counter [counter]="counterValue" (counterChange)="onChange($event)"></custom-counter>
    

    您也可以删除(counterChange)="onChange($event)"

    试试这个,

    <custom-counter [(counter)]="counterValue"></custom-counter>
    

    【讨论】:

    • 这是有道理的。我不能只使用[(counter)],因为我需要以某种方式获得有关更改的通知。但是[*] + (*Change) 方式迫使我在*Change 处理程序中同步* 模型。这不酷。
    • 是的,完全正确。恐怕这是你必须接受的权衡。
    • 嗯等等。再看一个例子。如何做到这一点? stackblitz.com/edit/angular-yzhhrh 使用内部 ngModel 一切正常。如何做到这一点?
    • 我的回答可能有误。我简化了您的代码,它可以按您的意愿工作。看看这个plnkr.co/edit/nhLJF0GileOwuKycVSl5?p=preview。我会看看你的代码有什么问题
    • @SharikovVladislav 看看
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    相关资源
    最近更新 更多