Angular ControlValueAccessor registerOnChange回调被覆盖

时间:2017-03-31 16:52:52

标签: angular typescript

更新:Link to Plunker

遇到一个奇怪的问题。我正在使用Angular 2.4.1。组件最初加载时,值setter运行并且onChangeCallback正确触发。但是,我是控制台记录onChangeCallback,在最初设置之后,它被替换为匿名函数。

以下是console.log的结果:

  1. function(_){}
  2. function(newValue){                 dir.viewToModelUpdate(NEWVALUE);                 control.markAsDirty();                 control.setValue(newValue,{emitModelToViewChange:false});             }

  3. function(_){}

  4. 第一个发生在页面加载,紧接着是2.我假设Angular正在处理令牌并且此时正确实现ControlValueAccessor。当我然后对select元素进行更改时,onChangeCallback再次被称为匿名函数,而没有添加ControlValueAccessor。

    有关如何解决此问题的任何想法?只有这种形式控制才能解决这个问题。

    import { Component, Input, Output, EventEmitter, forwardRef, ViewChild, ElementRef, Renderer, ChangeDetectorRef, OnChanges } from '@angular/core';
    import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
    
    @Component({
      selector: 'select-resizable',
      template:`
        <select #mainSelectElement [(ngModel)]="value" (change)="updateSelected($event.target.value)" style="width: initial;">
          <ng-content></ng-content>
        </select>
        <select class="usa-sr-only" aria-hidden="true" role="presentation" #hiddenSelectElement style="width: initial;">
          <option>{{value}}</option>
        </select>
      `,
      providers: [
        { provide: NG_VALUE_ACCESSOR, useClass: forwardRef(() => SelectResizableComponent), multi: true }
      ]
    })
    export class SelectResizableComponent implements ControlValueAccessor {
    
      @ViewChild('hiddenSelectElement') hiddenSelectElement: ElementRef;
      @ViewChild('mainSelectElement') mainSelectElement: ElementRef; 
    
      private _selected: any;
    
      private onChangeCallback: (_: any) => void = (_: any) => {};
      private onTouchedCallback: () => void = () => {};
    
      get value(): any {
        return this._selected;
      }
    
      set value(val: any) {
        this._selected = val;
        this.onChangeCallback(val);
        console.log(this.onChangeCallback);
      }
    
      constructor(private renderer: Renderer, private ref: ChangeDetectorRef) {}
    
      updateSelected(event) {
        this.ref.detectChanges();
        const width = (this.hiddenSelectElement.nativeElement.clientWidth * 1.02) + 'px';
        this.renderer.setElementStyle(this.mainSelectElement.nativeElement, 'width', width);
      }
    
      writeValue(val: any) {
        this.value = val;
      }
    
      registerOnChange(fn: any) {
        this.onChangeCallback = fn;
      }
    
      registerOnTouched(fn: any) {
        this.onTouchedCallback = fn;
      }
    }
    

1 个答案:

答案 0 :(得分:2)

  providers: [
    { provide: NG_VALUE_ACCESSOR, useClass: forwardRef(() => SelectResizableComponent), multi: true }
  ]

问题就在那里。我使用useClass而不是useExisting提供了令牌。因此,在实例化组件之后,从NG_VALUE_ACCESSOR标记的组件类创建了一个新值。

感谢Adam,因为他发现我有两个值。