Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Validation Angular2-创建一个可重用、经过验证的文本输入组件_Validation_Angular - Fatal编程技术网

Validation Angular2-创建一个可重用、经过验证的文本输入组件

Validation Angular2-创建一个可重用、经过验证的文本输入组件,validation,angular,Validation,Angular,我正在创建一个带有节点后端的Angular2应用程序。我将有表格,提交数据到所说的后端。我希望在客户端和服务器端都进行验证,并且我希望避免重复这些验证规则 上述内容与实际问题有些无关,只是说这就是我不使用传统Angular2验证方法的原因 这就给我留下了以下HTML结构: <div class="form-group" [class.has-error]="hasError(name)"> <label class="control-label" for="name"&

我正在创建一个带有节点后端的Angular2应用程序。我将有表格,提交数据到所说的后端。我希望在客户端和服务器端都进行验证,并且我希望避免重复这些验证规则

上述内容与实际问题有些无关,只是说这就是我不使用传统Angular2验证方法的原因

这就给我留下了以下HTML结构:

<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您的答案的补充解决方案,因为它是您建议的文章的相关实现,适合这个问题的需要。我仍然希望有另一个解决方案来帮助摆脱丑陋的提供者和样板方法。