Select/deselect all options in a dynamically created ion-select

How do I implement a select/ deselect all function in my check-boxes that are rendered dynamically from server?

HTML

<ion-select [(ngModel)]="selectedvalue" multiple="true" (ionChange)="checkState($event)">
    <ion-option (ionSelect)="selector()">Select/Deselect All</ion-option>
    <ion-option *ngFor="let item of optionsList" value="{{item.value}}" selected="{{item.checked}}">{{item.text}}</ion-option>
</ion-select>

TS

this.optionsList.push({value: 1, text: "Pizza", checked: false });
this.optionsList.push({value: 2, text: "Sushi", checked: false });
 

I have tried to update the optionsList through a listener on the select all option.

public selector(){
    for (var i = 0; i < this.optionsList.length; i++) {
      this.optionsList[i].checked = true;
    }
    console.log(this.optionsList)
}

Console log displays that the optionsList’s checked is updated accordingly, but the display side does not update accordingly. If I implement a deep copy array inside my method, then my situation would be the same as this user’s post . What I wanted was if the user clicked on the select all checkbox, it should immediately show all checkboxes are checked, vice versa. Please advise thanks.

Hi, can anyone help me? Still couldnt figure this out

what you want to do? if you have a any demo please share here

The gist of it is that I want to implement a checkbox with select all/deselect all functionality. The options are rendered when optionsList gets populated with valid options from the server (For example Option A,B,C, etc inside the attached pic, are all loaded from my server).
SelectALLCheckbox1

Yes, it can be done. I have an example that imports Select and uses viewChild to reference it. It’s the only way I could figure how to do it. I’m pasting the basic idea of it. You’d have to figure a way to add a boolean to the mix to track if all are or are not selected. But this should provide a good starting point.

import { ViewChild } from '@angular/core';
import { Select } from 'ionic-angular';
@Component({
  selector: 'page-profile',
  templateUrl: 'profile.html',
})
export class ProfilePage {
  @ViewChild('myselect') mySelect: Select;

Function to open custom select (pretty simple)

openSelect(select: Select){
  select.open();
 }

Function to select all

  selectAll(select: Select){
    let selectInputs = select._overlay['data']['inputs'];
    selectInputs.map((array) => {
      array.checked = true;
    })
  }

My Html

   <ion-item>
       <ion-select #myselect [(ngModel)]="option" interface="alert" (click)="openSelect(myselect)" >
         <ion-option (ionSelect)="selectAll(myselect)">Select All</ion-option>
         <ion-option *ngFor="let option of options [value]="option">{{option.randomValue}}</ion-option>
       </ion-select>
   </ion-item>

The solution isn’t provided out of the box. You have to take over and do some component trespassing to get real control over the properties you want to manipulate.

1 Like

You’re sending the Select because you have multiple distinct select groups that might be loaded dynamically? You probably don’t need ViewChild - instead you could define a SelectGroup object that contains an array of options, and your display of the Selects iterates over an array of SelectGroup. Then you pass the particular SelectGroup to selectAll.

However, the only reason I can think of for removing ViewChild is to avoid the following type of error. Let’s say ViewChild refers to element named foo. Then you push a new page which also has an element named foo. The old ViewChild still exists, but it now refers to the foo in the new active view. I’d rather bind behavior to specific variables if possible, to lock out weird errors. But if you name every HTMLElement uniquely, you won’t have an issue.

Very close to what I’m doing. What I have is actually one select with the same options, and multiple dynamic targets. The gist of it is multiple profiles of a sort that allow for customizing how much information is shared with different groups of people. Same info to different extents. So the select options are always the same.

Still, I ran into bugs earlier today using ViewChild as you pointed out. The scenario you described was playing out even when on the same page. Makes sense in hindsight. I took it out of the equation and and seem to be bug free.

I had initially been referencing the selects overlay options as an Options[] array, I think as you’re suggesting, but it wasn’t working.

I’ll revisit now that ViewChild is out of the picture. I’d prefer that over hacking at

[‘data’][‘inputs’]

If the options are always the same, maybe best to use a Map. Keys of the map are the options, and the values are the dynamic targets.

Here’s the strange thing. Looking back, that’s essentially what I was doing but 2 things popped up.

  1. No option to choose checked is available, so I must use selected as opposed to checked
  2. Referencing the selected property did not effect the options.

My use case is to present the select with all options unchecked. This seems to have no effect

openSelect(select: Select) {
 select.open();
 select.options.map((array) => {
   array.selected = false;
 })
 }

This, however, presents with the intended result

openSelect(select: Select) {
 let myOverlay: Overlay;
 select.open();
 myOverlay = select._overlay;
 let selectInputs = myOverlay['data']['inputs'];
   selectInputs.map((array) => {
     array.checked = false;
   })
 }

This is what I ended up with. As of now, it’s the best way I could select / deselect all options, reset the values on open as I wanted to, and collect the value on close without error. I did end up using @ViewChildren to account for multiple ion-selects.

My html

<ion-list>
  <ion-item *ngFor="let profile of profiles; let i = index">
    <ion-select #myselect interface="alert" [(ngModel)]="option" (click)="openSelect(i, $event)">
       <ion-option [value]="contactOptions" (ionSelect)="selectAll(i, $event)">Select All</ion-option>
       <ion-option *ngFor="let option of contactOptions" [value]="option">{{option.key}}</ion-option>
    </ion-select>
  </ion-item>
</ion-list>

Component.ts

import { Component, ViewChildren, QueryList } from '@angular/core';
import { Select, RadioButton } from 'ionic-angular';
...
export class ProfilePage {
 @ViewChildren('myselect') selectGroup: QueryList<Select>;
   
  allSelected: boolean;

   constructor() { 
    this.allSelected = false;
   }

openSelect(i:number, ev: any) {
  let _select: Select = this.selectGroup['_results'][i];
  let selectInputs: RadioButton[] = _select._overlay['data']['inputs'];

   _select.registerOnChange(() => {
    console.log(_select.value);
     })
  _select.value = [];
  selectInputs.map((array) => {
  array.checked = false;
  })
  _select.open()
 } 

selectAll(i: number, ev: any){
   let _select: Select = this.selectGroup['_results'][i];
   let selectInputs: RadioButton[] = _select._overlay['data']['inputs'];

   if (this.allSelected) {
   selectInputs.map((array) => {
     array.checked = false;
     this.allSelected = false;
          })
       } else {
   selectInputs.map((array) => {
     array.checked = true;
     this.allSelected = true;
     })
   }
 }

}