Angular2:验证表单而不在每个输入定义错误消息?

时间:2016-03-22 03:57:55

标签: angular

我希望validate form中有angular2。我学习了一些文档,它将被定义为:

<form [ngFormModel]="form">
        <input type="text" ngControl="username" />

        <p *ngIf="username.pending">Fetching data from the server...</p>

        <div *ngIf="username.dirty && !username.valid && !username.pending">
          <p *ngIf="username.errors.required">Username is required.</p>
          <p *ngIf="username.errors.startsWithNumber">Your username can't start with a number</p>
          <p *ngIf="username.errors.usernameTaken">This username is taken</p>
        </div>

        <button (click)="submitData()" [disabled]="!form.valid" class="btn btn-primary">Sumbit data</button>
</form>
constructor(private builder: FormBuilder) {

    this.username = new Control(
        "", 
        Validators.compose([Validators.required, UsernameValidator.startsWithNumber]),
        UsernameValidator.usernameTaken
    );

    this.form = builder.group({
        username:  this.username
    });
}

对于每个输入,我需要定义许多错误消息。我觉得这不好 我想要像jquery.validate,我只是定义input并且错误消息将自动呈现,就像这样

<input required name="username" maxlength='8' pattern="^(?!\s|.*\s$).*$" ...> 

3 个答案:

答案 0 :(得分:3)

要减少代码,一种方法可能是编写组件。

将处理所有condition checkingserror messages

This guy did a nice job here of implementing and explaining it.

HTML with Component看起来像这样

<input ngControl="email" id="email" />
<control-messages control="email"></control-messages>

并且所有dirty work都会进入control-messages组件。

答案 1 :(得分:0)

事实上,您可以利用专用组件来实现这一目标。该组件将包含所有通用内容,例如&#34; label&#34;和错误区域。重要的一点是利用ng-content提供表单元素(input,textarea,select)作为此组件的输入的方法。

另一个有趣的事情是能够从组件引用与此输入关联的控件。这样,您将能够透明地知道/显示与表单元素关联的验证错误。

以下是此类组件的示例实现。首先是相关模板的内容:

<div class="form-group form-group-sm" [ngClass]="{'has-error':state && !state.valid}">
  <label for="for"
    class="col-sm-3 control-label”>{{label}}</label>
  <div class="col-sm-8">
    <ng-content ></ng-content>
    <p *ngIf="state.pending">Fetching data from the server...</p>

    <div *ngIf="state.dirty && !state.valid && !state.pending">
      <p *ngIf="state.errors.required">Field is required.</p>
      <p *ngIf="state.errors.startsWithNumber">Your field can't start with a number</p>
      <p *ngIf="state.errors.usernameTaken">This field is taken</p>
    </div>
  </div>
</div>

和组件本身

@Component({
  selector: 'field',
  templateUrl: 'field.html'
})
export class FormFieldComponent {
  @Input()
  label: string;

  @Input()
  feedback: boolean;

  @ContentChild(NgFormControl) state;

  (...)
}

然后您可以在表单中使用此组件:

<form [ngFormModel]="form">
  <field label="Name">
    <input type="text" [ngFormControl]="form.controls.username" />
  </field>

  <button (click)="submitData()" [disabled]="!form.valid" class="btn btn-primary">Sumbit data</button>
</form>

有关更多详细信息,请参阅此文章(部分&#34;字段&#34的表单组件;)

答案 2 :(得分:0)

我希望现在回答这个问题的时间要晚,但这可能对其他人有所帮助。 为了解决这个问题,我创建了以下指令。该指令适用于模板驱动和&amp;反应形式。

它的作用:

  1. 基于正则表达式的验证(强制和 非必填字段)。
  2. 显示已配置的错误消息 正则表达。
  3. 您也可以选择将字段名称传递给 使您的错误消息更加用户友好。
  4. 适用于文字输入,选择&amp; textarea元素
  5. 使用方法:

    准备配置文件。

    配置文件:error-configurations.ts

    export const errorConfiguration = {
        'alphaNum': {
            'regex': /^[a-zA-Z0-9 ]*$/,
            'msg': 'LABEL should contain only alpaha numeric values'
        },
        'email': {
            'regex': /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/,
            'msg': 'LABEL is not valid email'
        }
    };
    

    在配置文件中,指定正则表达式及其各自的错误消息。在错误消息中,如果指定了“easyLabel”属性,则“LABEL”将替换为字段名称。

    在你的元素中需要按如下方式使用它:

    案例1&gt;强制性电子邮件         

        It will show following messages
            If field is empty : Field is mandatory
            If field is invalid email : Field is not valid demail ( this is from configuartion file LABEL is replaced with "Field" as easyLabel is not specified.)
    

    案例2&gt;非必填电子邮件         

        It will show following message
            If field is invalid email : Field is not valid demail
    

    案例3&gt;特殊字段标签,用于更友好的错误消息         

        It will show following messages
            If field is empty : Email Address is mandatory
            If field is in valid email : Email Address is not valid email
    

    指令文件:easy-validator.directive.ts

    import { Directive, ElementRef, forwardRef, Input } from '@angular/core';
    import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
    import { errorConfiguration } from './error-configurations';    // use configuration file
    
    
    @Directive({
        selector: '[easyValidate]',
        providers: [
            { provide: NG_VALIDATORS, useExisting: forwardRef(() => EasyValidatorDirective), multi: true }
        ]
    })
    export class EasyValidatorDirective implements Validator {
        @Input('easyValidate') easyValidate: string;
        @Input('easyLabel') easyLabel;
        private isRequired: boolean;
        private patternName: string;
        private master;
        public easyConfig;
        constructor(
            public el: ElementRef
        ) {
            this.easyConfig = errorConfiguration;
            this.easyConfig['REQ'] = {'msg' : 'LABEL is mandatory'};
    
    
            if (!('remove' in Element.prototype)) {
                Element.prototype.remove = function () {
                    if (this.parentNode) {
                        this.parentNode.removeChild(this);
                    }
                };
            }
        }
        validate(control: AbstractControl): { [key: string]: any } {
            let val = control.value;
            let temp_arr = this.easyValidate.split('|');
            this.isRequired = temp_arr[0] === 'REQ';
            this.patternName = temp_arr.length > 0 ? temp_arr[1] : '';
            if (this.isRequired) {
                this.el.nativeElement.addEventListener('blur', () => this.getErrorMsgElement().classList.remove('hide'), false);
    
                if (val == '' || val == null || val.toString().trim() == '') {
                    this.showErrorMsg('REQ');
                    return {
                        msoValidateRequired: false 
                    };
                }
            }
            if (this.patternName !== '' && ((val != '' && val != null))) {
                this.el.nativeElement.addEventListener('blur', () => this.getErrorMsgElement().classList.remove('hide'), false);
                this.el.nativeElement.addEventListener('keydown', () => this.getErrorMsgElement().classList.remove('hide'), false);
                this.el.nativeElement.addEventListener('change', () => this.getErrorMsgElement().classList.remove('hide'), false);
    
                if (this.getRegEx(this.patternName)) {
                    let pattern: RegExp = this.getRegEx(this.patternName);
                    if (pattern && !pattern.test(val) && val != '') {
                        this.showErrorMsg(this.patternName);
                        return {
                            msoValidatePattern: false
                        };
                    }
                }
    
            }
    
            this.removeErrorMsgElement();
            return null;
        }
    
        private showErrorMsg(msgKey: string) {
            this.getErrorMsgElement().innerHTML = this.getErrorMsg(msgKey);
        }
        private getErrorMsgElement() {
            let errorElementList = this.el.nativeElement.parentNode.getElementsByClassName('error-span');
            return errorElementList.length ? errorElementList[0] : this.createErrorElement();
        }
    
        private createErrorElement() {
            let errorSpan = document.createElement('span');
            errorSpan.setAttribute('class', 'text-danger error-span hide');
            return this.el.nativeElement.parentNode.appendChild(errorSpan);
        }
        private removeErrorMsgElement() {
            this.getErrorMsgElement().remove();
        }
        private getErrorMsg(msgKey: string) {
            let errMsg: string = this.getConfigMsg(msgKey) ? this.getConfigMsg(msgKey) : 'Invalid Value';
    
            errMsg = errMsg.replace('LABEL', (this.easyLabel ? this.easyLabel : 'Field'));
            return errMsg;
        }
    
        getRegEx(regKey: string) {
            if (typeof this.easyConfig[regKey] !== 'undefined') {
                return this.easyConfig[regKey]['regex'];
            }
            return false;
        }
    
        getConfigMsg(regKey: string) {
            if (typeof this.easyConfig[regKey] !== 'undefined') {
                return this.easyConfig[regKey]['msg'];
            }
            return false;
        }
    }
    

    您需要在模块中声明此指令才能使用它。

    模块文件:app.module.ts

    @NgModule({
      declarations: [
        AppComponent, .... , EasyValidatorDirective
      ],
      imports: [    ...  ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }