Search code examples
angularnpmdrop-down-menumulti-selectng-multiselect-dropdown

ng-multiselect-dropdown select options in a continuous range


I am using ng-multiselect-dropdown in my Angular 8.3 web SPA. I have a dropdown which has the functionality to select multiple options like so:

Multi-select dropdown

I need help with selecting the options in a continuous range. For example, as in the image, Q2 and Q4 are selected. I want to implement a functionality such that if a user selects Q2 and Q4, Q3 gets auto-selected. Similarly, if a user first selects Q3 and then selects Q1, Q2 gets auto-selected. In summary, upon selection of more than 1 quarters in a continuous range will need to be selected. However, if only one quarter (say Q4) is selected, the others need not be selected.

component.html

      <!-- Select quarter -->
      <div class="dropdown ml-2"
      >
        <ng-multiselect-dropdown
          [placeholder]="'Select quarter(s)'"
          [settings]="dropdownSettings"
          [data]="quarterList"
          [(ngModel)]="selectedQuarterList"
          (onDropDownClose)="onDropdownClose()"
          (click)="this.isDropdownOpen = true"
        >
        </ng-multiselect-dropdown>
      </div>

component.ts

  ngOnInit() {
    this.dropdownSettings = {
      singleSelection: false,
      idField: "quarterId",
      textField: "title",
      selectAllText: "Select All",
      unSelectAllText: "Clear selection",
      itemsShowLimit: 4,
      allowSearchFilter: false,
    };
}

Any help with the same is appreciated, thanks.


Solution

  • A ng-dropdown-select store an array in the variable selectedQuarterList. The first is order this array, after we get the first and last element of this array (really the index) and select all the values between this one

    So, first we add the events (onSelect) and (onDeSelect). I choose the same function passing a new argument that is true -if select- or false -if unselect-

      <ng-multiselect-dropdown
        ...
          (onSelect)="onItemSelect($event,true)"
          (onDeSelect)="onItemSelect($event,false)"
        >
        </ng-multiselect-dropdown>
    

    The function onItemSelect becomes like

      onItemSelect(event: any, checked: boolean) {
        
        if (this.selectedQuarterList.length > 1) { //almost two elements selected
    
          //we order the elements acording the list
          const value=this.quarterList.filter(x=>this.selectedQuarterList.indexOf(x)>=0)
    
          //get the index of the first and the last element
          let first = this.quarterList.findIndex((x) => x == value[0]);
          let last = this.quarterList.findIndex(
            (x) => x == value[value.length - 1]
          );
    
          //and give the value between this indexs
          this.selectedQuarterList = this.quarterList.filter(
            (_, index) => index >= first && (last < 0 || index <= last)
          );
        }
      }
    

    But, with only this code, we can not uncheck an option in middle -imagine you has selected ["Q1","Q2","Q3"] it's impossible uncheck "Q2" (first get the value 0, last the value 2 and again is selected "Q2"

    To take account this we need find the index of the element unselected and change the variables first and last so the function becomes like

      onItemSelect(event: any, checked: boolean) {
        if (this.selectedQuarterList.length > 1) {
          const value=this.quarterList.filter(x=>this.selectedQuarterList.indexOf(x)>=0)
          let first = this.quarterList.findIndex((x) => x == value[0]);
          let last = this.quarterList.findIndex(
            (x) => x == value[value.length - 1]
          );
    
          //we add this condition
          if (last - first + 1 > value.length && !checked) {
            const index = this.quarterList.findIndex((x) => x == event);
            if (index < this.quarterList.length / 2) {
              first = index + 1;
            } else
              last =index-1;
          }
    
          this.selectedQuarterList = this.quarterList.filter(
            (_, index) => index >= first && (last < 0 || index <= last)
          );
        }
      }
    

    you can see in this stackblitz