How to set formControlNames using *ngFor in Angula

2020-07-28 07:48发布

问题:

I'm trying to set form control using *ngFor over objects in an Array. Depending on the users sometimes I will have 1 object in the Array but other times multiple.

My issue is that I want to create a formControlName using the loop which I can but not sure how to set form group validators in the component? Just setting them like below means if there is only 1 object the form remains invalid while looking for the other formControlName that does not exist.

So if the first object with name:"Days" isn't in the list, "Days" would still be in this.form and shows up in controls:

Array:

indicators = [
  {name:"Days",data:[250,1]},
  {name:"Multiply Average",data:[3,.25,1]}
],

Component:

ngOnInit() {
    this.form = this._fb.group({
            "Multiply Average":['', Validators.compose([
                Validators.required
                ])],
            "Days":['', Validators.compose([
                Validators.required
                ])],
        });  
    };

Template:

  <span
     *ngFor="let i of indicators">
          {{i.name}}: 
          <md-slider
            formControlName={{i.name}}
            color="primary"
            [max]=i.data[0]
            [thumb-label]="true"
            [step]=i.data[1]
            [min]=i.data[2]>
          </md-slider>
  </span>

Any help would be great

回答1:

What you need is conditional validation. Depending on choice you need to set the wanted validators, or then remove them. This here is a very simple example to give you the idea, if you have several more fields, more validations etc I suggest you take a look at this: "How to implement conditional validation in Angular model-driven forms"

There is sample of iterating through form controls and making the whole thing more dynamic, but the idea is the same as below.

We can set a change event on when user makes choice in the md-select. You could of course also use valueChanges, but I like a simple change event:

<md-select
  formControlName="indicator1"
  (change)="checkValue(form.get('indicator1'))">
  <md-option
      *ngFor="let indicator of indicators['indicatorlist']" 
       [value]="indicator">
       {{indicator}}
  </md-option>   
</md-select>

We pass the form control so that we can compare it with the value of which validators should be removed in case it doesn't match, in this case we want to remove validator is the value is something else than Above WMA - Volume Price. We set/unset the validators and we also need to use updateValueAndValidity() here:

checkValue(ctrl) {
  if(ctrl.value != "Above WMA - Volume Price") {
    this.form.get('Multiply Average').setValidators(null);
    this.form.get('Multiply Average').updateValueAndValidity();
  } else {
    this.form.get('Multiply Average').setValidators(Validators.required);
    this.form.get('Multiply Average').updateValueAndValidity();
  }
}

Instead of setValidators(null) you can also just use clearValidators()

As already mentioned, this is a very crude sample to just give you the idea.

Now in the plunker, if you choose something else than Above WMA - Volume Price from the drop down, the form will now be considered valid (if other fields are valid), even though there is no value in that form control with name Multiply Average.

DEMO: https://plnkr.co/edit/h4nQfg1VYykaGgfNfnWk?p=preview



回答2:

Make sure you have [formGroup]="form" on your form tag.

Also to make it more verbose use property binding instead of interpolation over formControlName attribute

[formControlName]="i.name"