16

I have a list with an object has name and id properties:

[
  {
    "name": "open",
    "id": "1"
  },
  {
    "name": "inprogress",
    "id": "2"
  },
  {
    "name": "close",
    "id": "3"
  }
]

And using MatSelect with *ngFor to iterate over an array and bind the current status with select using [(ngModel)].

Expected output:

If the current status is inprogress then disable open option

StackBlitz Example

Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84

4 Answers4

24

The example doesn't work properly because selected is bound with [value]="topping.id", but the logic uses selected.id which doesn't exist except on startup because you are initializing selected with a topping object.

Also, the logic [disabled]="topping.id < selected.id" is possibly flawed because it also disables inprogress when close is selected - you might want that - I'm not sure - but you only said you wanted to disable open when inprogress is selected.

Either use [value]="topping":

<mat-form-field>
    <mat-select placeholder="Toppings" [(ngModel)]="selected" [formControl]="toppings">
        <mat-option *ngFor="let topping of list" [value]="topping" [disabled]="selected.id === '2' && topping.id === '1'">{{topping.name}}</mat-option>
    </mat-select>
</mat-form-field>

Or change the logic and initialization of selected:

selected: any =  '2';

<mat-form-field>
    <mat-select placeholder="Toppings" [(ngModel)]="selected" [formControl]="toppings">
        <mat-option *ngFor="let topping of list" [value]="topping.id" [disabled]="selected === '2' && topping.id === '1'">{{topping.name}}</mat-option>
    </mat-select>
</mat-form-field>

Update for Angular v6/7 and later

Use [(value)] instead of [(ngModel)]. Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and is removed in Angular v7.

G. Tranter
  • 16,766
  • 1
  • 48
  • 68
2

if user can select multiple options we dont really need ngModel as well, below is my solution to disable certain option on select of some different option in angular material mat-select.

//toppings is a form control name for mat-select
this.toppings.valueChanges.subscribe((selection) => { 

this.selected = '';

//includes because in case we are using multi selection we will receive selection as array

if(selection.includes('inprogress')) // if index instead of name use index value
this.selected = 'inprogress' // selected is globally defined variable
)}

checkUserSelection(topping){

if(this.selected === 'inprogress' && topping === 'open')"{
return true;
}
return false
}

----------------- Html Code ---------------------

<mat-form-field>
<mat-select placeholder="Toppings" 
[formControl]="toppings">

<mat-option *ngFor="let topping of list" 
<!-- Added null check for the topping field -->
[value]="topping?.id" 
[disabled]="checkUserSelection(topping)"
</mat-option>
</mat-select>

Mehdi Fracso
  • 448
  • 2
  • 16
Nikhil Kamani
  • 850
  • 9
  • 12
2

I did it like this in HTML

      <mat-select [(ngModel)]="algorithm">
        <mat-option
          *ngFor="let algo of algos"
          [value]="algo.name"
          [disabled]="!algo.allow">
          {{ algo }}
        </mat-option>
      </mat-select>

and in ts

 algos = ['FIFO', 'LIFO'];
    somefunctionCall(){ // Map the Array
        const fifoAllowed = false;
        isAllowed = (algo) => algo === 'FIFO' ? fifoAllowed : true;
        this.algos = this.algos.map(a => ({ name: a, allow: isAllowed(a) })
)}
Divek John
  • 623
  • 8
  • 16
0

You can disabled option in mat-select by putting condition as below :

<mat-form-field>
  <mat-select placeholder="Toppings" [(ngModel)]="selected" [formControl]="toppings">
    <mat-option *ngFor="let topping of list" [value]="topping.id" [disabled]="topping.id < selected.id">{{topping.name}}</mat-option>
  </mat-select>
</mat-form-field>

<br> 
Kishan
  • 773
  • 4
  • 10