LIDOR SYSTEMS

Advanced User Interface Controls and Components

Excel Like Editing in Angular TreeGrid

Created: 24 January 2018

In this article, you will learn how to modify the IntegralUI TreeGrid component for Angular, so that you can edit cells in similar way like in Microsoft Excel application. Using keyboard you can navigate between cells and edit each cell individually.

TreeGrid component is part of IntegralUI Web
a suite of UI Components for development of web apps

If you have any questions, don't hesitate to contact us at support@lidorsystems.com

Using arrow and other keys you can navigate among the grid cells. Whenever a cell is focused, by pressing the ENTER key a text editor will popup where you can change the cell text. While text editor is still active, pressing arrow keys allows you to move to a next cell while editor is still visible.

How to Navigate among Grid Cells using the Keyboard

At first, you need to enable keyboard navigation into the Grid component. This is determined by the allowFocus property, which whet set to true enables use of the keyboard. Now, you can navigate between the grid cells using the following keys:

  • Left Arrow - moves the focus to one cell left
  • Right Arrow - moves the focus to one cell right
  • Up Arrow - moves the focus to one cell up
  • Down Arrow - moves the focus to one cell down
  • PageUp - moves one view up
  • PageDown - moves one view down
  • Home - moves the focus to a cell in first row
  • End - moves the focus to a cell in last row
<iui-treegrid [appRef]="applicationRef" [columns]="columns" [rows]="rows" [allowFocus]="true" [controlStyle]="gridStyle" [showFooter]="false" [allowDrag]="true" [rowHeight]="19" (beforeEdit)="onBeforeEdit($event)" #treegrid>
        <ng-template let-column [iuiTemplate]="{ type: 'header' }">
            {{column.headerText}}
        </ng-template>
        <ng-template let-cell [iuiTemplate]="{ type: 'cell' }">
            <div class="treegrid-excedit-cell-content" (mouseup)="cellMouseUp($event, cell)">
                <input *ngIf="cell==editCell" type="text" [(ngModel)]="cell.text" (keydown)="editorKeyDown($event)" (focus)="selectContent($event)" (blur)="editorLostFocus()" [iuiFocus]="editorFocused" [ngStyle]="{ width: getCellWidth(cell) + 'px' }" />
                <span *ngIf="cell!=editCell">
                    {{cell.text}}
                </span>
            </div>
        </ng-template>
</iui-treegrid>
                            

When focus is moved to the cell close to the grid border or to a cell that is not present in the current view, the grid view is scrolled. In addition, if the focus is present on a cell that has the expand box, pressing the Left or Right arrow key will at first collapse or expand the grid row, and subsequently move the focus to the next cell.

The keyboard functionality as you can see is built-in the TreeGrid component, but you can also modify or extend it on your side.

How to Edit Cells like In Excel

Now, we can show an editor when a cell is focused. For this purpose, you can use a simple input element or create your own custom editor.

In this example, by pressing the ENTER key when cell is focused, the cell content is replaced by a text editor. This is based on settings in cell template where you can see a switch between editor and label, depending on whether the cell is in edit mode or not.

// Editing
public editCell: any = null;
public editorFocused: boolean = false;
private editTimeout: any = null;
private isEditActive: boolean = false;
private originalText: string = '';

selectContent(e: any){
    if (e.target){
        setTimeout(function(){
            e.target.setSelectionRange(0, e.target.value.length);
        }, 1);
    }
}

cellMouseUp(e: any, cell: any){
    // Show text editor on mouse up, but only on left mouse button click, when there is no active multi-selection and no menu option clicked
    if (e.which == 1 && !e.ctrlKey && !e.shiftKey)
        this.showEditor(cell);
}

onBeforeEdit(e: any){
    e.cancel = true;

    this.showEditor(e.cell, 0);
}

showEditor(cell: any, delay?: number){
    if (cell){
        let self = this;

        self.treegrid.focusedCell = null;

        if (self.editTimeout)
            clearTimeout(self.editTimeout);

        let editorDelay = delay == 0 ? 0 : 500;

        if (!self.isEditActive)
            self.editTimeout = setTimeout(function(){
                self.openTextEditor(cell);

                clearTimeout(self.editTimeout);
            }, editorDelay);
        else
            self.openTextEditor(cell);
    }
}

openTextEditor(cell: any){
    this.originalText = cell.text;
    this.isEditActive = true;
    this.editCell = cell;
    this.editorFocused = true;
}

closeEditor(){
    this.editCell = null;
    this.originalText = '';
    this.editorFocused = false;
}

editorLostFocus(){
    this.closeEditor();
}

                            
<iui-treegrid [appRef]="applicationRef" [columns]="columns" [rows]="rows" [allowFocus]="true" [controlStyle]="gridStyle" [showFooter]="false" [allowDrag]="true" [rowHeight]="19" (beforeEdit)="onBeforeEdit($event)" #treegrid>
        <ng-template let-column [iuiTemplate]="{ type: 'header' }">
            {{column.headerText}}
        </ng-template>
        <ng-template let-cell [iuiTemplate]="{ type: 'cell' }">
            <div class="treegrid-excedit-cell-content" (mouseup)="cellMouseUp($event, cell)">
                <input *ngIf="cell==editCell" type="text" [(ngModel)]="cell.text" (keydown)="editorKeyDown($event)" (focus)="selectContent($event)" (blur)="editorLostFocus()" [iuiFocus]="editorFocused" [ngStyle]="{ width: getCellWidth(cell) + 'px' }" />
                <span *ngIf="cell!=editCell">
                    {{cell.text}}
                </span>
            </div>
        </ng-template>
</iui-treegrid>
                            

Note To make sure the editor receives the input focus, you can use the iuiFocus directive. This directive sets the focus to an element to which it is applied, based on simple value: true or false.

At current state, you can edit the grid cell, by pressing the ENTER key the change is confirmed and by pressing the ESCAPE key, editor is closed and change is cancelled. Navigation among cells while editor is displayed is not yet active.

To create functionality like in Microsoft Excel, that is to navigate among cells while text editor is displayed, you need to handle the keydown event and add functionality based on which navigation key is pressed. To make it easier, TreeGrid component provides a public method named moveFocusFromCell that allows you to quickly move the focus to another cell, while keeping the text editor active.

editorKeyDown(e: any){
    let self = this;

    if (this.editCell){
        let focusTimer: any = null;
        let newCell: any = null;
        
        switch (e.keyCode){
            case 13: // ENTER
                this.treegrid.focusedCell = this.editCell;
                this.closeEditor();
                break;
                
            case 27: // ESCAPE
                this.treegrid.focusedCell = this.editCell;
                this.editCell.text = this.originalText;
                this.closeEditor();
                break;

            case 33: // PAGE_UP
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'pageup');
                break;

            case 34: // PAGE_DOWN
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'pagedown');
                break;

            case 35: // END
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'end');
                break;

            case 36: // HOME
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'home');
                break;

            case 37: // LEFT_ARROW
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'left');
                break;

            case 38: // UP_ARROW
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'up');
                break;
                
            case 39: // RIGHT_ARROW
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'right');
                break;
                
            case 40: // DOWN_ARROW
                newCell = this.treegrid.moveFocusFromCell(this.editCell, 'down');
                break;
        }

        if (newCell)
            focusTimer = setTimeout(function(){
                self.showEditor(newCell);
                clearTimeout(focusTimer);
            }, 10);
    }

    e.stopPropagation();
}
                            

As a result, you have a grid where you can navigate between cells when edit mode is active or not. Switching this mode is simple, pressing the ENTER key shows the text editor while cell is focused, and pressing again the ENTER key, confirms the change and closes the editor.

Conclusion

In cases where you need to edit grid cells, and quickly switch the focus to another cell, is best to implement an Excel like editing. IntegralUI TreeGrid component for Angular comes with built-in functionality and public methods that allows you to implement this kind of a solution.

When keyboard navigation is enabled, you can move from one cell to another using standard keys, and edit the cell that is currently focused. Furthermore, you can use simple or custom text editor and implement your own way to navigate among the grid cells.

The comple sample code and the TreeGrid component are part of IntegralUI Web.

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.