Use Switch instead of CheckBox for selection in Grid

Is there a good way to use the Grid's native selection functionality but to swap out the CheckBox with a Switch?

24 Replies

BS Balaji Sekar Syncfusion Team February 19, 2020 02:03 PM UTC

Hi Tomas, 
 
Greetings from syncfusion support 
 
In the below sample, we have bind the keyUp event for search input element in created event of Grid and based on the search value we have performed the search operation in Grid by using the search method. Please refer the below code example and sample for more information. 
 
    created() { 
        document.getElementById("Grid_searchbar").addEventListener('keyup', (event) => { 
            clearTimeout(this.debounceTimer); // you can customize as per your requirement 
            this.debounceTimer 
                = setTimeout(() => { this.searchFun(event); }, 600); 
        }) 
    } 
 
    searchFun(event) { 
        var value = (event.target as HTMLInputElement).value; 
        this.grid.search(value); 
        clearTimeout(this.debounceTimer); 
    } 
   
 
Help documentation : 
 
 
 
Regards,
Balaji Sekar.
 



CB Collin Barrett February 19, 2020 02:09 PM UTC

Balaji,

Was your response posted to the correct thread? My name is Collin (not Tomas) and my question was regarding selection in the Grid, not searching in the Grid.

Thanks.


BS Balaji Sekar Syncfusion Team February 19, 2020 02:16 PM UTC

Hi Collin, 
 
Sorry for inconvenience caused, 
 
Query : Is there a good way to use the Grid's native selection functionality but to swap out the CheckBox with a Switch? 
Yes, because we have default support for grid with checkboxes. If you need switch component instead of checkboxes we need to do some customization in the sample level. Please follow the below workaround. 
 
As per your requirement we have achieved the checkbox features with the switch component. By default checkbox rendered with multiple selection mode. So for the switch component, we have set the selection mode as multiple and enable the enableSimpleMultiRowSelection in the grid. 
 
While on row selection and deselection we have dynamically changed the checked state of the switch component in rowSelected and rowDeselecting event. 
 
If we click the headercell switch we need to select all the records in that page. This is achieved by using the addRowsToSelection method in the change event of switch component. addRowsToSelection is a method used to select the row with the rowIndex. please refer the below sample and code example for more information. 
 
 
 
App.component.html 
<ejs-grid #grid [dataSource]='data' height='315px' [selectionSettings]='selectionOptions' (dataBound)='dataBound($event)' (rowSelected)='rowSelected($event)' 
(rowDeselecting)='rowDeselecting($event)'[allowPaging]='true'(rowDeselected)='rowDeselected($event)'(detailDataBound)='detailDataBound($event)' > 
                    <e-columns> 
                      <e-column headerText='Employee Image'  width='150' textAlign='Center'> 
                        <ng-template #headerTemplate let-data> 
                            <div> 
                             <ejs-switch class='headerswitch' [checked]="false" (change)='change($event)'></ejs-switch> 
                            </div> 
                        </ng-template> 
                            <ng-template #template let-data> 
                                <div class="image"> 
                             <ejs-switch [checked]="false" (change)='change($event)'></ejs-switch> 
                                </div> 
                            </ng-template> 
                        </e-column> 
                      ------- 
                    </e-columns> 
                </ejs-grid> 
 
 
 
App.component.ts 
export class AppComponent { 

  @ViewChild('grid') public grid: GridComponent; 
  public data: object[]; 
    public selectionOptions: SelectionSettingsModel; 

  ngOnInit(): void { 
    this.data = hierarchyOrderdata; 
     this.selectionOptions = { type: 'Multiple', enableSimpleMultiRowSelection: true }; 
  } 
  dataBound(args){ 
  } 
  detailDataBound(args){ 
  } 
  change(args){ 
  if(args.event.target.closest('th')){ 
    if(args.checked){ 
    var allrecords = this.grid.getCurrentViewRecords(); 
// selecting and deselecting all the records in the grid when change the checked state of the header cell switch  
    for(var i=0;i<allrecords.length;i++){ 
      if(this.grid.getSelectedRowIndexes().indexOf(i) >-1) 
      { 
        continue; 
      } 
// selecting the records in the current page 
      this.grid.selectionModule.addRowsToSelection([i]) 
    } 
    }else{ 
// clearing the selection 
      this.grid.clearSelection(); 
    } 
  } 
  } 
  rowDeselecting(args){ 
// changed the checked state of the switch component  
     args.target.closest('tr').getElementsByClassName('e-switch')[0].ej2_instances[0].checked = false 
    if(args.row.length>1){ 
      for(var i=0;i<args.row.length;i++){ 
        args.row[i].getElementsByClassName('e-switch')[0].ej2_instances[0].checked = false 
      } 
    } 
  } 
  rowSelected(args){ 
// changed the checked state of the row cell switch component  
    args.row.getElementsByClassName('e-switch')[0].ej2_instances[0].checked = true; 
    if( this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length){ 
// changed the checked state of the headercell switch component 
this.grid.element.getElementsByClassName('headerswitch')[0].ej2_instances[0].checked = true; 
    } 
  } 
  rowDeselected(args){ 
// changed the checked state of the headercell switch component 
    if( this.grid.getCurrentViewRecords().length > this.grid.getSelectedRecords().length){ 
this.grid.element.getElementsByClassName('headerswitch')[0].ej2_instances[0].checked = false; 
    } 
  } 
 
 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Balaji Sekar.        



CB Collin Barrett February 19, 2020 05:47 PM UTC

Thanks! I think this is going to work.

I do get a couple of TypeScript errors. I am not sure if there is a way to resolve?





BS Balaji Sekar Syncfusion Team February 20, 2020 09:33 AM UTC

Hi Collin, 
 
Greeting from syncfusion support. 
 
Query : I do get a couple of TypeScript errors. I am not sure if there is a way to resolve? 
 
We have validated the provided details. We suggest you to set the element type as any for such cases to resolve the problem. Please refer the below code. 
 
  rowSelected(args){ 
    args.row.getElementsByClassName('e-switch')[0].ej2_instances[0].checked = true; 
    if( this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length){ 
(<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = true; 
    } 
  } 
  rowDeselected(args){ 
    if( !(this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length)){ 
(<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = false; 
    } 
  } 
 
 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Balaji Sekar.   



CB Collin Barrett February 25, 2020 07:49 PM UTC

Do you know if there is a way to get selection with switches working with the following setting enabled?


We want to toggle selection of a row only if the user actually clicks the switch rather than anywhere in the row. checkboxOnly seems to be the feature that enables that, however when we enable it with the switches, it seems like the same events (rowSelected, rowDeselecting, rowDeselected, etc.) are not firing.

I noticed this note in the API for checkboxOnly:

To enable checkboxOnly selection, should specify the column type as checkbox.

However, when specifying the column's type='checkBox', we see switches and checkboxes side-by-side. The switches then do nothing.




Thanks for any help you may be able to provide.




PK Prasanna Kumar Viswanathan Syncfusion Team February 26, 2020 09:32 AM UTC

Hi Collin, 
 
Thanks for your update. 
 
Query : Do you know if there is a way to get selection with switches working with the following setting enabled?  
 
The checkboxOnly API is used to select the records using checkbox and checkbox column is enabled by specifying the column's type='checkBox'  
 
Based on your requirement we found that you need select the row only with switch element. So, we have created sample in which we select the rows only with the switch. In that sample we have prevent the row selection when the target element does not contains switch in the rowSelecting event.  
 
Please refer the below sample and code example for more information. 
 
 
 
export class AppComponent { 
 
  @ViewChild('grid') public grid: GridComponent; 
  public data: object[]; 
    public selectionOptions: SelectionSettingsModel; 
 
  ngOnInit(): void { 
    this.data = hierarchyOrderdata; 
     this.selectionOptions = { type: 'Multiple', enableSimpleMultiRowSelection: true }; 
  } 
  change(args){ 
  if(args.event.target.closest('th')){ 
    if(args.checked){ 
    var allrecords = this.grid.getCurrentViewRecords(); 
    for(var i=0;i<allrecords.length;i++){ 
      if(this.grid.getSelectedRowIndexes().indexOf(i) >-1) 
      { 
        continue; 
      } 
      this.grid.selectionModule.addRowsToSelection([i]) 
    } 
    }else{ 
      this.grid.clearSelection(); 
    } 
  } 
  } 
  rowDeselecting(args){ 
    if(args.row.length>1){ 
      for(var i=0;i<args.row.length;i++){ 
         args.row[i].getElementsByClassName('e-switch')[0].ej2_instances[0].checked = false 
      } 
    } 
  } 
 
  rowSelecting(args){ 
 
// prevent the selection when the target does not contains switch element 
    if( !( args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == true )){ 
       if(<any>this.grid.element.getElementsByClassName('headerswitch')[0].ej2_instances[0].checked == false) 
          args.cancel = true; 
    } 
  } 
  rowSelected(args){ 
     if (this.grid.element.getElementsByClassName('headerswitch')[0].ej2_instances[0].checked == true){ 
         args.row.getElementsByClassName('e-switch')[0].ej2_instances[0].checked = true; 
     } 
    if( this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length){ 
( <any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = true; 
    } 
  } 
  rowDeselected(args){ 
    if( !(this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length)){ 
(<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = false; 
    } 
  } 
 
 
 
Please get back to us if you need further assistance on this. 
 
Regards, 
Prasanna Kumar N.S.V 
 



CB Collin Barrett February 26, 2020 07:44 PM UTC

Thanks for that solution. That seems to mostly work, but there is one bug. I can see this both in your StackBlitz and when porting into my application.

To reproduce:
  1. Use the headerswitch to select all
  2. Click anywhere in a selected row other than the switch
Bug:
Notice that the switch remains selected, but the record is deselected.

I'll look into this a bit myself and see if I can resolve it, but please let me know if you know how to fix this. Thanks.


PK Prasanna Kumar Viswanathan Syncfusion Team February 27, 2020 09:07 AM UTC

Hi Collin, 
 
Thanks for your update. 
 
We can able to reproduce the mentioned behavior at our end. In the previous sample we have handled row selection only through the switch element. Now we have handled both rowSelection and rowDeselection only through the switch element by preventing the selection and deselection of row when the target element does not contains switch in the rowSelecting and rowDeselecting event respectively.  
 
Please refer the sample and code example for more information. 
 
 

rowDeselecting(args){ 
// prevent the deselection when the target does not contains switch element  
    if( !( args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == false )){ 
          args.cancel = true; 
    } 
------- 
  } 

  rowSelecting(args)
// prevent the selection when the target does not contains switch element  
    if( !( args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == true )){ 
       if(<any>this.grid.element.getElementsByClassName('headerswitch')[0].ej2_instances[0].checked == false) 
          args.cancel = true; 
    } 
  } 


 
Please get back to us if you need further assistance on this. 
 
Regards, 
Prasanna Kumar N.S.V 



CB Collin Barrett February 27, 2020 03:11 PM UTC

Thanks, that change seems to be working! Thanks again for your help with this.


CB Collin Barrett February 27, 2020 04:35 PM UTC

I spoke too soon. There is one more bug.

If there is only one row in the grid, deselecting all with the headerswitch does not work.

I can fix this by changing line 47 to "if (args.row.length > 0) {" rather than "if (args.row.length > 1) {", however then the user can deselect a selected row by clicking anywhere in the row again.

I'm investigating myself, but if you have any more ideas, please let me know.


RS Rajapandiyan Settu Syncfusion Team February 28, 2020 01:10 PM UTC

Hi Collin, 

Thanks for your update. 
 
Query : If there is only one row in the grid, deselecting all with the headerswitch does not work. 
 
We can able to reproduce the mentioned behavior at our end. To resolve this problem, we have to change the code ( as you mentioned ) args.row.length > 0 from args.row.length > 1 but we have to do this action in the rowDeselected event instead of rowDeselecting event. Please refer the below code example and sample for more information. 


 
rowDeselecting(args) { 
    if (!(args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == false)) { 
      args.cancel = true; 
    } 
  } 

--------- 

  rowDeselected(args) { 
    if (!(this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length)) { 
      (<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = false; 
    } 
    if ( args.row.length > 0 ) { 
      for (var i = 0; i < args.row.length; i++) { 
        args.row[i].getElementsByClassName('e-switch')[0].ej2_instances[0].checked = false 
      } 
    } 
  } 


Please get back to us if you need further assistance on this. 
  
Regards, 
Rajapandiyan S.



CB Collin Barrett February 28, 2020 08:56 PM UTC

Thanks! That did it.


BS Balaji Sekar Syncfusion Team March 2, 2020 09:18 AM UTC

Hi Collin, 
  
We glad that your issue has been fixed.  
  
Please get back to us if you require further other assistance from us. 
  
Regards, 
Balaji Sekar. 



CB Collin Barrett March 17, 2020 08:37 PM UTC

Do you have any suggestions for selecting one or more rows in the grid with this solution via the TypeScript code? I have tried things like:


    dataBound() {
        this.grid.selectRows([1, 2, 3, 4, 5]);
    }

and

    dataBound() {
        this.grid.selectionModule.addRowsToSelection([1, 2, 3, 4, 5]);
    }

I can hit a breakpoint inside that dataBound() function, but the rows in the grid are not selected.

Thanks!


BS Balaji Sekar Syncfusion Team March 18, 2020 06:13 AM UTC

Hi Collin, 

We have validated your query with provided the information and we suggest you to defined the selection type in Multiple state. Since you can select multiple rows in dataBound event without fails. Please refer the below code example and sample for more information. 
[app.component.html] 
<ejs-grid [allowSelection]='true' [selectionSettings]='selectOptions' (dataBound)="dataBound($event)"> 
  .      .      .     
</ejs-grid> 

[app.component.ts] 

 dataBound(){ 
       this.grid.selectRows([2,4,6]) 
    } 

 
Please get back to us if you have any query, 
 
Regards, 
Balaji Sekar. 



CB Collin Barrett March 18, 2020 01:15 PM UTC

Thanks for your response. I did already have 'Multiple' selection enabled, however. Would you be able to fork this last stackblitz with the working toggle switch selection and demo how to select one or more rows from the TypeScript?


BS Balaji Sekar Syncfusion Team March 19, 2020 05:54 AM UTC

Hi Collin, 
 
Thanks for your update, 
 
We applied multiple selections through the dataBound event using the Grid method of selectRows. In the code example below, we selected multiple grid rows using index array values and we changed the switch state from the corresponding selected rows. For more information, please refer to the example code below and the sample. 
 
dataBound(args) { 
    var index = [ 2, 4, 6, 7, 10, 11] 
    this.grid.selectRows(index); 
    for (var i = 0, len = index.length; i < len; i++) { 
      (<any>this.grid.getRowByIndex(index[i]).getElementsByClassName('e-switch')[0]).ej2_instances[0].checked = true; 
    } 
  } 
 
 

Please get back to us if you need further assistance. 

Regards, 
Balaji Sekar. 



CB Collin Barrett March 19, 2020 01:18 PM UTC

Thanks for that solution.

It does check the switches, however it does not mark them as actually selected in the grid's selection module. (The background color of those switched rows does not update to mark them selected.) I am using the selected rows from this component by calling this.grid.getSelectedRecords() , which does not return the default selected rows with that solution. Any other ideas?

Thanks!


RS Rajapandiyan Settu Syncfusion Team March 20, 2020 01:37 PM UTC

Hi Collin , 

Thanks for your update. 
 
Query : Do you have any suggestions for selecting one or more rows in the grid with this solution via the TypeScript code? I have tried things like:    dataBound() {this.grid.selectRows([1, 2, 3, 4, 5])}; 

From your query we could see that you need to select the rows by programmatical way. So now we have handled the programmatical way of selection also in the given sample, by using the grid’s selection API isInteracted ( row selection occurs when isInteracted is false i.e. programmatical way ) and checked the selected row’s switch component in the rowSelecting event. Please refer the below code example and sample for more information. 
 
App.component.ts 
export class AppComponent { 
-------- 
  ngOnInit(): void { 
-------- 
  } 
  dataBound(args) { 
     this.grid.selectRows([1,2,3]); 
  } 
  detailDataBound(args) { 
  } 
  change(args) { 
----- 
  } 
  rowDeselecting(args) { 
    if (!(args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == false)) { 
      if(this.grid.selectionModule.isInteracted){ 
      args.cancel = true; 
      } 
    } 
  } 

  rowSelecting(args) { 
    if (!(args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == true)) { 
      if ((<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked == false && this.grid.selectionModule.isInteracted == true ){ 
        args.cancel = true; 
        this.grid.selectionModule.isInteracted = false; 
      } 
      else{ 
// enable the switch component to the checked state 
        if(args.rowIndexes && args.rowIndexes.length > 0){ 
        for(var i=0; i<args.rowIndexes.length ; i++ ) { 
this.grid.getRows()[args.rowIndexes[i]].getElementsByClassName("e-switch")[0].ej2_instances[0].checked = true; 
        }else{ 
          this.grid.getRows()[args.rowIndex].getElementsByClassName("e-switch")[0].ej2_instances[0].checked = true; 
        } 
      } 
    } 
  } 
  rowSelected(args) { 
--------- 
  } 
  rowDeselected(args) { 
------- 
    } 
  } 


 
 
Please get back to us if you need further assistance on this. 

Regards, 
Rajapandiyan S.              



CB Collin Barrett March 20, 2020 08:12 PM UTC

Thanks! That works.


RS Rajapandiyan Settu Syncfusion Team March 23, 2020 04:37 AM UTC

Hi Collin,  
   
We are glad that your reported problem has been resolved.   
   
Please get back to us if you need further assistance on this.  
   
Regards,  
Rajapandiyan S. 



CB Collin Barrett April 1, 2020 08:05 PM UTC

Hi Syncfusion,

Do you have any suggestions to resolve the bugs described below after enabling allowSorting with this Switch Selection solution? Thanks!


Changes from previous Stackblitz provided by Syncfusion represented in ^that fork
  • Enable allowSorting on the grid.
  • Enable persistSelection in the grid's selectionSettings.
  • Comment out the default selected rows in dataBound().

Bug 1: 
  1. Select 1 or more rows via their switch.
  2. Click a column header to sort.
  3. See that the rows that were selected are still grayed out as selected, but their switches are not selected.

Bug 2:
  1. Click the select all headerswitch at the top of the switch column.
  2. Click the select all headerswitch again to deselct all
  3. See that the row switches are not all deselected.



RS Rajapandiyan Settu Syncfusion Team April 2, 2020 11:57 AM UTC

Hi Collin, 

Thanks for your update. 

Query : Do you have any suggestions to resolve the bugs described below after enabling allowSorting with this Switch Selection solution?  
See that the rows that were selected are still grayed out as selected, but their switches are not selected. 
Click the select all headerswitch again to deselct all.See that the row switches are not all deselected. 
 
We are able to reproduce the reported behaviors at our end. Please use the below modified codes to resolve the problem. 

For Issue #1: 

rowSelecting(args) { 
    if(args.rowIndex != undefined){ 
    if (!(args.target && args.target.closest('td') && args.target.closest('td').getElementsByClassName('e-switch').length 
 > 0 && args.target.closest('td').getElementsByClassName('e-switch')[0].ej2_instances[0].checked == true)) { 
      if ((<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked == false && ( <any> 
    this.grid.selectionModule).isInteracted == true ){ 
        args.cancel = true; 
       ( <any>this.grid.selectionModule).isInteracted = false; 
      } 
      else{ 
        if(args.rowIndexes && args.rowIndexes.length > 0){ 
        for(var i=0; i<args.rowIndexes.length ; i++ ) { 
( <any>this.grid.getRows()[args.rowIndexes[i]].getElementsByClassName("e-switch")[0]).ej2_instances[0].checked = true; 
        }else{ 
          (<any>this.grid.getRows()[args.rowIndex].getElementsByClassName("e-switch")[0]).ej2_instances[0].checked = true; 
        } 
      } 
    } 
    } 
  } 
  rowSelected(args) { 
  if(args.rowIndex != undefined){ 
    ( <any>this.grid.selectionModule).isInteracted = false; 
    if ((<any> this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked == true) { 
      args.row.getElementsByClassName('e-switch')[0].ej2_instances[0].checked = true; 
    } 
    if (this.grid.getCurrentViewRecords().length == this.grid.getSelectedRecords().length) { 
      (<any>this.grid.element.getElementsByClassName('headerswitch')[0]).ej2_instances[0].checked = true; 
    } 
  } 
  } 


 
For Issue #2: 
change(args) { 
    if (args.event.target.closest('th')) { 
      if (args.checked) { 
     --------------- 
      } else { 
        this.grid.clearSelection(); 
        if (this.grid.isPersistSelection) { 
          var rowstoclear = this.grid.getRows(); 
          for (var i = 0; i < rowstoclear.length; i++) { 
// uncheck the switch component in the row 
            (<any>rowstoclear[i].getElementsByClassName('e-switch')[0]).ej2_instances[0].checked = false;    

          } 
        } 
      } 
    } 
  } 


 
Please get back to us if you need further assistance on this. 
 
Regards, 
Rajapandiyan S.

Loader.
Up arrow icon