Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 未更新ControlValueAccessor ngModel_Angular_Angular Forms_Angular2 Ngmodel_Controlvalueaccessor - Fatal编程技术网

Angular 未更新ControlValueAccessor ngModel

Angular 未更新ControlValueAccessor ngModel,angular,angular-forms,angular2-ngmodel,controlvalueaccessor,Angular,Angular Forms,Angular2 Ngmodel,Controlvalueaccessor,这是一个简单的自定义表单控件 @Component({ selector: 'app-custom-control', template: ` {{ value }} <input [ngModel]="value" (ngModelChange)="onChange($event)"> `, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() =&g

这是一个简单的自定义表单控件

@Component({
  selector: 'app-custom-control',
  template: `
    {{ value }}
    <input [ngModel]="value" (ngModelChange)="onChange($event)">
  `,
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomControlComponent),
    multi: true,
  }]
})
export class CustomControlComponent implements ControlValueAccessor {

  private value: any;

  private onChange: (val) => void;
  private onTouch: () => void;

  writeValue(value: any) {
    this.value = value;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }
}
@组件({
选择器:“应用程序自定义控件”,
模板:`
{{value}}
`,
供应商:[{
提供:NG_值访问器,
useExisting:forwardRef(()=>CustomControlComponent),
多:是的,
}]
})
导出类CustomControlComponent实现ControlValueAccessor{
私人价值:任何;
私有变更:(val)=>无效;
私有onTouch:()=>无效;
writeValue(值:任意){
这个值=值;
}
注册变更(fn:任何):无效{
this.onChange=fn;
}
注册人(fn:任何):无效{
this.onTouch=fn;
}
}
使用方法如下:

@Component({
  selector: 'my-app',
  template: `
    <app-custom-control
      [ngModel]="model"
      (ngModelChange)="onChange($event)">
    </app-custom-control>
    <input [ngModel]="model" (ngModelChange)="onChange($event)">
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  model = 'hello';

  onChange(value) {
    this.model = value;
  }
}
@组件({
选择器:“我的应用程序”,
模板:`

编辑:

通过更简单的示例(无内部输入)可以看到实际问题:

@组件({
选择器:“应用程序自定义控件”,
模板:`
{{value}}
设置新值
`,
供应商:[{
提供:NG_值访问器,
useExisting:forwardRef(()=>CustomControlComponent),
多:是的,
}]
})
导出类CustomControlComponent实现ControlValueAccessor{
价值:任何;
onChange:(val)=>无效;
未触及:()=>无效;
writeValue(值:任意){
这个值=值;
}
注册变更(fn:任何):无效{
this.onChange=fn;
}
注册人(fn:任何):无效{
this.ontoched=fn;
}
}

单击自定义控件内的按钮后,将更新父控件上的属性值,但不更新ngModel。例如:

要使其正常工作,您必须对驻留在
自定义控件.component.ts中的输入使用香蕉在框中的语法

自定义控件.component.ts


这是因为当您在外部输入中键入时,将执行
CustomControlComponent
ControlValueAccessor.writeValue()
,这反过来将更新内部输入

让我们把它分成几个小步骤

1) 输入外部输入

2) 更改检测被触发

3) 最终将到达
NgModel
指令中的
ngochanges
(该指令绑定到
自定义控件
),这将导致
FormControl
实例在下一次勾选中更新

@指令({
选择器:'[ngModel]:not([formControlName]):not([formControlName]),
提供程序:[formControlBinding],
exportAs:'ngModel'
})
导出类NgModel扩展了NgControl实现的OnChanges,
探空{
/* ... */
ngOnChanges(更改:SimpleChanges){
这是一个错误;
如果(!this._注册)this._setUpControl();
如果(变更中的“isDisabled”){
此._已更新禁用(更改);
}
如果(iPropertyUpdated(更改,此.viewModel)){
this.\u updateValue(this.model);
this.viewModel=this.model;
}
/* ... */
private\u updateValue(值:any):void{
那么我同意了(
()=>{this.control.setValue(值,{emitViewToModelChange:false});
});
}
}
}
4)
FormControl.setValue()
将调用已注册的更改函数回调,该回调将依次调用
ControlValueAccessor.writeValue

control.registerChange((newValue:any,emitModelEvent:boolean)=>{
//控件->视图
dir.valueAccessor!.writeValue(newValue);
//控制模式
if(emitModelEvent)dir.viewtomodeUpdate(newValue);
});
其中
dir.valueAccessor!.writeValue(newValue)
将是
CustomControlComponent.writeValue
函数

writeValue(值:任意){
这个值=值;
}
这就是你的内部输入被外部输入更新的原因


现在,为什么不反过来呢

当您在内部输入中键入时,它将仅调用其
onChange
函数,如下所示:

函数setUpViewChangePipeline(控件:FormControl,dir:NgControl):无效{
dir.valueAccessor!.registerChange((newValue:any)=>{
控件。_pendingValue=新值;
控件。_pendingChange=true;
控件。_pendingDirty=true;
if(control.updateOn==='change')updateControl(control,dir);
});
}
这将再次启动
updateControl
功能

函数updateControl(控件:FormControl,dir:NgControl):void{
if(control._pendingDirty)control.markAsDirty();
control.setValue(control._pendingValue,{emitModelToViewChange:false});
方向视图更新(控制待定值);
控件。_pendingChange=false;
}
查看
updateControl
,您将看到它具有
{emitModelToViewChange:false}
标志。查看
FormControl.setValue()
,我们将看到该标志阻止内部输入被更新

setValue(值:任意,选项:{
只有你自己?:布尔值,
emitEvent?:布尔值,
emitModelToViewChange?:布尔值,
emitViewToModelChange?:布尔值
}={}):无效{
(这是{value:any})。value=this。_pendingValue=value;
//这里!
if(this.\u onChange.length&&options.emitModelToViewChange!==false){
这是一个很好的例子(
(changeFn)=>changeFn(this.value,options.emitViewToModelChange!==false));
}
此.updateValue和Validity(选项);
}
实际上,只有内部输入没有更新,但是绑定到该输入的
FormControl
实例被更新。这可以通过以下操作看到:

custom-control.component.html
{{value}
{i.control.value | json}

您的答案确实正确,谢谢。但实际问题并不是内部输入的ngModel。我编辑了这个问题以澄清问题所在。@БССССююа,我的答案中揭示了发生这种情况的原因。为了解决更新后的问题,您将
@Component({
  selector: 'app-custom-control',
  template: `
    {{ value }}
    <button (click)="onChange('new value')">set new value</button>
  `,
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomControlComponent),
    multi: true,
  }]
})
export class CustomControlComponent implements ControlValueAccessor {

  value: any;

  onChange: (val) => void;
  onTouched: () => void;

  writeValue(value: any) {
    this.value = value;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
}