自定义控件不更新父表单验证

时间:2019-10-04 16:43:18

标签: angular-reactive-forms angular4-forms

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

例如,您在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,但是,当基础数组中的值更改时,它永远不会触发。

有人可以解释为什么吗?

1 个答案:

答案 0 :(得分:0)

好的,所以我不得不在这里做一些事情才能使它起作用,我不会仅将整个代码发布到相关部分。

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

    静态ArrayMustBeValid(control:AbstractControl){     if(control.value){       if(control.value.length> 0){         let 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. 必须将验证器添加到FormControl中的app.component.ts

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