Javascript 模板驱动表单中的自定义ControlValueAccessor
我有一个自定义的Javascript 模板驱动表单中的自定义ControlValueAccessor,javascript,angular,angular2-template,angular2-forms,Javascript,Angular,Angular2 Template,Angular2 Forms,我有一个自定义的组件,它有两种模式:常规模式和禁用模式。这是模板(我对它进行了一些简化,用于演示案例): 以下是自定义ControlValueAccessor组件: import { Component, Input, ViewChild, forwardRef, AfterViewInit, OnInit, OnChanges, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALI
组件,它有两种模式:常规模式和禁用模式。这是模板(我对它进行了一些简化,用于演示案例):
以下是自定义ControlValueAccessor组件:
import { Component, Input, ViewChild, forwardRef,
AfterViewInit, OnInit, OnChanges,
NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS,
ControlValueAccessor, FormControl,
Validator, NgForm } from '@angular/forms';
@Component({
selector: 'data-text-input',
template: `
<label *ngIf="!disabled"
class="field-label">
<input class="field-value"
[type]="type"
[required]="required"
(blur)="onBlur()"
[(ngModel)]="value"
#fieldValue="ngModel">
<span class="field-name">{{ label }}</span>
</label>
<div class="field-label" *ngIf="disabled">
<span class="field-value">{{ value }}</span>
<span class="field-name">{{ label }}</span>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef( ()=> DataTextInputComponent ),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef( ()=> DataTextInputComponent ),
multi: true
}
]
})
export class DataTextInputComponent implements OnChanges, ControlValueAccessor, Validator {
@Input() public disabled: boolean = false;
@Input() public label: string;
@Input() public required: boolean = false;
@Input() public type: string = 'text';
@ViewChild('fieldValue') public fieldValue: FormControl;
// infrastructure
public registerOnChange(fn: any) { this.propagateChange = fn; }
public registerOnTouched(fn: any) { this.propagateTouch = fn; }
private propagateChange = (_: any) => { };
private propagateTouch = (_: any) => { };
/**
* inner value
*/
private innerValue: any = null;
/**
* on changes hook
*/
public ngOnChanges(): void {
if ( this.disabled ) {
this.propagateChange(this.innerValue);
}
}
/**
* input events
*/
public onBlur(): void {
this.propagateChange(this.innerValue);
this.propagateTouch(true);
}
/**
* value accessor setter and getter
*/
public get value(): any {
return this.innerValue;
};
public set value(value: any) {
if ( value !== 'undefined' ) {
this.innerValue = value;
this.propagateChange(value);
this.propagateTouch(true);
}
}
/**
* value accessor implementation
* @param value
*/
public writeValue(value: any): void {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
/**
* validation
* @param c
*/
public validate(c: FormControl) {
return this.errors = (this.disabled) ? null : this.customValidate(c);
}
private customValidate(c: FormControl): {} {
if ( c.touched ) {
// some validation logic which is not relevant here;
return null;
}
return null;
}
}
import{Component,Input,ViewChild,forwardRef,
AfterViewInit、OnInit、OnChanges、,
NgModule}来自“@angular/core”;
导入{NG_值存取器、NG_校验器、,
ControlValueAccessor,FormControl,
验证程序,NgForm}来自“@angular/forms”;
@组成部分({
选择器:“数据文本输入”,
模板:`
{{label}}
{{value}}
{{label}}
`,
供应商:[
{
提供:NG_值访问器,
useExisting:forwardRef(()=>DataTextInputComponent),
多:真的
},
{
提供:NG_验证器,
useExisting:forwardRef(()=>DataTextInputComponent),
多:真的
}
]
})
导出类DataTextInputComponent实现OnChanges、ControlValueAccessor、Validator{
@Input()公共禁用:布尔值=false;
@Input()公共标签:字符串;
@Input()public required:boolean=false;
@Input()公共类型:string='text';
@ViewChild('fieldValue')公共字段值:FormControl;
//基础设施
公共注册表更改(fn:any){this.propagateChange=fn;}
公共注册表(fn:any){this.propagateTouch=fn;}
私有更改=((uu:any)=>{};
private-propagateTouch=(uuq:any)=>{};
/**
*内在价值
*/
私有innerValue:any=null;
/**
*上钩
*/
public ngOnChanges():void{
如果(此项已禁用){
this.propagateChange(this.innerValue);
}
}
/**
*输入事件
*/
public onBlur():void{
this.propagateChange(this.innerValue);
这是真的;
}
/**
*值访问器setter和getter
*/
public get value():any{
返回此.innerValue;
};
公共设置值(值:任意){
如果(值!=“未定义”){
this.innerValue=值;
这是一个变化(值);
这是真的;
}
}
/**
*值存取器实现
*@param值
*/
public writeValue(值:any):void{
if(值!==此.innerValue){
this.innerValue=值;
}
}
/**
*验证
*@param c
*/
公共验证(c:FormControl){
返回this.errors=(this.disabled)?null:this.customValidate(c);
}
私有customValidate(c:FormControl):{}{
如果(c.触摸){
//此处不相关的一些验证逻辑;
返回null;
}
返回null;
}
}
表单中还使用了其他组件(如颜色选择器和ng select)
奇怪的是这个。表单值设置正确。没有错误。数据文本输入组件以及表单中的其他组件中的值均正确显示(对于禁用的<代码>和禁用的<代码>!禁用的<代码>)。奇怪的是,当我使用调试器检查this.profileForm
对象时,控件
属性具有所有控件及其各自的值,但是表单的值
属性忽略了这些控件,其中禁用
属性(也称为无输入字段)设置为true
这是普朗克:
有什么想法吗?嗯,这并不明显,直到我找到了将值设置到
AbstractControl.prototype.updateValueAndValidity的方法,结果证明,在这里使用变量名disabled
是个坏主意:
<form #profileForm="ngForm">
<data-text-input
label="lastName"
[required]="true"
[disabled]="userIsRegistered"
name="lastName"
ngModel></data-text-input>
</form>
我已将disabled
属性重命名为isReadOnly
,“因为readonly
也是一个可以在别处检查的属性,也是一个TypeScript界面,而且,塔达,它可以工作。我在代码中没有看到电子邮件控件。”。你能创建一个plunker来演示你的问题吗?我已经用plunker更新了这个问题,你需要在这里发布所有显示问题的代码,而不是一个明天可以改变或消失的plunker,在将来对任何人都没有帮助:@Rob,你是否因为规则而否决了这个问题?如果是,请再次投票,因为我已经纠正了这两点。我不希望讨论朝着错误的方向发展。你需要在你的物品中添加与解决这个问题相关的任何东西。然后您可以完全移除plunker链接。我没有投反对票
this._sub = this.dl.selectedEmployee.subscribe( u => {
if ( u.id ) {
this.isLoading = false;
setTimeout( () => {
this.profileForm.setValue(u);
this.profileForm.control.markAsPristine();
}, 10);
}
});
import { Component, Input, ViewChild, forwardRef,
AfterViewInit, OnInit, OnChanges,
NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS,
ControlValueAccessor, FormControl,
Validator, NgForm } from '@angular/forms';
@Component({
selector: 'data-text-input',
template: `
<label *ngIf="!disabled"
class="field-label">
<input class="field-value"
[type]="type"
[required]="required"
(blur)="onBlur()"
[(ngModel)]="value"
#fieldValue="ngModel">
<span class="field-name">{{ label }}</span>
</label>
<div class="field-label" *ngIf="disabled">
<span class="field-value">{{ value }}</span>
<span class="field-name">{{ label }}</span>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef( ()=> DataTextInputComponent ),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef( ()=> DataTextInputComponent ),
multi: true
}
]
})
export class DataTextInputComponent implements OnChanges, ControlValueAccessor, Validator {
@Input() public disabled: boolean = false;
@Input() public label: string;
@Input() public required: boolean = false;
@Input() public type: string = 'text';
@ViewChild('fieldValue') public fieldValue: FormControl;
// infrastructure
public registerOnChange(fn: any) { this.propagateChange = fn; }
public registerOnTouched(fn: any) { this.propagateTouch = fn; }
private propagateChange = (_: any) => { };
private propagateTouch = (_: any) => { };
/**
* inner value
*/
private innerValue: any = null;
/**
* on changes hook
*/
public ngOnChanges(): void {
if ( this.disabled ) {
this.propagateChange(this.innerValue);
}
}
/**
* input events
*/
public onBlur(): void {
this.propagateChange(this.innerValue);
this.propagateTouch(true);
}
/**
* value accessor setter and getter
*/
public get value(): any {
return this.innerValue;
};
public set value(value: any) {
if ( value !== 'undefined' ) {
this.innerValue = value;
this.propagateChange(value);
this.propagateTouch(true);
}
}
/**
* value accessor implementation
* @param value
*/
public writeValue(value: any): void {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
/**
* validation
* @param c
*/
public validate(c: FormControl) {
return this.errors = (this.disabled) ? null : this.customValidate(c);
}
private customValidate(c: FormControl): {} {
if ( c.touched ) {
// some validation logic which is not relevant here;
return null;
}
return null;
}
}
<form #profileForm="ngForm">
<data-text-input
label="lastName"
[required]="true"
[disabled]="userIsRegistered"
name="lastName"
ngModel></data-text-input>
</form>