Validation Angular2-创建一个可重用、经过验证的文本输入组件
我正在创建一个带有节点后端的Angular2应用程序。我将有表格,提交数据到所说的后端。我希望在客户端和服务器端都进行验证,并且我希望避免重复这些验证规则 上述内容与实际问题有些无关,只是说这就是我不使用传统Angular2验证方法的原因 这就给我留下了以下HTML结构:Validation Angular2-创建一个可重用、经过验证的文本输入组件,validation,angular,Validation,Angular,我正在创建一个带有节点后端的Angular2应用程序。我将有表格,提交数据到所说的后端。我希望在客户端和服务器端都进行验证,并且我希望避免重复这些验证规则 上述内容与实际问题有些无关,只是说这就是我不使用传统Angular2验证方法的原因 这就给我留下了以下HTML结构: <div class="form-group" [class.has-error]="hasError(name)"> <label class="control-label" for="name"&
<div class="form-group" [class.has-error]="hasError(name)">
<label class="control-label" for="name"> Property Name
<input id="name" class="form-control" type="text" name="name" [(ngModel)]="property.name" #name="ngModel" />
<div class="alert alert-danger" *ngIf="hasError(name)">{{errors.name}}</div>
</div>
<div class="form-group" [class.has-error]="hasError(address1)">
<label class="control-label" for="address1"> Address
<input id="address1" class="form-control" type="text" name="address1" [(ngModel)]="property.address.address1" #address1="ngModel" />
<div class="alert alert-danger" *ngIf="hasError(address1)">{{errors['address.address1']}}</div>
</div>
属性名
{{errors.name}
地址
{{errors['address.address1']}
我将有一些大的形式,并希望减少上述的冗长。我希望实现类似以下目标:
<my-text-input label="Property Name" [(ngModel)]="property.name" name="name"></my-text-input>
<my-text-input label="Address" [(ngModel)]="property.address.address1" name="address1" key="address.address1"></my-text-input>
我在努力实现这一目标时步履蹒跚。给我带来麻烦的部分有:
- 在
上设置双向绑定(我在组件中所做的更改不会反映回父级)ngModel
- 基于组件的
变量生成模板引用变量(@输入
和#name
属性)。#address1
- 我突然想到,也许我不需要为组件的每个实例使用单独的模板引用变量名。也许我可以直接使用
,因为它只从该组件中引用。想法#input
- 我突然想到,也许我不需要为组件的每个实例使用单独的模板引用变量名。也许我可以直接使用
- 我可以将
或错误
对象传递给组件的每个实例进行验证,但我希望减少重复李>约束
我意识到这是一个有点宽泛的问题,但我相信一个好的答案对很多用户来说都是非常有用和有价值的,因为这是一个常见的场景。我也意识到我并没有实际展示我所做的尝试(只是解释说我确实已经自己努力解决了这个问题),但我故意忽略了我所做尝试的代码示例,因为我相信必须有一个干净的解决方案来实现这一点,我不希望答案只是对我丑陋的,非正统代码。我想您需要的是自定义表单控件。它可以做你提到的所有事情,并大大减少冗长。这是一个很大的课题,我不是专家,但这里是一个很好的起点: 示例解决方案: propertyEdit.component.ts:
import {Component, DoCheck} from '@angular/core';
import {TextInputComponent} from 'textInput.component';
let validate = require('validate.js');
@Component({
selector: 'my-property-edit',
template: `
<my-text-input [(ngModel)]="property.name" label="Property Name" name="name" [errors]="errors['name']"></my-text-input>
<my-text-input [(ngModel)]="property.address.address1" label="Address" name="address1" [errors]="errors['address.address1']></my-text-input>
`,
directives: [TextInputComponent],
})
export class PropertyEditComponent implements DoCheck {
public property: any = {name: null, address: {address1: null}};
public errors: any;
public constraints: any = {
name: {
presence: true,
length: {minimum: 3},
},
'address.address1': {
presence: {message: "^Address can't be blank"},
length: {minimum: 3, message: '^Address is too short (minimum is 3 characters)'},
}
};
public ngDoCheck(): void {
this.validate();
}
public validate(): void {
this.errors = validate(this.property, this.constraints) || {};
}
}
import {Component, Input, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgModel} from '@angular/forms';
const noop = (_?: any) => {};
@Component({
selector: 'my-text-input',
template: `
<div class="form-group" [class.has-error]="hasErrors(input)">
<label class="control-label" [attr.for]="name">{{label}}</label>
<input class="form-control" type="text" [name]="name" [(ngModel)]="value" #input="ngModel" [id]="name" />
<div class="alert alert-danger" *ngIf="hasErrors(input)">{{errors}}</div>
</div>
`,
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextInputComponent), multi: true },
],
})
export class TextInputComponent implements ControlValueAccessor {
protected _value: any;
protected onChange: (_: any) => void = noop;
protected onTouched: () => void = noop;
@Input() public label: string;
@Input() public name: string;
@Input() public errors: any;
get value(): any {
return this._value;
}
set value(value: any) {
if (value !== this._value) {
this._value = value;
this.onChange(value);
}
}
public writeValue(value: any) {
if (value !== this._value) {
this._value = value;
}
}
public registerOnChange(fn: (_: any) => void) {
this.onChange = fn;
}
public registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
public hasErrors(input: NgModel): boolean {
return input.touched && this.errors != null;
}
}
从'@angular/core'导入{Component,DoCheck};
从“textInput.component”导入{TextInputComponent};
让validate=require('validate.js');
@组成部分({
选择器:“我的属性编辑”,
模板:`
我只是在研究并实现那个解决方案。感谢指针。它仍然感觉有点不正常,因为必须设置提供者和onChange
和onTouched
回调,所以我将保留这个问题,希望有一个更干净的解决方案,但到目前为止这看起来有点希望。我添加了我的im您的答案的补充解决方案,因为它是您建议的文章的相关实现,适合这个问题的需要。我仍然希望有另一个解决方案来帮助摆脱丑陋的提供者和样板方法。