Search code examples
angularkendo-grid

How to focus to a specific cell when editing a row


When there is an element in the first column of a table and I edit a row, the focus goes to the wrong place.

I am using kendo grid. I have a table with a button in the first column which is shown only if certain conditions are satisfied. In the second row there is a text which I want to edit. In the third row there is an edit button. If I press the edit button and the 1st column is empty, the focus goes to the second column, with the edited text. If the first column is not empty, when I press the edit button, the focus goes to the 1st button and the actual edited text is not focused.

I have seen here there is a method called focus but I don't know how to use it and I don't find any example.

I also saw a similar problem here but it's for jQuery, not for Angular.

The (very simplified) code is the following:

   <kendo-grid-column>
      <!--Column 1: Button, depending on some condition-->
      <ng-template kendoGridCellTemplate>
        <button *ngIf="someCondition">HELLO</button>
      </ng-template>
    </kendo-grid-column>

    <kendo-grid-column>
      <!--Column 2: Editable -->
      <ng-template kendoGridCellTemplate>
        <span>whatever</span>
      </ng-template>
      <ng-template kendoGridEditTemplate>
        <input [formControl]="formGroup.get('field')">
      </ng-template>
    </kendo-grid-column>

    <kendo-grid-column>
      <!--Column 3: Edit button-->
      <ng-template kendoGridCellTemplate>
        <button kendoGridEditCommand type="button">Edit</button>
      </ng-template>
    </kendo-grid-column>

I wish always the second column were focused when I press the edit button. Thank you very much!


Solution

  • I implemented what you are trying to achieve with the help of this kendo demo, it suggests you need to focus on the input you want by using settimeout.

    import { Observable } from 'rxjs/Observable';
    import { Component, OnInit, Inject } from '@angular/core';
    import { FormGroup, FormControl, Validators } from '@angular/forms';
    
    import { GridDataResult } from '@progress/kendo-angular-grid';
    import { State, process } from '@progress/kendo-data-query';
    
    import { Product } from './model';
    import { EditService } from './edit.service';
    
    import { map } from 'rxjs/operators/map';
    
    @Component({
      selector: 'my-app',
      template: `
          <kendo-grid
              [data]="view | async"
              [height]="533"
              [pageSize]="gridState.take" [skip]="gridState.skip" [sort]="gridState.sort"
              [pageable]="true" [sortable]="true"
              (dataStateChange)="onStateChange($event)"
              (edit)="editHandler($event)" (cancel)="cancelHandler($event)"
              (save)="saveHandler($event)" (remove)="removeHandler($event)"
              (add)="addHandler($event)"
              [navigable]="true"
            >
            <ng-template kendoGridToolbarTemplate>
                <button kendoGridAddCommand>Add new</button>
            </ng-template>
             <kendo-grid-column>
                    <ng-template kendoGridCellTemplate let-dataItem>
                        <button *ngIf="dataItem.UnitPrice%2==0" kendoGridFocusable >HELLO</button>
                    </ng-template>
                </kendo-grid-column>
            <kendo-grid-column field="ProductName" title="Product Name"></kendo-grid-column>
            <kendo-grid-column field="UnitPrice" editor="numeric" title="Price"></kendo-grid-column>
            <kendo-grid-column field="Discontinued" editor="boolean" title="Discontinued"></kendo-grid-column>
            <kendo-grid-column field="UnitsInStock" editor="numeric" title="Units In Stock"></kendo-grid-column>
            <kendo-grid-command-column title="command" width="220">
                <ng-template kendoGridCellTemplate let-isNew="isNew">
                    <button kendoGridEditCommand [primary]="true">Edit</button>
                    <button kendoGridRemoveCommand>Remove</button>
                    <button kendoGridSaveCommand [disabled]="formGroup?.invalid">{{ isNew ? 'Add' : 'Update' }}</button>
                    <button kendoGridCancelCommand>{{ isNew ? 'Discard changes' : 'Cancel' }}</button>
                </ng-template>
            </kendo-grid-command-column>
          </kendo-grid>
      `
    })
    export class AppComponent implements OnInit {
        public view: Observable<GridDataResult>;
        public gridState: State = {
            sort: [],
            skip: 0,
            take: 10
        };
        public formGroup: FormGroup;
    
        private editService: EditService;
        private editedRowIndex: number;
    
        constructor(@Inject(EditService) editServiceFactory: any) {
            this.editService = editServiceFactory();
        }
    
        public ngOnInit(): void {
            this.view = this.editService.pipe(map(data => process(data, this.gridState)));
    
            this.editService.read();
        }
    
        public onStateChange(state: State) {
            this.gridState = state;
    
            this.editService.read();
        }
    
        public addHandler({sender}) {
            this.closeEditor(sender);
    
            this.formGroup = new FormGroup({
                'ProductID': new FormControl(),
                'ProductName': new FormControl('', Validators.required),
                'UnitPrice': new FormControl(0),
                'UnitsInStock': new FormControl('', Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,3}')])),
                'Discontinued': new FormControl(false)
            });
    
            sender.addRow(this.formGroup);
        }
    
        public editHandler({sender, rowIndex, dataItem}) {
            this.closeEditor(sender);
    
            this.formGroup = new FormGroup({
                'ProductID': new FormControl(dataItem.ProductID),
                'ProductName': new FormControl(dataItem.ProductName, Validators.required),
                'UnitPrice': new FormControl(dataItem.UnitPrice),
                'UnitsInStock': new FormControl(
                        dataItem.UnitsInStock,
                        Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,3}')])),
                'Discontinued': new FormControl(dataItem.Discontinued)
            });
    
            this.editedRowIndex = rowIndex;
    
            sender.editRow(rowIndex, this.formGroup);
            setTimeout(() => {
              (<HTMLElement>document.querySelector(`.k-grid-edit-row > td:nth-child(${2}) input`))
                  .focus();
            });
        }
    
        public cancelHandler({sender, rowIndex}) {
            this.closeEditor(sender, rowIndex);
        }
    
        public saveHandler({sender, rowIndex, formGroup, isNew}) {
            const product: Product = formGroup.value;
    
            this.editService.save(product, isNew);
    
            sender.closeRow(rowIndex);
        }
    
        public removeHandler({dataItem}) {
            this.editService.remove(dataItem);
        }
    
        private closeEditor(grid, rowIndex = this.editedRowIndex) {
            grid.closeRow(rowIndex);
            this.editedRowIndex = undefined;
            this.formGroup = undefined;
        }
    }
    

    Additionally, also read about the focusable directive