Q:

How to access a template variable reference in a specific row of an Angular Material table? (Angular 7)

I'm currently trying to implement a more complex version of the following behavior, but as I will not have access to my project until Monday, I'll simplify for the sake of it, using an altered example from Angular Material's tutorials.
An Angular Material table is filled with data from a string array. Data is presented in an input field on the first column. On the second column of every row is a set of buttons that, when pressed, change the contents of their line's input.

I've tried to identify the input element through the use of a template reference variable, but it always turns up as undefined. So I assume Angular Material's table is doing something behind my back that changes the scope of said variable.
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">

    <ng-container matColumnDef="inputColumn">
        <th mat-header-cell *matHeaderCellDef> No. </th>
        <td mat-cell *matCellDef="let element">
            <input #inputRef placeholder="{{element.name}}">
        </td>
    </ng-container>

    <ng-container matColumnDef="buttonColumn">
        <th mat-header-cell *matHeaderCellDef> Name </th>
        <td mat-cell *matCellDef="let element">
            <button (click)="inputRef.value='Changed Element'">Change!</button>
        </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

On my actual project, data will come from an API, and there will also be more buttons that will either enable the input, save or discard changes made to its content and so forth. But if I manage to get this example to work, then the remainder should be pretty straight forward.
Any help would be greatly appreciated.

A:

You can solve this by using ViewChildren to access all the input elements in your table and identifying them via the id attribute for example.

Check out this stackblitz where I threw together a quick solution.

Basically all I did in the template was to add the matInput directive to your input elements and uniquely identify each one of the via the id attribute (just assigning the inputColumn variable of the current row element):
<mat-form-field>
  <input matInput id="{{element.inputColumn}}" placeholder="{{element.inputColumn}}">
</mat-form-field>

Added a function call on your button where we pass the current rows element:
<button mat-raised-button (click)="changeValue(element)">{{element.buttonColumn}}</button>

In the component we retrieve all the input elements with the matInput directive:
@ViewChildren(MatInput) matInputs: QueryList<MatInput>;

And then in the function that gets called by the buttons we search for the correct matInput via the id that corresponds to the element's inputColumn value:
changeValue(element: TableData) {
  const input = this.matInputs.find(matInput => matInput.id === element.inputColumn);
  input.value = 'Changed!';
}

I am sure there are other ways to solve this, not sure how this behaves if you have a lot of buttons/rows.

