Click and hold on cell for dropdown menu

Dear Syncfusion team.

I have a grid I created with the GridComponent from Syncfusion. What I am trying to achieve is a "click and hold" functionality for the cells of the grid. My app is fairly complex so I am unable to transfer it to stackblitz. My grid looks like this :



What I would like to implement, is that when I click and hold on a cell for more than 2 seconds, a dropdown menu appears below that cell with different options to select from. Once an option selected, the cell value changes to what has been selected. If the dropdown menu appears and a user clicks somewhere else on the page, I want to dismiss/cancel the dropdown menu and hide it.

Is that possible to implement with the grid component?

I created a very minimal StackBlitz as a playground :

Thank you

5 Replies

PG Praveenkumar Gajendiran Syncfusion Team December 9, 2020 02:51 PM UTC

Hi Remy,

Thanks for contacting Syncfusion support. 

Based on your request, we have prepared a Grid sample. In the below sample, we have used setTimeout and clearTimeout functions to achieve “click and hold on a cell to open dropdown menu” requirement. 

Please refer the below code example, sample and documentation for more information.

Code Example:
[app.component.ts] 
 
export class AppComponent { 
  @ViewChild("normalgrid") 
  public grid: GridComponent; 
  public data: Object[]; 
  public editSettings: Object; 
 
  public editparams: Object; 
  public flag: boolean; 
  public formatoptions: Object; 
  public mouseTimer; 
  public ele; 
  public gfields = ["OrderID", "CustomerID", "ShipCity", "ShipCountry"]; 
  public rowIndex; 
  public field; 
 
  public ngOnInit(): void { 
    this.data = orderDataSource.slice(0, 30); 
    this.editSettings = { 
      allowEditing: true, 
      allowAdding: true, 
      allowDeleting: true, 
      mode: "Batch", 
      showConfirmDialog: false 
    }; 
 
    this.editparams = { 
      params: { 
        dataBound: this.ddDataBound.bind(this), 
        change: this.change.bind(this) 
      } 
    }; 
    this.formatoptions = { type: "dateTime", format: "M/d/y hh:mm a" }; 
  } 
 
  load(args: any): void { 
    this.grid.element.addEventListener("mousedown", this.mouseDown.bind(this)); // mouseDown event 
    this.grid.element.addEventListener("mouseup", this.mouseUp.bind(this)); //mouseUp event 
  } 
 
  ddDataBound(args) { 
    var drop = document.getElementsByClassName("e-dropdownlist")[0] 
      .ej2_instances[0]; 
    drop.showPopup(); // open dropdown popup initially. 
  } 
 
  change(args) { 
    //triggered when the dropdown value changed 
    this.grid.saveCell(); // save the changed value 
    this.grid.endEdit(); // update the selected value 
  } 
  cellEdit(args) { 
    if (this.flag == true) { 
      args.cancel = true; // prevent the edit action 
      this.flag = false; // set the flag as false 
    } 
  } 
  recordDoubleClick() { 
    // triggered when double click the record 
    this.flag = true; // set the flag variable as true 
  } 
 
  mouseDown(args) { 
    debugger; 
    if (args.target.getAttribute("class") == "e-rowcell") { 
      this.ele = args.target; 
      this.mouseUp(); 
      this.rowIndex = parseInt(args.target.getAttribute("index")); 
      this.field = this.gfields[ 
        parseInt(args.target.getAttribute("aria-colindex")) 
      ]; 
      this.mouseTimer = window.setTimeout(this.menu_toggle.bind(this), 2000); //set timeout to fire in 2 seconds when the user presses mouse button down 
    } 
  } 
  menu_toggle() { 
    this.grid.editCell(this.rowIndex, this.field); // edit the target cell by passing rowIndex and field values as parameter to editCell method. 
  } 
  mouseUp() { 
    if (this.mouseTimer) window.clearTimeout(this.mouseTimer); //cancel timer when mouse button is released 
  } 
} 

[app.component.html] 
 
<ejs-grid #normalgrid id="Normalgrid" [dataSource]="data" allowPaging="true" [editSettings]="editSettings" 
                                           (load)="load($event)" (recordDoubleClick)="recordDoubleClick($event)" (cellEdit)="cellEdit($event)"> 
                                           <e-columns> 
                                                          <e-column field="OrderID" headerText="Order ID" width="140" textAlign="Right" isPrimaryKey="true"> 
                                                          </e-column> 
                                                          <e-column field="CustomerID" headerText="Customer ID" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                                          <e-column field="ShipCity" headerText="Ship City" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                                          <e-column field="ShipCountry" headerText="Ship Country" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                           </e-columns> 
                             </ejs-grid> 


Please get back to us if you need further assistance.

Regards,
Praveenkumar G 



RE Remy December 9, 2020 04:30 PM UTC

HPraveenkumar,

Thank you for your prompt response. I'll try to adapt this sample to my app. Is there a way I can hold my click on a cell, have the dropdown appear, hover over the desired option in the dropdown while still holding the click, and have the desired option selected and the dropdown closed only once I release the click over the desired option instead of having to click and hold to show the dropdown and re-clicking again to select an option? Everything would be done in one click press/release.

Thank you,
Remy


PG Praveenkumar Gajendiran Syncfusion Team December 11, 2020 01:14 PM UTC

Hi Remy,

Based on your request, we have prepared a Grid sample. In the below sample, we have used open event of Dropdown and mouseUp event to achieve your requirement. 

Please refer the below code example, sample and documentation for more information.

Code Example:
[app.component.ts] 
 
export class AppComponent { 
  @ViewChild("normalgrid") 
  public grid: GridComponent; 
  public data: Object[]; 
  public editSettings: Object; 
 
  public editparams: Object; 
  public flag: boolean; 
  public formatoptions: Object; 
  public mouseTimer; 
  public ele; 
  public gfields = ["OrderID", "CustomerID", "ShipCity", "ShipCountry"]; 
  public rowIndex; 
  public field; 
 
  public ngOnInit(): void { 
    this.data = orderDataSource.slice(0, 30); 
    this.editSettings = { 
      allowEditing: true, 
      allowAdding: true, 
      allowDeleting: true, 
      mode: "Batch", 
      showConfirmDialog: false 
    }; 
 
    this.editparams = { 
      params: { 
        dataBound: this.ddDataBound.bind(this), 
        change: this.change.bind(this), 
        open: this.OnOpen.bind(this) 
      } 
    }; 
    this.formatoptions = { type: "dateTime", format: "M/d/y hh:mm a" }; 
  } 
 
  load(args: any): void { 
    this.grid.element.addEventListener("mousedown", this.mouseDown.bind(this)); // mouseDown event 
    this.grid.element.addEventListener("mouseup", this.mouseUp.bind(this)); //mouseUp event 
  } 
 
  ddDataBound(args) { 
    var drop = document.getElementsByClassName("e-dropdownlist")[0] 
      .ej2_instances[0]; 
    drop.showPopup(); // open dropdown popup initially. 
  } 
 
  change(args) { 
    //triggered when the dropdown value changed 
    this.grid.saveCell(); // save the changed value 
    this.grid.endEdit(); // update the selected value 
  } 
 
OnOpen(e, instance) {         // dropdown popup open event 
    var drop = document.getElementsByClassName("e-dropdownlist")[0] 
      .ej2_instances[0]; 
    e.popup.element 
      .querySelector("ul") 
      .addEventListener("mouseup", function(e) { 
        drop.onMouseClick(e);                 // here we select the hover dropdown item by mouseUp event 
      }); 
  } 
 
  cellEdit(args) { 
    if (this.flag == true) { 
      args.cancel = true; // prevent the edit action 
      this.flag = false; // set the flag as false 
    } 
  } 
  recordDoubleClick() { 
    // triggered when double click the record 
    this.flag = true; // set the flag variable as true 
  } 
 
  mouseDown(args) { 
    if (args.target.classList.contains("e-rowcell")) { 
      this.ele = args.target; 
      this.mouseUp(); 
      this.rowIndex = parseInt(args.target.getAttribute("index")); 
      this.field = this.gfields[ 
        parseInt(args.target.getAttribute("aria-colindex")) 
      ]; 
      this.mouseTimer = window.setTimeout(this.menu_toggle.bind(this), 2000); //set timeout to fire in 2 seconds when the user presses mouse button down 
    } 
  } 
  menu_toggle() { 
    this.grid.editCell(this.rowIndex, this.field); // edit the target cell by passing rowIndex and field values as parameter to editCell method. 
  } 
  mouseUp() { 
    if (this.mouseTimer) window.clearTimeout(this.mouseTimer); //cancel timer when mouse button is released 
  } 
} 

[app.component.html] 
 
<ejs-grid #normalgrid id="Normalgrid" [dataSource]="data" allowPaging="true" [editSettings]="editSettings" 
                                           (load)="load($event)" (recordDoubleClick)="recordDoubleClick($event)" (cellEdit)="cellEdit($event)"> 
                                           <e-columns> 
                                                          <e-column field="OrderID" headerText="Order ID" width="140" textAlign="Right" isPrimaryKey="true"> 
                                                          </e-column> 
                                                          <e-column field="CustomerID" headerText="Customer ID" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                                          <e-column field="ShipCity" headerText="Ship City" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                                          <e-column field="ShipCountry" headerText="Ship Country" width="150" editType="dropdownedit" 
                                                                        [edit]="editparams"></e-column> 
                                           </e-columns> 
                             </ejs-grid> 

Sample: https://stackblitz.com/edit/angular-spqesu-9fkly4?file=app.component.ts

Please get back to us if you need further assistance.

Regards,
Praveenkumar G 



RE Remy December 11, 2020 03:49 PM UTC

Hi Praveenkumar,

Thank you for your quick response. I am facing one small issue. My grid is generated dynamically via a service (same service used to generate all of the grids in the app). The code looks something like this :

this._gridService.defineGridColumns(structure as object, this.grid).then(result => {
   this.grid = (result as GridComponent);
});

The service itself doesn't include the [edit] parameter for each column since it might differ from one grid to another. Therefore I have to add it manually :

this._enginesGridService.defineGridColumns(engineStructure as object, this.grid).then(result => {
   this.grid = (result as GridComponent);
this.grid.columns.forEach(column => {
column.edit = this.editparams;
});
});

However, it seems that this doesn't monitor these events correctly unlike as if the editparams was declared directly in the HTML [edit] tag.

I reproduced the problem in the following Stackblitz sample :

Is there any way around this?

Thank you


PG Praveenkumar Gajendiran Syncfusion Team December 14, 2020 03:25 PM UTC

Hi Remy,

Based on your query, we suspect that you want to set the columns.edit property dynamically to the Grid. For this we suggest you to use the below solution in the load event to achieve your requirement. 

Please refer the below code example and sample for more information.

Code Example:
[app.component.ts] 
 
  load(args: any): void { 
    this.grid.element.addEventListener("mousedown", this.mouseDown.bind(this)); // mouseDown event 
    this.grid.element.addEventListener("mouseup", this.mouseUp.bind(this)); //mouseUp event 
 
    for (var i = 0; i < this.grid.columns.length; i++) { 
      (this.grid.columns[i] as any).edit = this.editparams; 
    } 
  } 
 
  
This is not meet your requirement , could you please explain more details about your requirement. Also, share the information about how to dynamically retrieve the columns and how to assign the dynamic columns into  the Grid? 

Please get back to us if you need further assistance.

Regards,
Praveenkumar G 


Loader.
Up arrow icon