Formcontrol不同的值,通过valueAccessor.writeValue设置值后保持不变

问题描述

问题与Formcontrol invalid state unchanged after setting value via valueAccessor.writeValue()相同。但是没有解决。您可以在他的帖子上回复

就我而言,这很不错。我有电话号码的指示:

import { Directive,HostListener,ChangeDetectionStrategy } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[phonemask]'
})
export class PhoneDirective {

  constructor(public ngControl: NgControl) { }

  @HostListener('ngModelChange',['$event'])
  onModelChange(event){
    this.onInputChange(event,false);
  }

  @HostListener('keydown.backspace',['$event'])
  keydownBackspace(event){
    this.onInputChange(event.target.value,true);
  }

  onInputChange(event,backspace){
    let newVal = event.replace(/\D/g,'');
    if (backspace && newVal.length <= 6) {
      newVal = newVal.substring(0,newVal.length - 1);
    }
    if (newVal.length === 0) {
      newVal = '';
    } else if (newVal.length <= 3) {
      newVal = newVal.replace(/^(\d{0,3})/,'$1');
    } else if (newVal.length <= 6) {
      newVal = newVal.replace(/^(\d{0,3})(\d{0,'$1-$2');
    } else if (newVal.length <= 9) {
      newVal = newVal.replace(/^(\d{0,'$1-$2-$3');
    } else {
      newVal = newVal.substring(0,9);
      newVal = newVal.replace(/^(\d{0,'$1-$2-$3');
    }
    this.ngControl.valueAccessor.writeValue(newVal);
    console.log(newVal);
    console.log(this.ngControl.value)
  }
}

问题是在某些情况下console.log(newVal); console.log(this.ngControl.value)具有不同的值。

例如

111-1
1111

111-111-111
111-111-1111

解决方法

引自this answer

Angular具有某些元素的默认值访问器,例如input type='text'input type='checkbox'等...

ControlValueAccessor是VIEW层和MODEL层之间的中间人。当用户输入内容时,VIEW会通知ControlValueAccessorinput的工作是通知模型。

例如,发生onChange事件时,将调用ControlValueAccessor的{​​{1}}方法。 Here's how onChange看上去像是每个 ControlValueAccessor

function setUpViewChangePipeline(control: FormControl,dir: NgControl): void {
  dir.valueAccessor!.registerOnChange((newValue: any) => {
    control._pendingValue = newValue;
    control._pendingChange = true;
    control._pendingDirty = true;

    if (control.updateOn === 'change') updateControl(control,dir);
  });
}

魔术发生在updateControl

function updateControl(control: FormControl,dir: NgControl): void {
  if (control._pendingDirty) control.markAsDirty();
  control.setValue(control._pendingValue,{emitModelToViewChange: false});
 
  // !
  dir.viewToModelUpdate(control._pendingValue);
  control._pendingChange = false;
}

dir.viewToModelUpdate(control._pendingValue);是在自定义指令中调用ngModelChange事件的原因。这意味着模型值是来自输入的值(小写)。并且由于ControlValueAccessor.writeValue 将值写入VIEW,因此VIEW的值和MODEL的值之间会有一个 delay

值得一提的是,FormControl.setValue(val)会将val写入和图层,但是如果我们使用它,将会有一个 infinite循环,因为setValue()内部调用viewToModelUpdate(因为必须更新MODEL),而viewToModelUpdate调用setValue()


因此,可能的解决方案是将该代码段添加到您的指令中:

ngOnInit () {
  const initialOnChange = (this.ngControl.valueAccessor as any).onChange;

  (this.ngControl.valueAccessor as any).onChange = (value) => initialOnChange(this.makeChangesToInput(value));
}

@HostListener('ngModelChange',['$event'])
onModelChange(event){
  this.ngControl.valueAccessor.writeValue(this.makeChangesToInput(event,false));
}

@HostListener('keydown.backspace',['$event'])
keydownBackspace(event){
  this.ngControl.control.setValue(this.makeChangesToInput(event,true));

  // if you want the `ngModelChange` handler from above to be called
  // this.ngControl.control.setValue(this.makeChangesToInput(event,true),{ emitViewToModelChange: true }); 
}

makeChangesToInput(value,backspace){
  let newVal = event.replace(/\D/g,'');
  if (backspace && newVal.length <= 6) {
    newVal = newVal.substring(0,newVal.length - 1);
  }
  if (newVal.length === 0) {
    newVal = '';
  } else if (newVal.length <= 3) {
    newVal = newVal.replace(/^(\d{0,3})/,'$1');
  } else if (newVal.length <= 6) {
    newVal = newVal.replace(/^(\d{0,3})(\d{0,'$1-$2');
  } else if (newVal.length <= 9) {
    newVal = newVal.replace(/^(\d{0,'$1-$2-$3');
  } else {
    newVal = newVal.substring(0,9);
    newVal = newVal.replace(/^(\d{0,'$1-$2-$3');
  }

  return newVal;
}

要点是,在将更改后的值发送到ControlValueAccessor之前,应该在VIEW层上对输入值进行任何更改。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...