我目前正在使用Angular 2 RC4和新的表单API开发一个很长的表单。
我有自己的输入组件,并希望进一步处理验证。
我试图让我的验证器使用我的输入,但验证器更新组件InputFieldComponent而不是我的输入字段......
这是我的HTML:
<label [attr.for]="inputId"><ng-content></ng-content></label>
<small class="text-muted">{{helptext}}</small>
<small [hidden]="(input.valid) || (input.untouched && input.pristine)" class="text-danger">
{{errormsg}}
</small>
<input
class="form-control custom-input"
[id]="inputId"
[required]="required"
[type]="type"
[attr.name]="name"
[(ngModel)]="value"
[pattern]="pattern"
#input="ngModel"
>
通过
调用<custom-input-field
name="birthDate"
[(ngModel)]="model.birthDate"
placeholder="DD/MM/YYYY"
helptext="Date of birth"
required="true"
pattern="^[0-3]?[0-9]\/[01]?[0-9]\/[12][90][0-9][0-9]$"
errormsg="The date of birth is mandatory and should be entered as dd/mm/yyyy"
>
Date of birth
</custom-input-field>
这是我的代码:
import {
Component,
Input,
forwardRef,
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
const noop = () => {};
let nextUniqueId = 0;
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputFieldComponent),
multi: true
};
@Component({
moduleId: module.id,
selector: 'custom-input-field',
styleUrls: ['input-field.component.css'],
templateUrl: 'input-field.component.html',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class InputFieldComponent implements ControlValueAccessor {
//the external properties
@Input() id: string = `custom-field-${nextUniqueId++}`;
@Input() helptext: string = null;
@Input() placeholder: string = null;
@Input() required: boolean = false;
@Input() type: string = 'text';
@Input() name: string = null;
//The internal data model
private innerValue: any = '';
//Placeholders for the callbacks which are later provided
//by the Control Value Accessor
private onTouchedCallback: () => void = noop;
private onChangeCallback: (_: any) => void = noop;
//get accessor
get value(): any {
return this.innerValue;
};
//set accessor including call the onchange callback
set value(v: any) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
}
}
//From ControlValueAccessor interface
// The writeValue function allows you to update your internal model with incoming values,
// for example if you use ngModel to bind your control to data.
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
//NOTE: Both following functions are later provided by Angular 2 itself. But we need to register dummy functions to be
// able code and transpile it without errors.
//From ControlValueAccessor interface
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
//From ControlValueAccessor interface
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
//** Read-only properties */
get inputId(): string { return `${this.id}-input`; }
};
答案 0 :(得分:1)
我终于找到了解决方法来实现我想要的目标。
Expression 'xxxx' was changed after it was checked
)最后使用自定义组件阴影dom来测试组件是否有效并且它是否有效并使代码更轻。
这是我的自定义输入组件的代码及其CSS选择器
@Component({
moduleId: module.id,
selector: 'custom-input-field',
templateUrl: 'input-field.component.html',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
directives: [DefaultValueAccessor, NgModel],
host: {
'(click)': 'focus()',
'[class.custom-input]': 'true',
},
/**
* This styles the input error msg that is integrated into our component using the automatic classes
* that ngModel updates on the component.
*
* It uses the shadow-dom and therefore has to be declared line by line in the component file
* (does not seem to work with Sass transpiler)
*/
styles: [
`
:host.ng-touched.ng-invalid >>> input {
border-left: 5px solid #a94442; /* red */
}
:host.ng-touched.ng-valid >>> input {
border-left: 5px solid #42A948; /* green */
}
:host.ng-valid:not([required]).ng-touched.ng-dirty >>> input {
border-left: 5px solid #42A948; /* green */
}
:host.ng-pristine >>> .error-msg {
display:none;
}
:host.ng-valid >>> .error-msg {
display:none;
}
:host.ng-untouched >>> .error-msg {
display:none;
}
:host.ng-touched.ng-invalid >>> .error-msg {
display:inline;
}
.text-danger { font-weight: 500; }
}
`]
})
这里是模板内容(丰富了更多属性):
<label [attr.for]="inputId"><ng-content></ng-content></label>
<small class="text-muted">{{helptext}}</small>
<small class="error-msg text-danger">
<ng-content select="input-error"></ng-content>
</small>
<input #input
class="form-control custom-input"
[disabled]="disabled"
[id]="inputId"
[attr.list]="list"
[attr.max]="max"
[attr.maxlength]="maxLength"
[attr.min]="min"
[attr.minlength]="minLength"
[readonly]="readOnly"
[required]="required"
[spellcheck]="spellCheck"
[attr.step]="step"
[attr.tabindex]="tabIndex"
[type]="type"
[attr.name]="name"
(focus)="_handleFocus($event)"
(blur)="_handleBlur($event)"
(change)="_handleChange($event)"
[(ngModel)]="value"
>
我这样称呼我的组件:
<custom-input-field
name="birthDate"
[(ngModel)]="model.birthDate"
placeholder="JJ/MM/AAAA"
helptext="format jj/mm/aaaa"
#birthDate="ngModel"
required="true"
pattern="^[0-3]?[0-9]\/[01]?[0-9]\/[12][90][0-9][0-9]$"
>
Date of birth
<input-error><br />The date of birth is mandatory and should be entered as dd/mm/yyyy</input-error>
</custom-input-field>