Angular 2 Reactive Forms会在提交

时间:2016-10-06 10:20:09

标签: angular angular2-forms

是否有一种方法可以在提交时触发反应形式的所有验证器,而不仅仅是“脏”#34;和"触摸"事件

这样做的原因是我们有一个非常大的表格,它没有表明是否需要某个字段,并且用户可能会错过一些必需的控件,因此在提交时,预计所有的将显示最终用户遗漏的无效字段。

我尝试将表单标记为"触及"使用

FormGroup.markAsTouched(true);

它有效,所以我也尝试将其标记为"脏"

FormGroup.markAsDirty(true);

但是班级的css仍然是" ng-pristine",

有没有办法从组件手动触发它,我试着谷歌搜索无济于事,谢谢你提前!

更新

我已经通过迭代FormGroup.controls并将其标记为"脏"来完成它,但是有一个"标准"这样做的方法。

10 个答案:

答案 0 :(得分:14)

这可以通过 here 的示例来实现,您可以在其中使用NgForm指令:

<form [formGroup]="heroForm" #formDir="ngForm">

然后在验证邮件中检查表单是否已提交:

<small *ngIf="heroForm.hasError('required', 'formCtrlName') && formDir.submitted">
  Required!
</small>

答案 1 :(得分:12)

有多种方法可以解决问题。如果你有嵌套的表单组,@ Splaktar的答案将不起作用。所以,这是适用于嵌套表单组的解决方案。

  

解决方案1 ​​:遍历所有表单组和表单控件,并以编程方式触摸它们以触发验证。

模板代码:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
...
<button type="submit" class="btn btn-success">Save</button>
</form>

component.ts代码:

    onSubmit() {
        if (this.myForm.valid) {
            // save data
        } else {
            this.validateAllFields(this.myForm); 
        }
    }

validateAllFields(formGroup: FormGroup) {         
        Object.keys(formGroup.controls).forEach(field => {  
            const control = formGroup.get(field);            
            if (control instanceof FormControl) {             
                control.markAsTouched({ onlySelf: true });
            } else if (control instanceof FormGroup) {        
                this.validateAllFields(control);  
            }
        });
    }
  

解决方案2 :使用变量检查表单是否已提交。 仅供参考:目前正在测试ngForm的提交字段,并将包含在将来的Angular版本中。因此不需要创建自己的变量。

component.ts代码

private formSubmitAttempt: boolean;

onSubmit() {
        this.formSubmitAttempt = true;
        if (this.myForm.valid) {
            console.log('form submitted');
        }
   }

模板代码:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
    <div class="form-group">
        <label class="center-block">
            Name:
            <input class="form-control" formControlName="name">
        </label>
        <div class="alert alert-danger" *ngIf="myForm.get('name').hasError('required') && formSubmitAttempt">
            Name is required
        </div>
        ...
</form>

答案 2 :(得分:9)

几个月后回来,我在这里分享基于所有评论的改进版本,仅供记录:

markAsTouched(group: FormGroup | FormArray) {
  group.markAsTouched({ onlySelf: true });

  Object.keys(group.controls).map((field) => {
    const control = group.get(field);
    if (control instanceof FormControl) {
      control.markAsTouched({ onlySelf: true });
    } else if (control instanceof FormGroup) {
      this.markAsTouched(control);
    }
  });
}

希望它会有用!

答案 3 :(得分:4)

这可以通过markAsTouched()完成。在合并PR #26812之前,您可以使用

TEST_F(MDNodeTest, PrintFromMetadataAsValue)

您可以在source code中找到更多信息。

答案 4 :(得分:2)

我找到了可能感兴趣的东西:

在提交时,我设置submitAttempt = true并将其放入应进行验证的div中:

nickname.touched || nickname.dirty || (nickname.untouched && submitAttempt)

含义: 如果没有触及,我们尝试提交,则会显示错误。

答案 5 :(得分:1)

我的应用程序有很多表单和输入,所以我创建了各种自定义表单组件(用于普通文本输入,textarea输入,选择,复选框等),这样我就不需要重复详细的HTML / CSS和表单验证UI逻辑到处都是。

我的自定义基本表单组件会查找其托管df = pd.DataFrame({'visitor_id':[1,1,2,2,1,1],'visit_id':[5,6,1,2,7,8], 'page_views':[10,20,30,30,40,50]}) df['New']=df.groupby('visitor_id').visit_id.transform('max') - df.visit_id df['weight'] = pd.Series([1/2]*len(df)).pow(df.New.values) df page_views visit_id visitor_id New weight 0 10 5 1 3 0 1 20 6 1 2 0 2 30 1 2 1 0 3 30 2 2 0 1 4 40 7 1 1 0 5 50 8 1 0 1 并使用其FormGroupDirective属性以及submitted个州FormControlvalid等。)确定需要在UI上显示哪个验证状态和消息(如果有)。

此解决方案

  • 不需要遍历表单的控件并修改其状态
  • 不需要为每个控件添加一些额外的touched属性
  • 不需要submitted - 绑定ngSubmit方法中的任何其他表单验证处理
  • 不会将模板驱动的表单与反应式表单相结合

<强>形状base.component:

onSubmit

<强>形状text.component:

import {Host, Input, OnInit, SkipSelf} from '@angular/core';
import {FormControl, FormGroupDirective} from '@angular/forms';


export abstract class FormBaseComponent implements OnInit {

  @Input() id: string;
  @Input() label: string;
  formControl: FormControl;

  constructor(@Host() @SkipSelf()
              private formControlHost: FormGroupDirective) {
  }

  ngOnInit() {
    const form = this.formControlHost.form;
    this.formControl = <FormControl>form.controls[this.id];
    if (!this.formControl) {
      throw new Error('FormControl \'' + this.id + '\' needs to be defined');
    }
  }

  get errorMessage(): string {
    // TODO return error message based on 'this.formControl.errors'
    return null;
  }

  get showInputValid(): boolean {
    return this.formControl.valid && (this.formControl.touched || this.formControlHost.submitted);
  }

  get showInputInvalid(): boolean {
    return this.formControl.invalid && (this.formControl.touched || this.formControlHost.submitted);
  }
}

<强>形状text.component.html:

import {Component} from '@angular/core';
import {FormBaseComponent} from '../form-base.component';

@Component({
  selector: 'yourappprefix-form-text',
  templateUrl: './form-text.component.html'
})
export class FormTextComponent extends FormBaseComponent {

}

<强>用法:

<label class="x_label" for="{{id}}">{{label}}</label>
<div class="x_input-container"
     [class.x_input--valid]="showInputValid"
     [class.x_input--invalid]="showInputInvalid">
  <input class="x_input" id="{{id}}" type="text" [formControl]="formControl">
  <span class="x_input--error-message" *ngIf="errorMessage">{{errorMessage}}</span>
</div>

答案 6 :(得分:1)

现在有了updateOn:“提交”选项,该选项将导致验证在提交时触发,例如:

this.myForm = new FormGroup({},{updateOn: ‘submit’});

答案 7 :(得分:0)

如果我能得到您的要求。您只想在每次提交时更新验证消息。最好的方法是存储控件状态的历史记录。

export interface IValdiationField {
  submittedCount: number;
  valid: boolean;
}
class Component {
   // validation state management
   validationState: Map<string, IValdiationField | number> = new Map();

   constructor() {
      this.validationState.set('submitCount', 0);
   }

   validationChecker(formControlName: string): boolean {

    // get submitted count
    const submittedCount: number = (this.validationState.get('submitCount') || 0) as number;

    // form shouldn't show validation if form not submitted
    if (submittedCount === 0) {
       return true;
    }

    // get the validation state
    const state: IValdiationField = this.validationState.get(formControlName) as IValdiationField;

    // set state if undefined or state submitted count doesn't match submitted count
    if (state === undefined || state.submittedCount !== submittedCount) {
       this.validationState.set(formControlName, { submittedCount, valid: this.form.get(formControlName).valid } );
       return this.form.get(formControlName).valid;
     }

        // get validation value from validation state managment
       return state.valid;
   }
   submit() {
     this.validationState.set('submitCount', (this.validationState.get('submitCount') as number) + 1);
   } 
}

然后在html代码* ngIf =“!validationChecker('formControlName')”中显示错误消息。

答案 8 :(得分:0)

“污秽”,“感动”,“提交”可以使用下一种方法进行组合:

<form [formGroup]="form" (ngSubmit)="doSomething()" #ngForm="ngForm">
<input type="text" placeholder="Put some text" formControlName="textField" required>
<div *ngIf="textField.invalid && (textField.dirty || textField.touched || ngForm.submitted)">
  <div *ngIf="textField.errors.required">Required!</div>
</div>
<input type="submit" value="Submit" />
</form>

答案 9 :(得分:0)

与开箱即用的验证器一起使用,最好的方法是简单地检查用户点击“提交”时表单组是否有效。

markAllAsTouched()然后可用于触发表单每个字段的有效性检查:

Stackblitz example here

// Component

loginForm: FormGroup;

ngOnInit() {
    this.loginForm = new FormGroup({
        username: new FormControl(null, [
            Validators.required,
            Validators.minLength(4)
        ]),
        password: new FormControl(null, [
            Validators.required,
            Validators.minLength(4)
        ]),
    });
}

submitLoginForm() {
    if (!this.loginForm.invalid) { // Checks form input validity
        // Form input is valid
        console.log('Valid login attempt - allow submission');
    } else {
        // Form input is not valid
        this.loginForm.markAllAsTouched(); // Trigger validation across form
        console.log('Invalid login attempt - block submission');
    }
}

// Template

<form id="login_wrapper" [formGroup]="loginForm" (ngSubmit)="submitLoginForm()">
    <h1>Log in</h1>
    <mat-form-field color="accent">
        <mat-label>Username</mat-label>
        <input matInput
            placeholder="Username"
            type="text"
            formControlName="username">
        <mat-error
            *ngIf="loginForm.controls.username.invalid && (loginForm.controls.username.dirty || loginForm.controls.username.touched)">
            Please enter a valid username
        </mat-error>
    </mat-form-field>
    <mat-form-field color="accent">
        <mat-label>Password</mat-label>
        <input matInput
            placeholder="Password"
            type="password"
            formControlName="password">
        <mat-error
            *ngIf="loginForm.controls.password.invalid && (loginForm.controls.password.dirty || loginForm.controls.password.touched)">
            Please enter a valid password
        </mat-error>
    </mat-form-field>
    <button id="login_btn"
        mat-flat-button
        color="primary"
        type="submit">Login</button>
</form>