Inhibit unselected choices when a user exceeds choosing a certain number of options

I want users to be able to select a maximum of 3 options from a list.

If a form has four options, once the user selects three, the fourth should become disabled.

Here is the setup I have:

import {
  Component,
  Input,
  ViewChild,
  OnInit,
  AfterViewInit
} from "@angular/core";
import { MatSelectionList } from "@angular/material/list";

type Option = {
  key: string;
  enabled: boolean;
};

@Component({
  selector: "app-list-component",
  template: `
    <mat-selection-list>
      <mat-list-option
        *ngFor="let option of options"
        checkboxPosition="before"
        [selected]="option.enabled == true"
        [disabled]="
          selectedOptionsCount >= maxSelectedFilters && !option.enabled
        "
      >
        {{ option.key }}
      </mat-list-option>
    </mat-selection-list>
  `,
  styleUrls: ["./list.component.css"]
})
export class ListComponent implements OnInit, AfterViewInit {
  options: Option[];
  selectedOptionsCount: number;

  @Input() filters: string[];
  @Input() selectedFilters: string[];
  @Input() maxSelectedFilters: number;

  @ViewChild(MatSelectionList) selectionList: MatSelectionList;

  ngOnInit(): void {
    this.options = this.filters.map((key) => ({
      key,
      enabled: this.selectedFilters.includes(key)
    }));
    // initially set the count
    this.selectedOptionsCount = this.selectedFilters.length;
  }

  ngAfterViewInit(): void {
    this.selectionList.selectionChange.subscribe(() => {
      // update the count based on the selection change
      this.selectedOptionsCount = this.selectionList.selectedOptions.selected.length;
    });
  }
}

In this configuration, only when you de-select an already selected option will the non-selected items become disabled.

How can you track these changes?


Edit:

The following solution seems to work. Add a template variable using '#' on the mat-list-option, and use it to access the 'selected' property:

// 
// ...
     <mat-list-option
        #foo
        *ngFor="let option of options"
        checkboxPosition="before"
        [selected]="option.enabled == true"
        [disabled]="selectedOptionsCount >= maxSelectedFilters && !foo.selected"
      >
// ...

Source: https://codesandbox.io/s/lucid-kare-wc26k?file=/src/components/list.component.ts

Answer №1

.html

<mat-form-field appearance="fill">
    <mat-label>Toppings</mat-label>
    <mat-select [formControl]="toppings" multiple (selectionChange)="changed()">
        <mat-option *ngFor="let topping of toppingList" [value]="topping"
            [disabled]="toppings.value?.length > '2' && check(topping)">{{topping}}</mat-option>
    </mat-select>
</mat-form-field>

.ts

import { Component } from "@angular/core";
import { FormControl } from "@angular/forms";

/** @title Select with multiple selection */
@Component({
  selector: "select-multiple-example",
  templateUrl: "select-multiple-example.html"
})
export class SelectMultipleExample {
  toppings = new FormControl();
  toppingList: string[] = [
    "Extra cheese",
    "Mushroom",
    "Onion",
    "Pepperoni",
    "Sausage",
    "Tomato"
  ];
  mySelections: any;

  changed() {
    this.mySelections = this.toppings.value;
    this.toppings.setValue(this.mySelections);
    console.log(this.toppings);
  }
  check(value: any) {
    if (this.mySelections.includes(value)) {
      return false;
    }
    else {
      return true;
    }
  }
}

Demo:https://stackblitz.com/edit/mur-mat-select-checkbox-disable-unselect-value?file=src/app/select-multiple-example.ts

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide for transferring data from HTML to controller in Angular 4

Hello everyone, I am new to Angular and currently working on displaying a table based on the value of a toggle button. I have implemented a toggle button using Angular material, but I'm struggling to pass the data to my controller. I would really app ...

Use the res.json method in express.js to automatically generate a predefined response structure

I'm looking for guidance on how to properly use res.json in my code. I want to establish a default response structure that includes a message and error, while also being able to include additional data when necessary. For example, when I use res.statu ...

Stop pages from breaking in jsPDF due to text overflow

Currently, I am utilizing the jsPDF and html2canvas libraries to generate a PDF file from HTML content. An issue that I am facing is dealing with dynamic content where it is challenging to determine when each page ends. I have implemented a function to c ...

Tips on converting Nextjs generated Prisma types case from snake_case to camelCase

I have a full-stack application built with Next.js and Prisma ORM "next": "12.3.0" "prisma": "^4.5.0" Essentially, I am looking to convert the case of my types from snake_case to camelCase to align with the front-en ...

The Angular expression has been modified after being examined

I've encountered a common error in my Angular application, but I'm struggling to pinpoint why it's happening and how to resolve it. I've attempted various approaches such as using setTimeout, delay(0), and switching to different hooks, ...

An error is triggered when an HttpClient post does not return any data

While sending a post request from my angular application to a web api, I am encountering an issue. The response from the api is supposed to be either a 200 status or a 404 status without any data being returned. An example of some headers for the 200 respo ...

Encountering issues during npm installation process

Encountering an issue during my attempt to install TypeScript C:\ESAB_Scripting\H5ScriptSDK\Samples>npm install -g TypeScript npm ERR! code E404 npm ERR! 404 Not Found - GET https://registry.npmjs.org/TypeScript - Not found ...

Ways to verify if a function has completed execution and proceed to invoke another function

I am seeking to verify if a user has chosen an item from the ngFor form and then redirect them to another page upon submitting the form with the updated value. HTML: <mat-select placeholder="Treatment" [(ngModel)]="model.TreatmentA" name="TreatmentA" ...

Utilizing ControlValueAccessor for accurate data validation

I've developed my own input fields using the ControlValueAccessor. How can I retrieve validation information within this component? Feel free to check out an example here: https://stackblitz.com/edit/angular-ngmodel-valid?file=src/app/text-input.com ...

Unexpected JSON end causes issue with DELETE request in Next.js version 13

I am currently working on a web app using Next 13 and I have a route.ts file located in the api folder. This file contains two different methods, POST and DELETE. While both methods successfully receive the request, I am facing an issue with JSON parsing ...

What is the best approach to manage consecutive URL requests in RxJS while transferring data between them?

When calling a service, it is possible for the server to respond with a queue URL if it is too busy to handle the request. In my Angular service, I am struggling to determine which RXJS 6+ operator to use in order to handle these types of calls effectivel ...

Problem with Typescript: The type '{ x;y }' is required to have a '[Symbol.iterator]()' method

Just starting out with Typescript and tackling the task of converting a React project from JavaScript to TypeScript. I've been diving into various posts for guidance, but I feel like I'm going in circles. Any assistance would be greatly appreci ...

Unable to access /route upon refreshing page in Angular 7

After developing several components in Angular 7, I decided not to use 'useHash: true' for routing. Everything seemed to be running smoothly when I deployed my Angular app on a live server. However, I encountered an issue when reloading a page a ...

The VueJS function is not defined

Looking for a way to fetch data from graphql in my vue project and store it in a variable. The function is asynchronous and the value of rawID needs to be awaited. However, there is a possibility that it could result in undefined, causing an error in the ...

Sending a pdf file from the Django backend to the Angular frontend

I've tried various solutions for similar issues, but none have worked with my specific case. My goal is to fetch a PDF file from the filesystem using Django and then send it back via an API call to Angular for display. In Django, my code looks like th ...

Dealing with mistakes in an Angular service

I've been grappling with error handling in Angular. I attempted to handle errors within a service, but I'm uncertain if that's the correct approach. @Injectable({ providedIn: 'root', }) export class CaseListService { public con ...

utilize a document within ngx Translate

I've been working on transitioning an app from AngularJS to Angular 4. As I gradually move components over, I'm encountering issues with translation. My goal is to continue using the old AngularJS translation alongside ngx-translate. Prior to ...

I am encountering an issue where I am unable to locate the module 'http' or its associated type declarations when attempting to include ytdl-core

After downloading ytdl-core for my Angular project using npm install ytdl-core --save (https://www.npmjs.com/package/ytdl-core), I tried to use the module by importing it like this: import ytdl from 'ytdl-core'; ytdl(url); However, when I launc ...

Is Angular 4 compatible with Progressive Web Apps (PWA)?

I'm attempting to incorporate @angular/pwa into my Angular 4 project, marking my introduction to PWAs. I encountered an error: The specified command add is invalid. For a list of available options, refer to ng help. Could this be due to the versio ...

Leveraging an external Typescript function within Angular's HTML markup

I have a TypeScript utility class called myUtils.ts in the following format: export class MyUtils { static doSomething(input: string) { // perform some action } } To utilize this method in my component's HTML, I have imported the class into m ...