触摸/未触摸未在自定义输入组件中更新 - Angular 2 [英] touched/untouched not updating in custom input component - Angular 2
问题描述
我有一个自定义输入组件,它正在更新验证和状态,但触摸/未触摸除外.其他所有状态(原始/脏)都按预期工作.
这是一个 plunker:https://plnkr.co/edit/O9KWzwhjvySnXd7vyo71
import { Component, OnInit, Input, ElementRef, forwardRef, Renderer } from '@angular/core';import { REACTIVE_FORM_DIRECTIVES, Validator, Validators, NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';导出 const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any =/*@ts2dart_const*/{提供:NG_VALUE_ACCESSOR,useExisting: forwardRef(() => CustomInputComponent),多:真};const noop = () =>{};@成分({选择器:'我的自定义输入',提供者:[CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],模板:`<div class="form-group"><label>自定义输入</label><input type="text" class="form-control" [(ngModel)]="value" required><p *ngIf="control.errors.required && control.touched">必填字段</p><strong>输入是否被触摸:{{control.touched ?是":否"}}</strong><br><strong>输入是否不变:{{control.untouched ?是":否"}}</strong><br><strong>输入是否脏:{{control.dirty ?'是' : '否'}}</strong><br><strong>输入是否原始:{{control.pristine ?'是' : '否'}}</strong>
<div>在自定义组件中:{{value}}
`})导出类 CustomInputComponent 实现 ControlValueAccessor {@Input() 控件;//内部数据模型私有_值:任何 = '';//回调占位符私人 _onTouchedCallback: (_:any) =>void = noop;私人 _onChangeCallback: (_:any) =>void = noop;//获取访问器get value(): any { return this._value;};//设置访问器包括调用onchange回调设置值(v:任何){如果 (v !== this._value) {this._value = v;this._onChangeCallback(v);}}//设置触摸模糊onTouched(){this._onTouchedCallback(null);}//来自ControlValueAccessor接口写值(值:任何){this._value = 值;}//来自ControlValueAccessor接口registerOnChange(fn: 任何) {this._onChangeCallback = fn;}//来自ControlValueAccessor接口registerOnTouched(fn: any) {this._onTouchedCallback = fn;}}
感谢您的帮助!
刚刚踩到@sharpmachine 的回答,它帮助解决了我的问题.我只是想改进它:
不必在模板级别(可能容易出错)将 blur
事件绑定到 onTouched()
,而是可以公开 ControlValueAccessor
作为 Directive
并在那里绑定事件.
import { Directive, forwardRef } from '@angular/core';从@angular/forms"导入 { ControlValueAccessor, NG_VALUE_ACCESSOR };导出 const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {提供:NG_VALUE_ACCESSOR,useExisting: forwardRef(() => CustomInputAccessor),多:真};@指示({选择器:'我的自定义输入',主持人:{'(模糊)':'onTouched($event)'},提供者:[CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],})导出类 CustomInputAccessor 实现 ControlValueAccessor {//内部数据模型私有_值:任何 = '';公共 onChange: any = (_) =>{/*空的*/}公开 onTouched: any = () =>{/*空的*/}get value(): any { return this._value;};设置值(v:任何){如果 (v !== this._value) {this._value = v;this.onChange(v);}}写值(值:任何){this._value = 值;}registerOnChange(fn: 任何) {this.onChange = fn;}registerOnTouched(fn: any) {this.onTouched = fn;}}
这样你应该能够使用组件,而不必每次使用它时都绑定 blur
事件.
希望有帮助!
I have a custom input component that is updating validation and states with the exception of touched/untouched. Everything else state-wise (pristine/dirty) works as expected.
Here's a plunker: https://plnkr.co/edit/O9KWzwhjvySnXd7vyo71
import { Component, OnInit, Input, ElementRef, forwardRef, Renderer } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES, Validator, Validators, NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = /*@ts2dart_const*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
};
const noop = () => {};
@Component({
selector: 'my-custom-input',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
template: `
<div class="form-group">
<label>CUSTOM INPUT</label>
<input type="text" class="form-control" [(ngModel)]="value" required>
<p *ngIf="control.errors.required && control.touched">Field is required</p>
<strong>Has input been touched: {{control.touched ? 'Yes' : 'No'}}</strong><br>
<strong>Is input untouched: {{control.untouched ? 'Yes' : 'No'}}</strong><br>
<strong>Is input dirty: {{control.dirty ? 'Yes' : 'No'}}</strong> <br>
<strong>Is input pristine: {{control.pristine ? 'Yes' : 'No'}}</strong>
</div>
<div>
In Custom Component: {{value}}
</div>
`
})
export class CustomInputComponent implements ControlValueAccessor {
@Input() control;
// The internal data model
private _value: any = '';
//Placeholders for the callbacks
private _onTouchedCallback: (_:any) => void = noop;
private _onChangeCallback: (_:any) => void = noop;
//get accessor
get value(): any { return this._value; };
//set accessor including call the onchange callback
set value(v: any) {
if (v !== this._value) {
this._value = v;
this._onChangeCallback(v);
}
}
//Set touched on blur
onTouched(){
this._onTouchedCallback(null);
}
//From ControlValueAccessor interface
writeValue(value: any) {
this._value = value;
}
//From ControlValueAccessor interface
registerOnChange(fn: any) {
this._onChangeCallback = fn;
}
//From ControlValueAccessor interface
registerOnTouched(fn: any) {
this._onTouchedCallback = fn;
}
}
Thanks for any help!
Just stepped on @sharpmachine answer and it helped to solve my problem. I just would like to improve it:
Instead of having to bind the blur
event to onTouched()
at the template level (which can be error-prone) it is possible to expose the ControlValueAccessor
as a Directive
and bind the event there.
import { Directive, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputAccessor),
multi: true
};
@Directive({
selector: 'my-custom-input',
host: {'(blur)': 'onTouched($event)'},
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
})
export class CustomInputAccessor implements ControlValueAccessor {
// The internal data model
private _value: any = '';
public onChange: any = (_) => { /*Empty*/ }
public onTouched: any = () => { /*Empty*/ }
get value(): any { return this._value; };
set value(v: any) {
if (v !== this._value) {
this._value = v;
this.onChange(v);
}
}
writeValue(value: any) {
this._value = value;
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
This way you should be able to use the component without having to bind the blur
event each time you use it.
Hope it helps!
这篇关于触摸/未触摸未在自定义输入组件中更新 - Angular 2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!