【问题标题】:Custom Control not updating parent form validation自定义控件不更新父表单验证
【发布时间】:2020-02-03 00:34:00
【问题描述】:

我一直致力于向表单添加自定义控件,我想这样做是因为我知道我们有多个组件可以组成一个表单。

所以例如你可能有类似app.components.ts:

import { Component, OnInit, AfterViewInit } from '@angular/core';
import { FormGroup, FormBuilder, FormControl, Validators, AbstractControl } from '@angular/forms';
import { Model } from './cool-array/cool-array.component';

@Component({
  selector: 'app-root',
  styleUrls: ['./app.component.css'], 
  template:`
  <!--The content below is only a placeholder and can be replaced.-->
  <div class="col-md-6">
      <form [formGroup]="form" >

        <div class="form-group">
          <label >Name</label>
          <input formControlName="name" type="text" class="form-control" >
        </div>

        <app-cool-array formControlName="items"></app-cool-array>

    </form>
  </div>

  <div class="col-md-6">
      <div class="row">
        IsValid Form: <strong> {{form.valid}}</strong>

        Total Errors: <strong>{{form.errors? form.errors.length:0}}</strong>
      </div>
      <div class="row">
        <table class="table table-stripped">
          <thead>
            <tr>
              <th>Error</th>
            </tr>
          </thead>

          <tbody>
            <tr *ngFor="let error of form.errors">

            </tr>
          </tbody>

        </table>
      </div>
  </div>
  `
})
export class AppComponent implements OnInit, AfterViewInit {


  /**
   *
   */
  constructor(private formBuilder:FormBuilder) {

  }

  form:FormGroup;
  model:MyModel;


  ngOnInit(): void {
    this.model = new MyModel();

    this.form = this.formBuilder.group({ });

    this.form.addControl('name', new FormControl('', Validators.required));
    this.form.addControl('items', new FormControl([],[(control)=>MyValidator.MustHaveOne(control) ]))
  }

  ngAfterViewInit(): void {
    console.log(this.form.errors)
  }
}

export class MyValidator{
  static MustHaveOne(control:AbstractControl){
    if(control.value.length === 0) return {'length':'Items Must Have at least 1 item'};

    return null;
  }
}


export class MyModel{
  name:string='';
  items:Model[]=[];
}

您可能还想添加子组件:

import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-cool-array',
  styleUrls: ['./cool-array.component.css'],
  providers:[
    {
      provide:NG_VALUE_ACCESSOR,
      multi:true,
      useExisting:CoolArrayComponent
    }
  ],
  template:`

<button (click)="onAdd()" class="btn btn-primary" >Add</button>
<button (click)="onRemove()" class="btn">Remove</button>

<table class="table table-striped table-responsive">
  <thead>
    <tr>
      <th>Something Required</th>
      <th>Something Not Requred</th>
    </tr>
  </thead>

<tbody>
  <tr *ngFor="let item of items"  (click)="onSelectedItem(item)" [ngClass]="{'selected-item':item === selectedItem}">
    <td><input class="form-control" required [(ngModel)]="item.somethingRequired"/></td>
    <td><input class="form-control" [(ngModel)]="item.somethingNotRequired"/></td>
  </tr>
</tbody>

</table>
  `
})
export class CoolArrayComponent implements OnInit, ControlValueAccessor {

  onChange:any = ()=>{};
  onTouched: any = () => { };


  writeValue(obj: any): void {
    this.items = obj;
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  disabled:boolean=false;

  items:Model[]=[];
  selectedItem:Model;

  constructor() { }

  ngOnInit() {
  }

  onAdd():void{
    this.items.push(new Model());
  }
  onRemove():void{
    let index = this.items.indexOf(this.selectedItem);
    if(index>-1)
      this.items.splice(index, 1);
  }



onSelectedItem(event){
    this.selectedItem = event;
  }
}


export class Model{
  somethingRequired:string;
  somethingNotRequired:string;

  get isValid():boolean{
    return this.somethingRequired !==undefined && this.somethingRequired.length>0;
  }
}

当子组件变得无效时,这应该将表单设置为无效。 我尝试添加一个 CustomValidator,但是,当底层数组中的值发生变化时,它永远不会被触发。

谁能解释一下这是为什么?

【问题讨论】:

    标签: angular-reactive-forms angular4-forms


    【解决方案1】:

    好的,所以我必须在这里做一些事情才能让它工作我不会只发布相关部分的整个代码。

    1. 我要做的是添加一个新的自定义验证器

      静态 ArrayMustBeValid(control:AbstractControl){ 如果(控制值){ 如果(控制。值。长度> 0){ 让 items:Model[] = control.value;

          let invalidIndex = items.findIndex(x=> !x.isValid);
          if(invalidIndex === -1) return null;
      
          return {'array': 'array items are not valid'};
        }
      }
      return {'array':'array cannot be null'};
      

      }

    2. 然后我必须在输入上添加一个更新事件,这应该在 keyup 上触发

      onUpdate(){
          this.onChange(this.items);
        }
      
    3. 必须在app.component.ts 中将验证器添加到FormControl

      this.form.addControl('items', new FormControl([],[(control)=&gt;MyValidator.MustHaveOne(control), (control)=&gt;MyValidator.ArrayMustBeValid(control) ]))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 1970-01-01
      • 2019-07-09
      • 2021-10-13
      • 1970-01-01
      相关资源
      最近更新 更多