@viewChild 不工作 - 无法读取未定义的 属性 nativeElement
@viewChild not working - cannot read property nativeElement of undefined
我正在尝试访问本机元素,以便在单击另一个元素时关注它(很像 html 属性 "for" - 因为不能用于此类元素.
但是我收到错误:
TypeError: Cannot read property 'nativeElement' of undefined
我尝试 console.log ngAfterViewInit()
中的 nativeElement 以便加载它,但它仍然会引发错误。
我还在点击事件处理程序中访问 nativeElement,这样我就可以在点击另一个元素时聚焦该元素 - 这可能是它的问题,因为它在视图加载之前编译了吗?
例如:
ngAfterViewInit() {
console.log(this.keywordsInput.nativeElement); // throws an error
}
focusKeywordsInput(){
this.keywordsInput.nativeElement.focus();
}
完整代码:
正在使用的 html 模板的相关部分:
<div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
<input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
<div class="form-control-icon" id="keywords-icon"></div>
</div>
component.ts:
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES,
FormGroup,
FormBuilder,
Validators,
ControlValueAccessor
} from '@angular/forms';
import { NumberPickerComponent } from './number-picker.component';
import { DistanceUnitsComponent } from './distance-units.component';
import { MapDemoComponent } from '../shared/map-demo.component';
import { AreaComponent } from './area-picker.component';
import { GoComponent } from './go.component';
import { HighlightDirective } from '../highlight.directive';
@Component({
selector: 'find-form',
templateUrl: 'app/find-page/find-form.component.html',
styleUrls: ['app/find-page/find-form.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES,
NumberPickerComponent,
DistanceUnitsComponent,
MapDemoComponent,
AreaComponent,
GoComponent]
})
export class FindFormComponent implements OnInit, AfterViewInit {
findForm: FormGroup;
submitted: boolean; // keep track on whether form is submitted
events: any[] = []; // use later to display form changes
@ViewChild('keywords-input') keywordsInput;
//comment
constructor(private formBuilder: FormBuilder, el: ElementRef) {}
ngOnInit() {
this.findForm = this.formBuilder.group({
firstname: ['', [ Validators.required, Validators.minLength(5) ] ],
lastname: ['', Validators.required],
keywords: [],
area: ['', Validators.required],
address: this.formBuilder.group({
street: [],
zip: [],
city: []
})
});
this.findForm.valueChanges.subscribe(data => console.log('form changes', data));
}
ngAfterViewInit() {
console.log(this.keywordsInput.nativeElement); // throws an error
}
focusKeywordsInput(){
this.keywordsInput.nativeElement.focus();
}
save(isValid: boolean) {
this.submitted = true;
// check if model is valid
// if valid, call API to save customer
console.log(isValid);
}
}
完整 html 模板(可能不相关):
<form class="text-uppercase" [formGroup]="findForm" (ngSubmit)="save(findForm.value, findForm.valid)">
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">find vegan</h2>
</div>
</div>
<div class="row has-error-text">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<multiselect #multiselect></multiselect>
</div>
</div>
</div>
<div class="row error-text" [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
<small>Please select at least 1 category.</small>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">within</h2>
</div>
</div>
<div class="row">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block;">
<number-picker #numberPicker></number-picker>
</div>
<distance-units></distance-units>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">of</h2>
</div>
</div>
<div class="row has-error-text">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<my-area></my-area>
</div>
</div>
</div>
<div class="row error-text" [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
<small [hidden]="findForm.controls.firstname.valid || (findForm.controls.firstname.pristine && !submitted)">Please enter an area.</small>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">keywords</h2>
</div>
</div>
<div class="row form-group">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
<input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
<div class="form-control-icon" id="keywords-icon"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<go></go>
</div>
</div>
</div>
</form>
@ViewChild('keywords-input') keywordsInput;
不匹配 id="keywords-input"
id="keywords-input"
应该改为模板变量:
#keywordsInput
请注意,应使用驼峰式大小写,因为模板引用名称中不允许使用 -
。
@ViewChild()
支持模板变量的名称为字符串:
@ViewChild('keywordsInput') keywordsInput;
或组件或指令类型:
@ViewChild(MyKeywordsInputComponent) keywordsInput;
另见
提示:
在调用 ngAfterViewInit()
之前未设置 keywordsInput
如果您的目标元素位于隐藏元素内,您也会收到此错误。如果这是你的 HTML:
<div *ngIf="false">
<span #sp>Hello World</span>
</div>
您的 @ViewChild('sp') sp
将是未定义的。
解决方案
在这种情况下,请不要使用*ngIf
。
而是使用 class 来 show/hide 您的元素被隐藏。
<div [class.show]="shouldShow">...</div>
很简单:导入这个目录
import {Component, Directive, Input, ViewChild} from '@angular/core';
如果在加载 DOM 之前调用这些元素,就会出现此类错误。始终使用:
window.onload = function(){
this.keywordsInput.nativeElement.focus();
}
接受的答案在所有方面都是正确的,在我无法在我的应用程序组件之一中获得 Google 地图渲染后,我偶然发现了这个线程。
现在,如果您使用的是最新的 angular 版本,即 angular 的 7+,那么您将不得不处理以下 ViewChild 声明,即
@ViewChild(selector: string | Function | Type<any>, opts: {
read?: any;
static: boolean;
})
现在,有趣的部分是静态值,根据定义,它表示
- static - True 在更改检测运行之前解析查询结果
现在为了渲染地图,我使用了以下内容,
@ViewChild('map', { static: true }) mapElement: any;
map: google.maps.Map;
像下面这样初始化 Canvas 适用于 TypeScript/Angular 解决方案。
const canvas = <HTMLCanvasElement> document.getElementById("htmlElemId");
const context = canvas.getContext("2d");
有时,当您尝试定位包含在条件中的元素时会发生此错误,例如:
<div *ngIf="canShow"> <p #target>Targeted Element</p></div>
在此代码中,如果 canShow
在渲染时为 false,Angular 将无法获取该元素,因为它不会被渲染,因此会出现错误。
其中一个解决方案是在元素上使用 display: hidden
而不是 *ngIf
,这样元素会被渲染但会隐藏,直到您的条件得到满足。
阅读更多over at Github
当您尝试定位包含在条件中的元素时,会发生此错误。
所以,如果我在这里使用 ngIf 代替 [hidden],它会给我 TypeError: Cannot read 属性 'nativeElement' of undefined
因此请使用 [hidden]、class.show 或 class.hide 代替 *ngIf。
<button (click)="displayMap()" class="btn btn-primary">Display Map</button>
<div [hidden]="!display">
<div #mapContainer id="map">Content to render when condition is true.</div>
</div>
我遇到了类似的问题,但在我的例子中,我试图读取 ngOnInit
方法中的 nativeElement
:
@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngOnInit(): void {
this.userNameInput.nativeElement.focus();
}
我已更改为 ngAfterViewInit
,一切正常:
@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngAfterViewInit(): void {
this.userNameInput.nativeElement.focus();
}
在我的例子中,我只是检查 undefied
` @ViewChild('myinput') myInputField: ElementRef;
ngAfterViewInit() {
if (this.myInputField !== undefined) {
this.myInputField.nativeElement.focus();
}
}
我正在尝试访问本机元素,以便在单击另一个元素时关注它(很像 html 属性 "for" - 因为不能用于此类元素.
但是我收到错误:
TypeError: Cannot read property 'nativeElement' of undefined
我尝试 console.log ngAfterViewInit()
中的 nativeElement 以便加载它,但它仍然会引发错误。
我还在点击事件处理程序中访问 nativeElement,这样我就可以在点击另一个元素时聚焦该元素 - 这可能是它的问题,因为它在视图加载之前编译了吗?
例如:
ngAfterViewInit() {
console.log(this.keywordsInput.nativeElement); // throws an error
}
focusKeywordsInput(){
this.keywordsInput.nativeElement.focus();
}
完整代码:
正在使用的 html 模板的相关部分:
<div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
<input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
<div class="form-control-icon" id="keywords-icon"></div>
</div>
component.ts:
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { REACTIVE_FORM_DIRECTIVES,
FormGroup,
FormBuilder,
Validators,
ControlValueAccessor
} from '@angular/forms';
import { NumberPickerComponent } from './number-picker.component';
import { DistanceUnitsComponent } from './distance-units.component';
import { MapDemoComponent } from '../shared/map-demo.component';
import { AreaComponent } from './area-picker.component';
import { GoComponent } from './go.component';
import { HighlightDirective } from '../highlight.directive';
@Component({
selector: 'find-form',
templateUrl: 'app/find-page/find-form.component.html',
styleUrls: ['app/find-page/find-form.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES,
NumberPickerComponent,
DistanceUnitsComponent,
MapDemoComponent,
AreaComponent,
GoComponent]
})
export class FindFormComponent implements OnInit, AfterViewInit {
findForm: FormGroup;
submitted: boolean; // keep track on whether form is submitted
events: any[] = []; // use later to display form changes
@ViewChild('keywords-input') keywordsInput;
//comment
constructor(private formBuilder: FormBuilder, el: ElementRef) {}
ngOnInit() {
this.findForm = this.formBuilder.group({
firstname: ['', [ Validators.required, Validators.minLength(5) ] ],
lastname: ['', Validators.required],
keywords: [],
area: ['', Validators.required],
address: this.formBuilder.group({
street: [],
zip: [],
city: []
})
});
this.findForm.valueChanges.subscribe(data => console.log('form changes', data));
}
ngAfterViewInit() {
console.log(this.keywordsInput.nativeElement); // throws an error
}
focusKeywordsInput(){
this.keywordsInput.nativeElement.focus();
}
save(isValid: boolean) {
this.submitted = true;
// check if model is valid
// if valid, call API to save customer
console.log(isValid);
}
}
完整 html 模板(可能不相关):
<form class="text-uppercase" [formGroup]="findForm" (ngSubmit)="save(findForm.value, findForm.valid)">
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">find vegan</h2>
</div>
</div>
<div class="row has-error-text">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<multiselect #multiselect></multiselect>
</div>
</div>
</div>
<div class="row error-text" [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
<small>Please select at least 1 category.</small>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">within</h2>
</div>
</div>
<div class="row">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block;">
<number-picker #numberPicker></number-picker>
</div>
<distance-units></distance-units>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">of</h2>
</div>
</div>
<div class="row has-error-text">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<my-area></my-area>
</div>
</div>
</div>
<div class="row error-text" [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
<small [hidden]="findForm.controls.firstname.valid || (findForm.controls.firstname.pristine && !submitted)">Please enter an area.</small>
</div>
</div>
<div class="row is-heading">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
<h2 class="search-filter-heading heading m-x-auto">keywords</h2>
</div>
</div>
<div class="row form-group">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
<input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
<div class="form-control-icon" id="keywords-icon"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
<div style="position: relative; display: inline-block; width: 100%;">
<go></go>
</div>
</div>
</div>
</form>
@ViewChild('keywords-input') keywordsInput;
不匹配 id="keywords-input"
id="keywords-input"
应该改为模板变量:
#keywordsInput
请注意,应使用驼峰式大小写,因为模板引用名称中不允许使用 -
。
@ViewChild()
支持模板变量的名称为字符串:
@ViewChild('keywordsInput') keywordsInput;
或组件或指令类型:
@ViewChild(MyKeywordsInputComponent) keywordsInput;
另见
提示:
在调用 ngAfterViewInit()
之前未设置 keywordsInput
如果您的目标元素位于隐藏元素内,您也会收到此错误。如果这是你的 HTML:
<div *ngIf="false">
<span #sp>Hello World</span>
</div>
您的 @ViewChild('sp') sp
将是未定义的。
解决方案
在这种情况下,请不要使用*ngIf
。
而是使用 class 来 show/hide 您的元素被隐藏。
<div [class.show]="shouldShow">...</div>
很简单:导入这个目录
import {Component, Directive, Input, ViewChild} from '@angular/core';
如果在加载 DOM 之前调用这些元素,就会出现此类错误。始终使用:
window.onload = function(){
this.keywordsInput.nativeElement.focus();
}
接受的答案在所有方面都是正确的,在我无法在我的应用程序组件之一中获得 Google 地图渲染后,我偶然发现了这个线程。
现在,如果您使用的是最新的 angular 版本,即 angular 的 7+,那么您将不得不处理以下 ViewChild 声明,即
@ViewChild(selector: string | Function | Type<any>, opts: {
read?: any;
static: boolean;
})
现在,有趣的部分是静态值,根据定义,它表示
- static - True 在更改检测运行之前解析查询结果
现在为了渲染地图,我使用了以下内容,
@ViewChild('map', { static: true }) mapElement: any;
map: google.maps.Map;
像下面这样初始化 Canvas 适用于 TypeScript/Angular 解决方案。
const canvas = <HTMLCanvasElement> document.getElementById("htmlElemId");
const context = canvas.getContext("2d");
有时,当您尝试定位包含在条件中的元素时会发生此错误,例如:
<div *ngIf="canShow"> <p #target>Targeted Element</p></div>
在此代码中,如果 canShow
在渲染时为 false,Angular 将无法获取该元素,因为它不会被渲染,因此会出现错误。
其中一个解决方案是在元素上使用 display: hidden
而不是 *ngIf
,这样元素会被渲染但会隐藏,直到您的条件得到满足。
阅读更多over at Github
当您尝试定位包含在条件中的元素时,会发生此错误。
所以,如果我在这里使用 ngIf 代替 [hidden],它会给我 TypeError: Cannot read 属性 'nativeElement' of undefined
因此请使用 [hidden]、class.show 或 class.hide 代替 *ngIf。
<button (click)="displayMap()" class="btn btn-primary">Display Map</button>
<div [hidden]="!display">
<div #mapContainer id="map">Content to render when condition is true.</div>
</div>
我遇到了类似的问题,但在我的例子中,我试图读取 ngOnInit
方法中的 nativeElement
:
@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngOnInit(): void {
this.userNameInput.nativeElement.focus();
}
我已更改为 ngAfterViewInit
,一切正常:
@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngAfterViewInit(): void {
this.userNameInput.nativeElement.focus();
}
在我的例子中,我只是检查 undefied
` @ViewChild('myinput') myInputField: ElementRef;
ngAfterViewInit() {
if (this.myInputField !== undefined) {
this.myInputField.nativeElement.focus();
}
}