【问题标题】:How to check for changes in form controls using Angular5如何使用 Angular5 检查表单控件的更改
【发布时间】:2017-12-07 11:28:48
【问题描述】:

我使用反应式表单,我有多个输入,我想为三个输入显示一个错误,验证是;字段是必需的,不应输入空格。

component.html:

    <form [formGroup]="contratoForm" class="campo-form">
        <div class="campoFormulario">
            <label class="etiquetaFormulario" for="txtCodigoContrato">Código contrato</label>
            <div style="display:inline-block; position: relative;"  class="control">
                <input [formControl]="txtCodigoContrato" type="text" id="txtCodigoContrato" name="txtCodigoContrato" class="cajaTexto ancho80" />
                <span>/</span>
            </div>                
            <div style="display:inline-block; position: relative;" class="control">                
                <input [formControl]="txtCodigoContrato2" type="text" id="txtCodigoContrato2" name="txtCodigoContrato2" class="cajaTexto ancho80" />              
            </div>
        </div>
        <div class="campoFormulario">
            <label class="etiquetaFormulario" for="txtContrato">Contrato</label>
            <div style="display:inline-block; position: relative;" class="control">
                <input [formControl]="txtContrato" type="text" id="txtContrato" name="txtContrato" class="cajaTexto ancho350" />

            </div>
        </div>
         <div *ngIf="((!txtCodigoContrato.valid && (txtCodigoContrato.dirty || txtCodigoContrato.touched)) && (txtCodigoContrato.hasError('required') || txtCodigoContrato.hasError('hasWhites')))
                ||
                ((!txtCodigoContrato2.valid && (txtCodigoContrato2.dirty || txtCodigoContrato2.touched)) && (txtCodigoContrato2.hasError('required') || txtCodigoContrato2.hasError('hasWhites')))
                ||
         ((!txtContrato.valid && (txtContrato.dirty || txtContrato.touched)) && (txtContrato.hasError('required') || txtContrato.hasError('hasWhites')))
                ">

            <span>check the fields in red, they are required</span>    
        </div>              
        <div class="buttons">
            <button class="btn btn-primary boton" type="button" style="float:right;" (click)="onCloseLink()">
                <span class="glyphicon glyphicon-off"></span> Cancel
            </button>

            <button class="btn btn-primary boton" type="button" style="float:right;" (click)="limpiar()">
                <span class="glyphicon glyphicon-trash"></span> Clean
            </button>
            <button type="submit" [disabled]="!contratoForm.valid" class="btn btn-primary boton" style="float:right;" (click)="onClick()">
                <span class="glyphicon glyphicon-floppy-disk"></span> Save
            </button>
        </div>
    </form>

component.ts:

    import { Component, HostBinding, OnDestroy, OnInit, Input, Output, EventEmitter, ElementRef, NgModule, ViewChild, ChangeDetectorRef  } from '@angular/core';
    import { Validators, FormBuilder, FormControl, FormGroup, AbstractControl} from '@angular/forms';
    import { AfterViewChecked } from '@angular/core/src/metadata/lifecycle_hooks';

    @Component({
        selector: 'app-formulario-contrato',
        templateUrl: './contrato.component.html',
        styleUrls: ['./contrato.component.css'] 
    })
    export class FormularioContratoComponent  {

        contratoForm: FormGroup;  

        constructor(private elRef: ElementRef, private formBuilder: FormBuilder, private cdRef: ChangeDetectorRef) {     
            this.createForm();           
        }

        txtCodigoContrato = new FormControl('', [
            Validators.required
            ,this.hasNotWhites
        ]);
        txtCodigoContrato2 = new FormControl('', [
            Validators.required
            , this.hasNotWhites
        ]);
        txtContrato = new FormControl('', [
            Validators.required
            , this.hasNotWhites
        ]);

        createForm() {
            this.contratoForm = this.formBuilder.group({
                txtCodigoContrato: this.txtCodigoContrato
                ,txtCodigoContrato2: this.txtCodigoContrato2
                ,txtContrato: this.txtContrato           
            });
        }  

        hasNotWhites(fieldControl: FormControl) {
            if (fieldControl.value.trim() != '') {
                return null
            }
            else {
               return { hasWhites: true };
            }          
        }

        ngAfterViewChecked() {
            this.cdRef.detectChanges();
        }

        limpiar() {   
        }

        onClick() {
            return null;
        }

component.css:

/* some stuff...*/
:host /deep/ .control input.ng-invalid.ng-touched {
  border-color: #ff8080;
}

验证工作正常,也就是说,当字段为空或我输入空格时,它们会跳转。我的问题是我必须添加更多表单控件,如果它包含消息,则可能会变得难以辨认:

  <div *ngIf="((!txtCodigoContrato.valid && (txtCodigoContrato.dirty || 
  txtCodigoContrato.touched)) && (txtCodigoContrato.hasError('required') || 
  txtCodigoContrato.hasError('hasWhites')))
                ||
                ((!txtCodigoContrato2.valid && (txtCodigoContrato2.dirty || 
  txtCodigoContrato2.touched)) && (txtCodigoContrato2.hasError('required') || 
  txtCodigoContrato2.hasError('hasWhites')))
                ||
         ((!txtContrato.valid && (txtContrato.dirty || txtContrato.touched)) 
  && (txtContrato.hasError('required') || txtContrato.hasError('hasWhites')))
                ">

有没有办法通过打字稿来控制这些值,也就是说,每次控件中的值发生变化时,它都由打字稿中返回真或假的函数控制,如果只在我的分区?

【问题讨论】:

  • 这有效,但仅在我更改输入时才会跳转。当我只用光标从一个输入移动到另一个输入而不输入任何内容时,我也需要跳转

标签: angular angular-reactive-forms custom-validators reactive-forms


【解决方案1】:

你可以这样做

this.contratoForm.valueChanges.subscribe(value = > //do something)

如果您愿意,您可以在之前添加一个映射函数,以便仅从您关心的正在更改的表单中获取值

this.contratoForm.valueChanges
.map(values => values.txtCodigoContrato)
.subscribe(txtCodigoContrato = > //do something)

【讨论】:

    【解决方案2】:

    尝试使用valueChangesArray.some() 函数

    hasError: boolean = false;
    
    constructor(private elRef: ElementRef, 
                private formBuilder: FormBuilder, 
                private cdRef: ChangeDetectorRef) {     
      this.createForm(); 
    
      // listen to all changes on the form
      this.contratoForm.valueChanges.subscribe(_ => {
        const controllersToCheck = [
          'txtCodigoContrato', 
          'txtCodigoContrato2', 
          'txtContrato'
        ];
        this.hasError = controllersToCheck.some(ctrlName => {
          let ctrl = this.contratoForm.get(ctrlName);
          return (ctrl.dirty || ctrl.touched) &&
                 (ctrl.hasError('required') || ctrl.hasError('hasWhites'));
        });
      });          
    }
    

    (检查!ctrl.valid是多余的,因为如果控制器有错误,那么它是无效的)

    HTML:

    <div *ngIf="hasError">
      <span>check the fields in red, they are required</span>    
    </div>
    

    更新

    here 所述

    你也可以听 {@link AbstractControl#statusChanges statusChanges} 在验证状态为时收到通知 重新计算。

    我认为它更适合你的情况,所以尝试订阅statusChanges 事件(而不是valueChanges):

    this.contratoForm.statusChanges.subscribe( ..........
    

    更新 2

    在您的 HTML 中使用函数:

    <div *ngIf="hasErrors()">
      <span>check the fields in red, they are required</span>
    </div>
    

    将此函数添加到您的组件 ts 文件中:

    hasErrors() {
      const controllersToCheck = [
        'txtCodigoContrato', 
        'txtCodigoContrato2', 
        'txtContrato'
      ];
      return controllersToCheck.some(ctrlName => {
        let ctrl = this.contratoForm.get(ctrlName);
        return (ctrl.dirty || ctrl.touched) && 
               (ctrl.hasError('required') || ctrl.hasError('hasWhites'));
      });
    }
    

    我创建了一个STACKBLITZ

    如果添加具有相同验证逻辑的新控制器,只需将它们的控件名称添加到 controllersToCheck 数组中

    【讨论】:

    • 它有效,但只有在我更改输入时才会跳转,当我只用光标从一个输入移动到另一个输入而不输入任何内容时我需要跳转
    • 尝试订阅statusChanges事件而不是valueChanges,查看我的更新答案
    • 我将其更改为“statuschange”,并且能够验证当我将光标从一个字段移动到另一个字段时,该字段的状态会发生变化,但它不会在我的函数中跳转不明白为什么:this.contratoForm.statusChanges.suscribe(.... .
    • "statusChanges" 评估值“有效”或“无效”,最初所有输入的值都无效,所以当我用光标从一个移动到另一个时,它们仍然无效并且不输入功能。
    • 那么,我想我需要检查我的表单中控件的触摸状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 2020-12-27
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多