I have some dynamic content being loaded in the html, using material tables, and linking the datasource to a signal, like this:
<table
mat-table
[dataSource]="[resultEntries$()][0]"
(contentChanged)="scrollToFourth()"
>
<ng-container matColumnDef="col-lemma">
<td mat-cell *matCellDef="let element">
<a
[id]="element.alpha"
class="link-primary"
role="button"
(click)="clickID(element)"
>{{ element.l }}</a
>
</td>
</ng-container>
<ng-container matColumnDef="col-brp">
<td mat-cell *matCellDef="let element">{{ element.bp }}</td>
</ng-container>
<ng-container matColumnDef="col-amp">
<td mat-cell *matCellDef="let element">{{ element.ap }}</td>
</ng-container>
<tr
mat-row
class="material-row"
*matRowDef="let row; columns: displayedColumns"
></tr>
</table>
And I need to run this function, in which I use the oldfashioned getElementById
to access the DOM element (I've tried ViewChild
to no avail).
scrollToFourth(): void {
let delayInMilliseconds = 50;
while (!this.resultEntry$()[0].alpha) {
setTimeout(() => {}, delayInMilliseconds);
}
document
.getElementById(this.resultEntry$()[0].alpha.toString())!
.scrollIntoView({
behavior: 'instant',
});
}
The problem is that it runs too early, and it gives me an error saying that the DOM element doesn't exist. If I move everything into ngAfterViewInit
, it's still too early. The only way it works is to put it inside a setTimeout
with a four-second delay, but of course, the exact number of seconds will depend on the client and server, so this is hardly a good alternative.
Any help will be greatly appreciated.
If your're using signal as data source, why not use "effects". It's true that you need enclosed the action in a setTimeout -without delay time- to say to Angular: "hey, change the data source and, when you finished of draw remember that you need makes this another sentences"
readonly dataSource = signal(ELEMENT_DATA);
@ViewChild('id') el!:ElementRef
constructor(){
effect(()=>{
const dataSource=this.dataSource();
//the setTimeout it's only to makes the actions after "repaint"
//but see that have no "delay time"
setTimeout(()=>{
this.el.nativeElement.scrollIntoView({
behavior: 'instant',
});
})
})
}