1

I have a table and I want to pass HTMLElement of the table cell to the component via click event hadler. At the very begininng I have the pointer to the correct table cell but after I init change detection manually the pointer points to the wrong cell (the next to the correct one)

I can't find out why it happens. I created example with console.log(tableCell) before and after initialization of the change detection (method setEditMode in AppComponent)

https://stackblitz.com/edit/angular-module-sandbox-btszav?file=src/app/app.component.html

app.component.html

    <button (click)="showClipboardText()">Fill the table</button>
    <table id="table" (click)="showTarget($event)">
      <thead>
        <tr>
          <th *ngFor="let colName of colNames">
            {{ colName }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let rowData of data; let rowIndex = index">
          <td
            #tableCell
            *ngFor="
              let cellData of rowData.length
                ? rowData
                : [].constructor(colNames.length);
              let colIndex = index
            "
            [attr.data-col-name]="colNames[colIndex]"
            (click)="setEditMode(rowIndex, colIndex, tableCell)"
          >
            {{ cellData?.value }}
            <input
              type="text"
              (keydown)="saveEdit($event, rowIndex, colIndex)"
              (blur)="saveEdit($event, rowIndex, colIndex)"
              *ngIf="!!data[rowIndex][colIndex]?.isEditMode"
            />
          </td>
          <button (click)="addRow()">+</button>
        </tr>
      </tbody>
    </table>

app.component.ts

    import {
          ChangeDetectorRef,
          Component,
          ElementRef,
          QueryList,
          ViewChildren,
        } from '@angular/core';
        
        @Component({
          selector: 'my-app',
          templateUrl: './app.component.html',
          styleUrls: ['./app.component.css'],
        })
        export class AppComponent {
          @ViewChildren('tableCell', { read: ElementRef })
          tableCells: QueryList<ElementRef>;
        
          colNames = ['Client', 'Order', 'Total'];
        
          data: Array<Array<{ isEditMode?: boolean; value?: string }>> = [
            Array(this.colNames.length),
          ];
        
          activeCell: { row: number; col: number };
        
          constructor(private cd: ChangeDetectorRef) {}
        
          addRow(): void {
            this.data.push(Array(this.colNames.length));
          }
        
          setEditMode(row: number, col: number, tableCell: HTMLElement): void {
            console.log(tableCell.dataset['colName']);
        
            if (this.activeCell) {
              const previousCellData =
                this.data[this.activeCell.row][this.activeCell.col];
              previousCellData.isEditMode = false;
            }
            if (!!this.data[row][col]) {
              this.data[row][col].isEditMode = true;
              this.data[row][col].value = '';
            } else {
              this.data[row][col] = { ...this.data[row][col], isEditMode: true };
            }
            this.activeCell = { row, col };
            this.cd.detectChanges();
            console.log(tableCell.dataset['colName']);
          }
        
          saveEdit(event: Event, row: number, col: number): void {
            if ((<KeyboardEvent>event).key && (<KeyboardEvent>event).key !== 'Enter')
              return;
        
            const value = (<HTMLInputElement>event.target).value;
            const previousCellData =
              this.data[this.activeCell.row][this.activeCell.col];
            previousCellData.isEditMode = false;
        
            this.data[row][col].value = value;
          }
        }

enter image description here

missbells
  • 53
  • 8
  • Please include code in the question itself in addition to any links to the code elsewhere. See [ask] for more tips on how to avoid closures and downvotes. – Heretic Monkey Feb 07 '22 at 20:39

1 Answers1

1

Working stackblitz: https://stackblitz.com/edit/angular-module-sandbox-cdbpbq?file=src/app/app.component.ts

Your issue boils down to the fact that we go from having an array of size 3, but with no default values defined. photo: enter image description here

Thus, each time we defined a value, the colIndex increased by one. You can check this if you set a data attribute for the colIndex as you did for the colName. The solution involves defining a default value for your row.

data: Array<Array<{ isEditMode?: boolean; value?: string }>> = [
    [
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
    ],
  ];

However, this also means we need to update our add row method to look like so:

addRow(): void {
    this.data.push([
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
      {
        isEditMode: false,
        value: '',
      },
    ]);
  }

Previously all you did was just add an array of length three, but with no cells defined within it.

SomeStudent
  • 2,856
  • 1
  • 22
  • 36
  • thanks! that helped me a lot. But now I can't understand why I still can't get input elemenet which is already present in the document after change detecion. I'm trying to get it in the very end of that method SetEditMode(): console.log(tablecell.querySelector('input')); But I got null in the console – missbells Feb 07 '22 at 22:21
  • Try printing out what tableCell is. I think when I was originally testing your code tableCell was the actual element. It is also possible that because the input is hidden behind an ngIf that when it is disabled it won’t show – SomeStudent Feb 08 '22 at 03:12
  • 1
    @missbells this post should actually be inline with what you need https://stackoverflow.com/questions/43034758/what-is-the-difference-between-ngif-and-hidden – SomeStudent Feb 08 '22 at 03:13
  • wow I really forgot about this feaure. thank you a lot! @SomeStudent – missbells Feb 08 '22 at 08:38
  • Sure thing, my pleasure – SomeStudent Feb 08 '22 at 12:20