my question is that is there a way so that I can get element reference of a particular row in mat-table. I am getting the data from an API. I want to display popover over a row in mat-table and popover requires element reference or HTML element to get attached to. Is there a way to do this?
-
There is a way for almost anything. Share your code, please – Belegnar Jul 05 '20 at 10:41
-
@Belegnar yes Sure My popover functions looks like this: showPopover(template: TemplateRef
, target: HTMLElement | ElementRef – Ashutosh Sharma Jul 07 '20 at 11:18, position: string, backdrop: boolean): void { setTimeout(() => this.popoverService.open(template, target, position, backdrop, {}), 200); } I am building a website tour. I have a table and lets say I have a button next in popovers when I click on it it shows the next popover. So when I click next I the popover should be displayed at particular row. But I don't know how to do it.
2 Answers
You may no longer need this answer, but I had a hard time tracking it down, so I'm going to leave the solution here for others who were performing the same searches as I.
Typically, you can access DOM elements by using Angular's ViewChildren
decorator. However in this instance, your table rows use the mat-row
directive, which means that ViewChildren
will instead return the Angular Material MatRow objects, with no (clean) path to the rendered rows. However, you can configure ViewChildren
to explicitly pass the ElementRef
instead (which I discovered in this answer).
So add a template variable reference to your row elements in your HTML file:
<table mat-table [dataSource]="dataSource">
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<!-- // #tableBodyRow below is your new template reference variable -->
<tr #tableBodyRow mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<!-- // Rest of your table definition here -->
</table>
And then in your component.ts
file, use ViewChildren
to access those elements, indicating that you want the DOM element specifically:
// The second parameter to the ViewChildren decorator is the key to getting
// the DOM elements
//
// The first parameter must match the template reference variable name you
// indicated in your HTML template.
@ViewChildren('tableBodyRow', {read: ElementRef}) renderedBodyRows: QueryList<
ElementRef<HTMLTableRowElement>
>;
You can now access the DOM elements created by MatTable
. 2 caveats:
- Items referenced by the
ViewChildren
decorator are only accessible afterngAfterViewInit
has run - see the Angular documentation. If you don't know what I'm talking about here, wrap therenderedBodyRows
variable in a getter function and expect it to returnundefined
while your table is being rendered. - The rows returned by this process do not appear to be in the order they are displayed in the DOM. If order/indices are important to you, make sure to perform some type of sorting based on the row content related to your dataSource object. If you're stuck, try assigning a class or other property to the rows in your
mat-row
definition based on the index.

- 153
- 1
- 7
In mat-table
, when you use row as:
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
Here, row is the ElementRef
, you can pass row in click
or hover
event, however you want.

- 424
- 2
- 9
-
thanx for your response. Actually I am building a website tour. I don't want to show popover when the user hovers or click. I need element reference already so that when the user clicks on next it takes it to that particular row. – Ashutosh Sharma Jul 07 '20 at 11:24
-
when you show column values you use `*matCellDef="let element"`, you can pass 'element' to your button click function. – Nitika Jul 08 '20 at 12:16
-
This isn't correct. *row* is a reference to a variable - the current item in the *dataSource* input to `mat-table`. It is not the instance of the `HTMLTableRowElement` generated in the DOM, which is what the Angular `ElementRef` object contains. – Aaron J Feb 23 '23 at 16:50