9

I have a form (using Angular Material), and I want to disable some of the input fields based on selection values. My code looks as below:

HTML

<mat-form-field class="someclass">
   <mat-select placeholder="Select payment method" formControlName="paymentMethod">
      <mat-option *ngFor="let payment of paymentMethodOptions" [value]="payment.value">
         {{payment.viewValue}}
      </mat-option>
   </mat-select>
</mat-form-field>

<mat-form-field class="someclass">
   <input matInput placeholder="Some input" formControlName="testInput">
</mat-form-field>

TS

paymentMethodOptions: payment[] = [
   { value: "opt-1", viewValue: "somevalue" },
   { value: "opt-2", viewValue: "anothervalue" }
];

paymentForm = new FormGroup({
   paymentMethod: new FormControl("", Validators.required),
   testInput: new FormControl({ value: "", disabled: true }, [
      Validators.required
   ])
});

I want to disable testInput if the value of the selection is equal to "opt-1". I've tried several options, but got different errors and couldn't solve it. Is there any working solution to this? Thanks in advance!

MathMax
  • 571
  • 7
  • 22
Andrew
  • 391
  • 5
  • 8
  • 19
  • I like a enabledDirective (it's looks like a work-around, but it have tha advantage that is the .html with control the enabled) https://stackoverflow.com/questions/47937639/how-to-make-a-disabled-reactive-form-editable-in-angular2 – Eliseo Nov 21 '18 at 07:49

3 Answers3

6

You'll can listen to the valueChanges event of the form :

this.paymentForm.valueChanges.subscribe((value) => {
  if(value.paymentMethod == 'opt-1'){
   this.paymentForm.controls['testInput'].disable();
  }else{
   this.paymentForm.controls['testInput'].enable();
  }
});

So everytime the select changes , the valueChanges event is called , the conditions kick in and it will enable or disable the formControl.

CruelEngine
  • 2,701
  • 4
  • 23
  • 44
  • 1
    Looks like your solution works too. Thank you very much! – Andrew Nov 21 '18 at 06:55
  • Why are you listening to `valueChanges` on the whole form? Won't it run every time there's any change on the form? We should only be concerned with the `mat-select` value change here. – SiddAjmera Nov 21 '18 at 06:56
  • @SiddAjmera formControl is bound to the select . Else i would have used the ``selectionChange`` event too . – CruelEngine Nov 21 '18 at 07:00
  • 1
    Wouldn't it be safe to assume that OP was a mere abstraction of the original implementation and that there are going to be a lot more form controls in the form rather than just a `mat-select`? – SiddAjmera Nov 21 '18 at 07:03
  • @SiddAjmera , i agree with what you are trying to say but if we go on with the assumption then there maybe a case where he may wants to persist the valueChange and make api calls too . – CruelEngine Nov 21 '18 at 07:05
  • Point. I take my words back in that case. Sorry about that. :) – SiddAjmera Nov 21 '18 at 07:06
  • @SiddAjmera no problem :) – CruelEngine Nov 21 '18 at 07:09
  • 1
    Both solutions work good, will try using both of them and decide which one suits my case better. Thanks for your support :) – Andrew Nov 21 '18 at 07:09
  • 1
    @Andrew happy coding :) – CruelEngine Nov 21 '18 at 07:11
3

You can leverage the selectionChange @Output property on MatSelect and react accordingly:

onSelectionChanged({value}) {
  console.log(value);
  if(value === 'opt-1') {
    this.paymentForm.get('testInput').disable();
  } else {
    this.paymentForm.get('testInput').enable();
  }
}

And in template

<mat-select ... (selectionChange)="onSelectionChanged($event)">

Here's a Sample StackBlitz for your ref.

NOTE: In case there are more controls in your form than just mat-select, listening to valueChanges on the whole form could be expensive as this will get triggered every time there is a change in any of the form control. All we are concerned about is the change in the mat-select selection change.

SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • @Andrew, if any of these answers helped you with your issue please consider marking any one of them as a solution to close the loop. – SiddAjmera Nov 21 '18 at 07:10
3

Though there are already answers provided, If any had stumbled with the same issue. You can directly disable a form field by directly accessing its control

Had created a Stackblitz demo link

  <!-- INPUT FIELD --> 
  <mat-form-field formControlName="testInput">
    <input matInput 
           placeholder="Some input"
           [disabled]="paymentForm.get('paymentMethod').value === 'opt-1'">   // Disables the input once paymentMethod's formControlName value is opt-1    
  </mat-form-field>     
KShewengger
  • 7,853
  • 3
  • 24
  • 36
  • Doesn't work. You'll have to use `attr.disabled` in this case. Also it did not change the `disabled` state if `opt-1` was selected first and then `opt-2` is selected. – SiddAjmera Nov 21 '18 at 07:23
  • Had accidentally removed the [disabled] on input from the Stackblitz demo link i sent. Now it actually changes its state, you can try it. You'll know it gets disabled when you can't click on the input anymore and it has a dotted border instead of solid https://stackblitz.com/edit/angular-nuygok – KShewengger Nov 21 '18 at 07:27
  • 1
    Indeed it works. So the trick is to use `paymentForm.get('paymentMethod').value` instead of `paymentForm.value.paymentMethod` – SiddAjmera Nov 21 '18 at 07:36