I have a template which uses MatInput
from Angular Material. I am trying to access this component from code using @ViewChild
so I can programmatically alter the focused
state, but this MatInput
is not there when the view initializes - its presence is determined by an *ngIf
directive. Basically, when the view loads, there is a p
element with some text. If a user clicks that element, it will be replaced with an input
where the starting value is the text of the original element. When it loses focus, it is saved and reverts back to a p
element. The problem is that when they first click on the text to change it, the input
that's created does not have focus - they have to click it again to start editing. I want them to be able to click once and start typing.
Here's my relevant code.
Template:
<mat-form-field *ngIf="selected; else staticText" class="full-width">
<input matInput type="text" [(ngModel)]="text" (blur)="save()">
</mat-form-field>
<ng-template #staticText>
<p class="selectable" (click)="select()">{{ text }}</p>
</ng-template>
Typescript:
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import { MatInput } from '@angular/material';
import { AfterViewInit } from '@angular/core/src/metadata/lifecycle_hooks';
@Component({
selector: 'app-click-to-input',
templateUrl: './click-to-input.component.html',
styleUrls: ['./click-to-input.component.scss']
})
export class ClickToInputComponent implements AfterViewInit {
@Input() text: string;
@Output() saved = new EventEmitter<string>();
@ViewChild(MatInput) input: MatInput;
selected = false;
ngAfterViewInit(): void {
console.log(this.input); // shows undefined - no elements match the ViewChild selector at this point
}
save(): void {
this.saved.emit(this.text);
this.selected = false;
}
select(): void {
this.selected = true; // ngIf should now add the input to the template
this.input.focus(); // but input is still undefined
}
}
From the docs:
You can use ViewChild to get the first element or the directive matching the selector from the view DOM. If the view DOM changes, and a new child matches the selector, the property will be updated.
Is *ngIf
working too slow, and I'm trying to access this.input
too soon before the property is updated? If so, how can I wait until *ngIf
is done replacing the DOM and then access the MatInput
? Or is there some other way to solve my focusing problem altogether that I'm just not seeing?