0

Consider a dynamic table, i.e. a table, the rows of which are build dynamically:

<table>
  <tbody>
    <tr *ngFor="let row of tableRows">
      <td>{{ row.id }}</td>
      <td>{{ row.name }}</td>
  </tbody>
</table>

I am now adding a new entry to the component's variable tableRows and just after doing so, I emit an addRow event. The component, which I use this table in, handles the addRow event by scrolling the last table row into view.

The issue that I have is that the table row, which I have just added, is not yet available in my DOM at the time that I call scrollIntoView. However, it appears to be a matter of milliseconds, everything works fine when adding the following setTimeOut to my addRow event handler:

setTimeout(() => this.scrollRowIntoView(), 0);

I don't like the idea of having to use a setTimeout here. So, I wonder, is there a way to just wait until the DOM has been updated before calling scrollIntoView() ?

When implementing AfterViewChecked in my parent component, i.e. the component, which contains the table and the addRow-event-handler, I realized:

The ngAfterViewChecked() method is called AFTER onAddRow, i.e. the addRow-event-handler. Obviously, I want it to be the other way round and call ngAfterViewChecked() BEFORE onAddRow, because only then the DOM has been updated. Now, I cannot just call onAddRow inside ngAfterViewChecked() since I do not want to call this method every time the view has been checked, but only if the addRow event has been emitted.

I have managed to get this to work by introducing a boolean variable rowAdded to my parent component, which is toggled inside ngAfterViewChecked(). If this variable is true, I call scrollIntoView inside ngAfterViewChecked() and toggle the boolean variable afterwards. In order for this to work, however, I still need to set the row that I want to scroll to inside my onAddRow event handler, because I set a property, which will be marked as "view changed after it has been checked" if I set it inside ngAfterViewChecked().

It appears to me that it cannot be foreseen which method is executed first ngAfterViewChecked or onAddRow so that I tend to stick with my initial solution with setTimeout.

Luk
  • 1,009
  • 2
  • 15
  • 33
  • 1
    Have you tried in AfterViewInit or OnChanges? Also, if that doesn't work either, try adding trackBy to ngFor. – Misha Mashina May 21 '22 at 08:39
  • Show how you emit addRow event – Anton Marinenko May 21 '22 at 08:55
  • Does this answer your question? [execute a function when \*ngFor finished in angular 2](https://stackoverflow.com/questions/37087864/execute-a-function-when-ngfor-finished-in-angular-2) – Drenai May 21 '22 at 09:20
  • @MishaMashina: AfterViewInit or AfterViewChecked? I want to call `scrollIntoView` after the adRow event has been fired, but only then, not if the view gets checked for any other reason. How can I implement this in AfterViewInit? – Luk May 21 '22 at 11:02
  • thx for the info considering `trackBy` and the `changeDetectorRef`. I looked into these features and they are great! But none of this seems to solve my problem. I think I am getting closer to a solution tho and have updated my question accordingly. – Luk May 22 '22 at 08:13

0 Answers0