angular - 当 ngIf 可能删除 Angular 组件时,如何从 typescript 中引用它?

标签 angular typescript angular-material angular-components

我有一个使用 Angular Material 中的 MatInput 的模板。我正在尝试使用 @ViewChild 从代码访问此组件,因此我可以通过编程方式更改 focused 状态,但是当 View 初始化 - 它的存在由 *ngIf 指令确定。基本上,当 View 加载时,有一个带有一些文本的 p 元素。如果用户单击该元素,它将被替换为 input,其中起始值是原始元素的文本。当它失去焦点时,它会被保存并恢复为 p 元素。问题是,当他们第一次单击文本进行更改时,创建的 input 没有焦点 - 他们必须再次单击它才能开始编辑。我希望他们能够单击一次并开始输入。

这是我的相关代码。

模板:

<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
  }
}

来自文档:

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.

*ngIf 是否工作太慢,我试图在属性更新之前过早地访问 this.input?如果是这样,我如何才能等到 *ngIf 完成替换 DOM,然后访问 MatInput?或者是否有其他方法可以完全解决我只是没有看到的聚焦问题?

最佳答案

我在 this stackblitz 中复制了您的案例.设置 this.selected = true 后,Angular 必须执行更改检测以显示 mat-form-field 元素,这通常会在当前执行周期之后发生。立即访问输入元素的一种方法是在代码中触发更改检测,例如使用 ChangeDetector.detectChanges(有关其他技术,请参阅 this answer):

import { Component, ChangeDetectorRef, ViewChild } from '@angular/core';
import { MatInput } from '@angular/material';

@Component({
  ...
})
export class FormFieldPrefixSuffixExample {

  @ViewChild(MatInput) input: MatInput;

  text = "Hello world!"
  selected = false;

  constructor(private changeDetector: ChangeDetectorRef) {
  }

  select(): void {
    this.selected = true;
    this.changeDetector.detectChanges();
    this.input.focus();
  }  
}

另一种解决方法,suggested by kiranghule27 , 是通过使其异步来延迟对 this.input.focus() 的调用:

  select(): void {
    this.selected = true;
    setTimeout(() => {
      this.input.focus();
    }, 0);
  }  

关于angular - 当 ngIf 可能删除 Angular 组件时,如何从 typescript 中引用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48083033/

相关文章:

javascript - Angular 5 StaticInjectorError :[Http]

java - 在没有spring boot的情况下使用spring mvc项目配置angular 2

angular - Localhost 为我的 Angular 应用程序发送了无效响应

typescript :意外未知

javascript - 如何使用 Jest 正确实现这样的测试套件架构?

angular - 在子文件夹下部署 Angular SPA

angular - 无法从 Webpack 配置向 Angular 2 提供环境变量

angular - 如何将 [formControlName] 与 mat-checkbox 一起使用

angularjs - 警告 : Added non-passive event listener to a scroll-blocking 'touchmove' event when md-select is in md-tabs

angular - 如何将 'on' 、 'off' 标签添加到 mat-slide-toggle ?