Formcontrol不同值,通过valueAccessor.writeValue()设置值后保持不变
Formcontrol different value, stays unchanged after setting value via valueAccessor.writeValue()
问题与Formcontrol invalid state unchanged after setting value via valueAccessor.writeValue()相同。但是没有解决。你可以回复他post.
我的情况是这样。我有 phone 个指令:
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})/, '');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '-');
} else if (newVal.length <= 9) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
} else {
newVal = newVal.substring(0, 9);
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,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 通知 ControlValueAccessor
,后者负责通知 MODEL。
例如,当input
事件发生时,ControlValueAccessor
的onChange
方法将被调用。 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的值之间会有延迟。
值得一提的是,FormControl.setValue(val)
会将val
写入两个层,VIEW和MODEL层,但是如果我们使用这个,会有无限循环,因为 setValue()
内部调用 viewToModelUpdate
(因为必须更新模型),而 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})/, '');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '-');
} else if (newVal.length <= 9) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
} else {
newVal = newVal.substring(0, 9);
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
}
return newVal;
}
要点是您应该在 VIEW 层对输入值执行任何更改,然后再将更改后的值发送到 ControlValueAccessor
。
问题与Formcontrol invalid state unchanged after setting value via valueAccessor.writeValue()相同。但是没有解决。你可以回复他post.
我的情况是这样。我有 phone 个指令:
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})/, '');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '-');
} else if (newVal.length <= 9) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
} else {
newVal = newVal.substring(0, 9);
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,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 通知 ControlValueAccessor
,后者负责通知 MODEL。
例如,当input
事件发生时,ControlValueAccessor
的onChange
方法将被调用。 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的值之间会有延迟。
值得一提的是,FormControl.setValue(val)
会将val
写入两个层,VIEW和MODEL层,但是如果我们使用这个,会有无限循环,因为 setValue()
内部调用 viewToModelUpdate
(因为必须更新模型),而 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})/, '');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '-');
} else if (newVal.length <= 9) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
} else {
newVal = newVal.substring(0, 9);
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,3})/, '--');
}
return newVal;
}
要点是您应该在 VIEW 层对输入值执行任何更改,然后再将更改后的值发送到 ControlValueAccessor
。