PrimeNG table: how to start a cell edit?

早过忘川 提交于 2020-12-13 11:29:08

问题


I've got a PrimeNG p-table with a number of columns and rows, one column uses an input as its cell editor. Compact version below:

<p-table [value]="rowDatas" selectionMode="single" [(selection)]="selectedRowData">
<ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex">
    <tr [pSelectableRow]="rowData">
        <td pEditableColumn>
            <p-cellEditor>
                <ng-template pTemplate="input">
                    <input id="{{'hours' + rowIndex}}" pInputText type="text" [(ngModel)]="rowData.hours">
                </ng-template>
                <ng-template pTemplate="output">
                    {{rowData.hours}}
                </ng-template>
            </p-cellEditor>
        </td>
</ng-template>

I have access to the table using ViewChild

@ViewChild(Table) private table: Table;

But I have no idea where to go from there. The PrimeNG documentation does not give a hint how to trigger cell edit programmatically. Googling it is throwing something out there with EditableColumns and onClick, but that does not work, and skips which rows should be edited.

I am able to identify the input field via an ID, if it were present. But the actual input HTML tag is only added if the cell is put in edit mode. So I cannot use the standard getElementById.focus.

How do I start editing a specific cell using PrimeNG p-table?


回答1:


I had similar problem and I found a solution that works in my case:

Template:

 <p-table
      #docDataTable
      [value]="frameworkDocumentDataValues"

component (Angular 8):

@ViewChild('docDataTable', {static: false}) private docDataTable: Table;

    ngAfterViewInit() {
        this.frameworkDocumentDataValues.forEach(row => this.docDataTable.initRowEdit(row));
      }

This approach leads to the situation that we have initially all table cells editable. That was my goal to be able to put values directly in a table without clocking on buttons like edit value, confirm etc...




回答2:


I just came across your issue as I had a similar requirement. I needed to go to the next row and set the first cell as editable based on a keyboard shortcut (lets say shift+z for this example). The end user is entering a lot of data into this table so "no mouse clicks to slow down the process please" was one of their requests. This is how I achieved it.

Add an id to your table cells and add the keydown event to the editors

<p-table [value]="rowDatas" selectionMode="single" [(selection)]="selectedRowData">
  <ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex">
    <tr [pSelectableRow]="rowData">
     <td pEditableColumn id="hours{{rowIndex}}">
        <p-cellEditor>
            <ng-template pTemplate="input">
                <input id="{{'hours' + rowIndex}}" pInputText type="text" 
                [(ngModel)]="rowData.hours" (keydown.shift.z)="goNextRow($event,'hours', rowIndex)">
            </ng-template>
            <ng-template pTemplate="output">
                {{rowData.hours}}
            </ng-template>
        </p-cellEditor>
     </td>
    <td pEditableColumn id="minutes{{rowIndex}}">
        <p-cellEditor>
            <ng-template pTemplate="input">
                <input id="{{'minutes' + rowIndex}}" pInputText type="text" 
                [(ngModel)]="rowData.minutes" (keydown.shift.z)="goNextRow($event,'hours', rowIndex)">
            </ng-template>
            <ng-template pTemplate="output">
                {{rowData.minutes}}
            </ng-template>
        </p-cellEditor>
     </td>
     <td pEditableColumn id="seconds{{rowIndex}}">
        <p-cellEditor>
            <ng-template pTemplate="input">
                <input id="{{'seconds' + rowIndex}}" pInputText type="text" 
                [(ngModel)]="rowData.seconds" (keydown.shift.z)="goNextRow($event,'hours', rowIndex)">
            </ng-template>
            <ng-template pTemplate="output">
                {{rowData.seconds}}
            </ng-template>
        </p-cellEditor>
     </td>
  </ng-template>

Script to go to next row. If no next row go to first row.

 goNextRow(event, columnName:string, index: number = 0) {
    event.stopPropagation(); 

    let element: HTMLElement = document.getElementById((columnName + (index + 1).toString())) as HTMLElement;
    if (element == undefined || element == null) {
        element = document.getElementById((columnName  + (0).toString())) as HTMLElement;
    }
    element.click();
}

And then reference the cell you want to edit by the id and index. In this case I want to go to the hours column (1st column) on the next row regardless of whether I am editing hours, minutes or seconds.

  (keydown.shift.z)="goNextRow($event,'hours', rowIndex)"

but you could change hours to any other cell i.e. the minutes column on next row

(keydown.shift.z)="goNextRow($event,'minutes', rowIndex)"

Basically, it fires the click event on the table cell making it editable.




回答3:


Once I also had to do a kind of Excel like grid and for the navigation I wrote a directive like this:

  import {
    Directive,
    OnInit,
    ElementRef,
    NgZone,
    HostListener,
  } from "@angular/core";

  import { Table, EditableColumn } from "primeng/table";
  import { DomHandler } from "primeng/components/dom/domhandler";

  enum Direction {
    Up,
    Down,
  }

  @Directive({
    selector: "[ArrowNavigation]",
  })
  export class ArrowNavigationDirective extends EditableColumn implements OnInit {
    constructor(
      public dt: Table,
      public el: ElementRef,
      public domHandler: DomHandler,
      public zone: NgZone
    ) {
      super(dt, el, domHandler, zone);
    }

    ngOnInit() {
      this.el.nativeElement.tabIndex = 1;
    }

    @HostListener("keydown.ArrowLeft", ["$event"]) ArrowLeft(
      $event: KeyboardEvent
    ) {
      this.moveToPreviousCell($event);
    }

    @HostListener("keydown.ArrowRight", ["$event"]) ArrowRight(
      $event: KeyboardEvent
    ) {
      this.moveToNextCell($event);
    }

    @HostListener("keydown.ArrowUp", ["$event"]) ArrowUp($event: KeyboardEvent) {
      this.moveVertically($event, Direction.Up);
    }

    @HostListener("keydown.ArrowDown", ["$event"]) ArrowDown(
      $event: KeyboardEvent
    ) {
      this.moveVertically($event, Direction.Down);
    }

    private moveVertically($event: KeyboardEvent, direction: Direction) {
      const currentCell = this.findCell($event.target);
      let targetRow =
        direction === Direction.Up
          ? currentCell.parentElement.previousElementSibling
          : currentCell.parentElement.nextElementSibling;
      let targetCell = null;

      while (targetRow) {
        const editableColumns = this.domHandler.find(
          targetRow,
          ".ui-editable-column"
        );

        if (editableColumns.length > 0) {
          const targetColumnIndex = this.domHandler.index(currentCell);

          targetCell = targetRow.firstElementChild;
          for (let index = 0; index < targetColumnIndex; index++) {
            targetCell = targetCell.nextElementSibling;
          }

          targetRow = undefined;
        } else {
          targetRow =
            direction === Direction.Up
              ? targetRow.previousElementSibling
              : targetRow.nextElementSibling;
        }
      }

      if (targetCell) {
        this.domHandler.invokeElementMethod(targetCell, "click");
        $event.preventDefault();
      }
    }
  }

PrimeNG was providing functions to move left and right but not up and down, so had to write the function.

And just use it like this:

  <td pEditableColumn ArrowNavigation>
      <p-cellEditor>
          <ng-template pTemplate="input">
              <input type="text" [(ngModel)]="myModel">
          </ng-template>
          <ng-template pTemplate="output">
              {{myModel]}}
          </ng-template>
      </p-cellEditor>
  </td>


来源:https://stackoverflow.com/questions/61587359/primeng-table-how-to-start-a-cell-edit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!