Reputation: 1426
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
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
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()
}
}
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
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