Home > Net >  Checkboxes not checking after adding disabled attribute
Checkboxes not checking after adding disabled attribute

Time:10-19

I have a list of items with checkboxes, and I would like to disable the ability to check off those boxes after a user has checked off 10 items from the list.

I am new to the world of Angular, so I am not clear why my use of [disabled] is not working:

<mat-selection-list appScrollable #filteredCountriesSelectionList >
  <mat-list-option appOffsetTop *ngFor="let country of filteredCountries" [value]="country.name" checkboxPosition="before" [disabled]="filteredCountries.length > 10">
     {{country.name}} {{country.iso3}} <span>{{country.emoji}}</span>
  </mat-list-option>
</mat-selection-list>

I attempted something like this in the past:

<mat-selection-list appScrollable #filteredCountriesSelectionList  [disabled]="filteredCountries.length >= 10">
  <mat-list-option (selectedChange)="onChange($event, country)" appOffsetTop *ngFor="let country of filteredCountries" [value]="country.name" checkboxPosition="before" [disabled]="filteredCountries.length > 10">
     {{country.name}} {{country.iso3}} <span>{{country.emoji}}</span>
  </mat-list-option>
</mat-selection-list>

And then in my component class file:

filteredCountries = [];

onChange(selected: boolean, country: string) {
  this.filteredCountries.push(country);
}

Since the work I have done above only served to completely disable the ability to click on checkboxes, I decided to console log event and selectedOptions to get the appropriate type and was able to get it at least for one of the parameters.

So instead what I landed on that is getting closer is removing [disabled] entirely I believe and doing it like so:

<mat-selection-list (selectionChange)="disableMaxSelection($event, filteredCountriesSelectionList.selectedOptions)" appScrollable #filteredCountriesSelectionList  [disabled]="filteredCountries.length >= 10">
  <mat-list-option (selectedChange)="onChange($event, country)" appOffsetTop *ngFor="let country of filteredCountries" [value]="country.name" checkboxPosition="before" [disabled]="filteredCountries.length > 10">
     {{country.name}} {{country.iso3}} <span>{{country.emoji}}</span>
  </mat-list-option>
</mat-selection-list>

So now I am depending on a selectionChange called disableMaxSelection() like so:

disableMaxSelection(event: MatSelectionListChange, selectedOptions) {}

And now I think I got it, but I might need some help with the logic here, something like comparing with current selected filter and if item is not in filter, don't disable? Not sure.

I have tried repeatedly to implement the use of [disabled]="" but it disables my checkboxes every single time. And my data is not an array of strings its an array of objects.

CodePudding user response:

I don't see any event specified in your element, try adding selectedChange onto your mat-list-option, also, you should add the disabled in the element container rather than the option.

I have taken an example from the offical docs:

Template HTML

<mat-selection-list [disabled]="shoesSelected.length > 3"> <!--disable goes here-->
  <mat-list-option 
   (selectedChange)="onChange($event, shoe)" <!-- listen to this event -->
   *ngFor="let shoe of typesOfShoes">
    {{ shoe }}
  </mat-list-option>
</mat-selection-list>

Component

...
@Component({...})
export class YourComponent {
  typesOfShoes: string[] = ['Boots', 'Clogs', 'Loafers', 'Moccasins',  'Sneakers'];
  shoesSelected: string[] = [];

  onChange(selected: boolean, shoe: string) {
    // ... do something with selected
    this.shoesSelected.push(shoe);
  }
}

CodePudding user response:

You need check if the length>10 and is not selected.

You can play with two properties:

  1. options: a QueryList
  2. selectedOptions.selected.length: how many items are you selected

So, if you write some like

<mat-selection-list #shoes>
  <mat-list-option *ngFor="let shoe of typesOfShoes;let i=index"
     [disabled]="shoes.selectedOptions.selected.length>2 &&
                 !isSelected(i,shoes.options)
                  ">
    {{shoe}}
  </mat-list-option>
</mat-selection-list>

Your function isSelected like

  isSelected(index:number,options:QueryList<MatListOption>)
  {
    if (!options)
      return;
    const option= options.find((x,i)=>i==index)
    return option && option.selected
  }

See how you can find the option of a QueryList by index using the "second argument of find"

And you get it

NOTE: You can use some like

  getValue(options:QueryList<MatListOption>)
  {
    if (!options)
      return null;
    return this.typesOfShoes.filter((x,index)=>this.isSelected(index,options));
  }

To get the values selected

See a stackblitz

Personal Opinion To control a series of check-boxes I feel is easer use a FormArray of FormControls or a simple [(ngModel)] using an array than fight with QueryLists

Update another way to control

e.g. Imagine we has a variable

selected:string[]=[]

And some like

<div *ngFor="let shoe of typesOfShoes;let i=index">
  <mat-checkbox
    [checked]="selected.indexOf(shoe)!=-1"
    (change)="change(shoe,$event.checked)"
    [disabled]="selected.length>2 && selected.indexOf(shoe)==-1"
    >{{shoe}}</mat-checkbox
  >
</div>

The function change

  change(value:string,checked:boolean)
  {
    const oldValue=this.selected || []
    if (!checked)
      this.selected=this.typesOfShoes.filter(
                x=>oldValue.indexOf(x)!=-1 && x!=value)
    else
      this.selected=this.typesOfShoes.filter(
                x=>oldValue.indexOf(x)!=-1 || x==value)
  }

You get it again

CodePudding user response:

So here is what worked for me, with great help.

<mat-selection-list (selectionChange)="onSelection($event)" appScrollable #filteredCountriesSelectionList  [disabled]="filteredCountries.length >= 10">
  <mat-list-option [disabled]="disableCountry(country.name)" appOffsetTop *ngFor="let country of filteredCountries | orderBy:'name'" [value]="country.name" checkboxPosition="before"  [attr.id]="'scrollTo'   country.name.split('')[0].toUpperCase()">
     {{country.name}} {{country.iso3}} <span>{{country.emoji}}</span>
  </mat-list-option>
</mat-selection-list>

And the component class file:

get isMaxCountries() {
  return this.selectedCountries?.length >= 10;
}

disableCountry(country: string) {
  if (this.isMaxCountries) {
    const countryNotSelected = this.selectedCountries.indexOf(country) === -1;
    return countryNotSelected;
  }
}

onSelection(event: MatSelectionListChange) {
  this.selectedCountries = event.source._value;
}
  • Related