我有一个自定义<data-input-text>
组件,它有两种模式:常规和禁用。这是模板(我在演示案例中对其进行了简化):
<label *ngIf="!disabled"
class="field-label"
[ngClass]="{'focused' : isFocused, 'with-errors' : errors}">
<input class="field-value"
[type]="type"
[required]="required"
(focus)="onFocus()"
(blur)="onBlur()"
[(ngModel)]="value"
#fieldInput="ngModel">
</label>
<div class="field-label" *ngIf="disabled">
<span class="field-value">{{ value }}</span>
<span class="field-name">{{ label }}</span>
</div>
在父表单中,我按以下方式使用此组件:
<form #profileForm="ngForm">
<data-text-input
label="lastName"
[required]="true"
[disabled]="userIsRegistered"
name="lastName"
ngModel></data-text-input>
</form>
userIsRegistered
返回一个布尔值,它应该在组件中的输入字段或跨度之间切换。这一切都很好,直到这里。
我在父组件中设置表单以匹配BehaviorSubject,如下所示:
this._sub = this.dl.selectedEmployee.subscribe( u => {
if ( u.id ) {
this.isLoading = false;
setTimeout( () => {
this.profileForm.setValue(u);
this.profileForm.control.markAsPristine();
}, 10);
}
});
以下是自定义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;
}
}
表格中也使用其他组件(如颜色选择器和ng-select)。
所以奇怪的是这个。表单值设置正常。没有错误。这些值在数据文本输入组件以及表单中的其他组件中正确显示(disabled
和!disabled
)。奇怪的是,当我使用调试器检查this.profileForm
对象时,controls
属性具有所有控件及其各自的值,但是表单的value
属性错过了这些,其中disabled
属性(也称为无输入字段)设置为true。
以下是Plunker:https://plnkr.co/edit/nbWQZzQjhGae622CanGa?p=preview
有什么想法吗?
答案 0 :(得分:0)
嗯,这一点并不明显,直到我找到了将值设置为this.messaging.getToken()
.then(oldToken => {
this.messaging.deleteToken(oldToken).then(() => {
this.messaging.getToken().then(newToken => {
this.updateToken(newToken)
})
})
})
的方式,事实证明,使用变量名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
也是一个可以在别处检查的属性,也是一个TypeScript接口 - 而且,tada,它可以工作。 / p>