问题
My setup is an Angular Material data table with clickable rows. When a row is clicked, its contents are shown inline in a textarea
for editing. My only problem is, I try to move input focus to the shown textarea
. I tried to do it using @ViewChild
, but it's being populated later, when the click handler has already executed.
Some code, to illustrate:
app.component.ts:
import {Component, ElementRef, ViewChild} from '@angular/core';
@Component({ selector: 'app-root', templateUrl: './app.component.html' })
export class AppComponent {
columns = ['id', 'def'];
selected: string;
ruleDef: string;
@ViewChild('edit') editArea: ElementRef;
selectRule(rule: Rule) {
this.selected = rule.id;
if (this.editArea) this.editArea.nativeElement.focus();
}
}
interface Rule {id: string, def: string}
app.component.html:
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef>Rule ID</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.id}}</mat-cell>
</ng-container>
<ng-container matColumnDef="def">
<mat-header-cell *matHeaderCellDef>Rule Definition</mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-form-field *ngIf="element.id === selected">
<code><textarea matInput [(ngModel)]="ruleDef" #edit></textarea></code>
</mat-form-field>
<code *ngIf="element.id !== selected">{{element.def}}</code>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columns"></mat-header-row>
<mat-row *matRowDef="let row; columns: columns;" (click)="selectRule(row)"></mat-row>
</mat-table>
In the selectRule()
function, the editArea
is either undefined
, or points to a row selected previously. Obviously the selectRule()
is a wrong place to put the focus change into, but I couldn't find an appropriate event handler in Angular
回答1:
You must wait for the zone to settle before setting focus.
It could be done the same way as is used in angular material:
import {take} from 'rxjs/operators/take';
constructor(private zone: NgZone) { }
selectRule(rule: Rule) {
this.selected = rule.id;
this.zone.onMicrotaskEmpty.asObservable().pipe(
take(1)
)
.subscribe(() => {
this.editArea.nativeElement.focus();
});
}
Ng-run Example
来源:https://stackoverflow.com/questions/49036289/how-to-detect-when-a-view-element-is-rendered-in-angular