plusheen
plusheen

Reputation: 1426

Set one of two Angular Material select to required based on a condition

I have a simple form which operates on the logic of:

Select Box 1 (Yes/No)

Select Box 2 (Show if Yes) Select Box 3 (Show if No)

Only the shown selection box should be set to required, the other is not required.

<mat-select placeholder='Show First Options' formControlName='b' [(ngModel)]="view">
    <mat-option [value]="'first'">
       First
    </mat-option>
    <mat-option  [value]="'second'">
      Second
    </mat-option>
  </mat-select>
</mat-form-field> 

<mat-form-field *ngIf="view === 'first'">
  <mat-select       
      placeholder='First Items' 
      formControlName='one'
      [required]="view === 'first'">
    <mat-option *ngFor="let item of items1" [value]="item">
      {{item}}
    </mat-option>
  </mat-select>
</mat-form-field>

<mat-form-field *ngIf="view === 'second'">
  <mat-select
      placeholder='Second Items'
      formControlName='two'
      [required]="view === 'second'"> 
    <mat-option *ngFor="let item of items2" [value]="item">
      {{item}}
    </mat-option>
  </mat-select>
</mat-form-field>

This works fine for the first, default select box. However, when you change to the second box, the first box seems to keep its required validator.

I have written a demo to demonstrate this: https://stackblitz.com/edit/angular-9eoffq

How can I ensure only the viewed select box is required?

Upvotes: 1

Views: 3672

Answers (3)

Ghost Rider
Ghost Rider

Reputation: 161

Still some one is looking for another solution, this may help.

<mat-select placeholder='Show First Options' formControlName='b' [(ngModel)]="view" #optionsSelector>
    <mat-option value="first"> First </mat-option>
    <mat-option value="second"> Second </mat-option>
  </mat-select>
</mat-form-field> 

<mat-form-field *ngIf="optionsSelector.value === 'first'">
  <mat-select placeholder='First Items' formControlName='one'>
    <mat-option *ngFor="let item of items1" [value]="item">
      {{item}}
    </mat-option>
  </mat-select>
</mat-form-field>

<mat-form-field *ngIf="optionsSelector.value === 'second'">
  <mat-select placeholder='Second Items'  formControlName='two'> 
    <mat-option *ngFor="let item of items2" [value]="item">
      {{item}}
    </mat-option>
  </mat-select>
</mat-form-field>

Upvotes: 0

AVJT82
AVJT82

Reputation: 73357

Instead of using ngModel you can instead make full use of your reactive form, and utilize the form controls. Also, by disabling and enabling fields they are either included/excluded from the form object, therefore also validations will not apply.

You could listen to valueChanges of form, but I like to avoid it since if you are having a large form, it will be fired excessively. But if you want to only listen to a specific control changes, you can also do that. I like a simple change event here though:

<mat-select formControlName='b' (change)="onChange()">

and then hiding/showing the other select:

<mat-form-field *ngIf="form.controls.b.value === 'first'">
<!-- -->
<mat-form-field *ngIf="form.controls.b.value === 'second'">

and the change event:

onChange() {
  if(this.form.get('b').value === 'first') {
    this.form.get('one').enable()
    this.form.get('two').disable()
  } else {
    this.form.get('one').disable()
    this.form.get('two').enable()     
  }
}

DEMO

With this, we need to remember that the disabled control(s) are excluded from the form object, if you want all values (disabled included), you need to call this.form.getRawValue()

Upvotes: 0

plusheen
plusheen

Reputation: 1426

Apologies for editing the demo provided as people were reviewing it which caused confusion, however I seemed to have solved it - the issue seemed to stem from the DOM re-rendering to remove the mat-form-field before removing the required tag. This meant that the form still had the required attribute.

The demo has been updated with the solution - I had to programatically remove the required validator and add it to the appropriate form control. Then I had to update the value and validity to clear the errors after the validators were changed.

this.form.valueChanges.subscribe(value => {
     if(value.b === 'first') {
         this.form.controls['one'].setValidators(Validators.required)
         this.form.controls['two'].clearValidators()
     } else {
         this.form.controls['two'].setValidators(Validators.required)
         this.form.controls['one'].clearValidators()
     }    

     this.form.controls['one'].updateValueAndValidity({onlySelf:true})
     this.form.controls['two'].updateValueAndValidity({onlySelf:true})
})

Upvotes: 1

Related Questions