英文:
Div id is null when using ngAfterViewInit
问题
在我的应用程序中,我正在使用Angular,并尝试在页面加载后立即访问一个div。我已导入AfterViewInit如下所示:
import { Component, OnInit, ViewChild, AfterViewInit, ElementRef } from '@angular/core';
创建了一个变量:
@ViewChild('editPreamblesInput') editPreamblesInput: ElementRef;
然后实现了ngAfterViewInit:
ngAfterViewInit(){
const result = this.editPreamblesInput.nativeElement;
console.log(result);
}
我的HTML如下:
<div id="editPreamblesInput" #editPreamblesInput (mouseenter)="userEditable && isUrl? displayPreamblesLink.show() : null" (mouseleave)="displayPreamblesLink.hide()">
<input-validation>
<igx-input-group>
<input igxInput name="preamblesRef" id="preamblesRef" type="text" formControlName="preamblesRef" [readonly]="!userEditable"
inputValidationDirective [control]="libraryForm.controls['preamblesRef']"/>
<label igxLabel for="preamblesRef">Preambles Reference</label>
</igx-input-group>
</input-validation>
<igx-action-strip #displayPreamblesLink [displayDensity]="displayDensity" class="action-strip" [hidden]="true">
<igx-buttongroup [multiSelection]="true" class="buttons">
<button igxButton type="button" (click)="editPreamblesRef()">
<igx-icon>link</igx-icon>
</button>
</igx-buttongroup>
</igx-action-strip>
</div>
然而,当我查看控制台时,我得到以下错误:
ERROR TypeError: Cannot read properties of undefined (reading 'nativeElement')
at LibrarySetupComponent.ng
并且editPreamblesInput
是null。我不确定为什么它是null以及我漏掉了什么?
编辑:
所以我弄清楚了为什么会发生这种情况。这个div是表单的一部分,只有在一个名为loaded的布尔值设置为true时才会显示:
<form *ngIf="loaded" [formGroup]="libraryForm" (ngSubmit)="onSubmit()">
这是在一个名为getData()的方法中设置的:
getData() {
this.libraryService.getAll().subscribe({
next: (libraries) => {
this.libraryList = libraries;
if(this.route.snapshot.params['libraryId']) {
const library = this.libraryList.find(l => l.id == this.route.snapshot.params['libraryId']);
this.patchLibrary(library);
} else {
this.patchLibrary(this.getNewLibrary());
}
this.loaded = true;
},
error: (err) => {
this.alertService.error(`Error getting ${this.alertVariable} data - ${err.message}`);
}
});
}
然后在ngOnInit方法中调用它。loaded的默认值为false,如果我将其更改为true,然后我可以访问该元素。所以我想我可以这样做:
complete:() => {
const test = document.getElementById("editPreamblesInput");
console.log(test);
}
然而,test显示为null。所以我在思考是否需要找到一种方法,告诉它在boolean为true之前等待访问它,但不确定如何做。
英文:
In my application I am using angular, and I am trying to access a div right after the page loads. I have imported Afterviewinit like so:
import { Component, OnInit, ViewChild, AfterViewInit, ElementRef } from '@angular/core';
created a variable:
@ViewChild('editPreamblesInput') editPreamblesInput: ElementRef;
and then implemented ngAfterViewInit like so:
ngAfterViewInit(){
const result = this.editPreamblesInput.nativeElement;
console.log(result);
}
my html is like:
<div id="editPreamblesInput" #editPreamblesInput (mouseenter)="userEditable && isUrl? displayPreamblesLink.show() : null" (mouseleave)="displayPreamblesLink.hide()">
<input-validation>
<igx-input-group>
<input igxInput name="preamblesRef" id="preamblesRef" type="text" formControlName="preamblesRef" [readonly]="!userEditable"
inputValidationDirective [control]="libraryForm.controls['preamblesRef']"/>
<label igxLabel for="preamblesRef">Preambles Reference</label>
</igx-input-group>
</input-validation>
<igx-action-strip #displayPreamblesLink [displayDensity]="displayDensity" class="action-strip" [hidden]="true">
<igx-buttongroup [multiSelection]="true" class="buttons">
<button igxButton type="button" (click)="editPreamblesRef()">
<igx-icon>link</igx-icon>
</button>
</igx-buttongroup>
</igx-action-strip>
</div>
However, when I look at my console I get the error:
ERROR TypeError: Cannot read properties of undefined (reading 'nativeElement')
at LibrarySetupComponent.ng
and editPreamnlesInput is null.
I'm not sure why this is null and what I am missing?
Edit:
So I've figured out why this is happening.
The div is a part of a form which only shows if a boolean called loaded is set to true:
<form *ngIf="loaded" [formGroup]="libraryForm" (ngSubmit)="onSubmit()">
this gets set to true in a method called getData():
getData() {
this.libraryService.getAll().subscribe({
next: (libraries) => {
this.libraryList = libraries;
if(this.route.snapshot.params['libraryId']) {
const library = this.libraryList.find(l => l.id == this.route.snapshot.params['libraryId']);
this.patchLibrary(library);
} else {
this.patchLibrary(this.getNewLibrary());
}
this.loaded = true;
},
error: (err) => {
this.alertService.error(`Error getting ${this.alertVariable} data - ${err.message}`);
}
});
}
this is then called in the ngOnInit method. loaded has a default value of false, if I change this to true I can then access that element. So I thought I could do something like:
complete:() => {
const test = document.getElementById("editPreamblesInput");
console.log(test);
however test comes up as null. So I'm thinking I need to find a way so that I tell it to wait until the boolean is true before it tries to access it but not sure how
答案1
得分: 1
你需要使用模板变量来访问它。
在你的模板中:
<div #div>Hello, world!</div>
在你的组件中:
@Component({ ...})
export class MyComponent implements AfterViewInit {
@ViewChild('div') div?: ElementRef;
ngAfterViewInit(): void {
if (this.div) {
console.log(this.div);
}
}
}
这里有一个 StackBlitz 示例以查看它的运行情况:
https://stackblitz.com/edit/angular-l1qyro?file=src%2Fmain.ts
英文:
You need to use a template variable to access it.
Inside your template:
<div #div>Hello, world!</div>
Inside your component:
@Component({ ...})
export class MyComponent implements AfterViewInit {
@ViewChild('div') div?: ElementRef;
ngAfterViewInit(): void {
if (this.div) {
console.log(this.div);
}
}
}
Here's a StackBlitz to see it in action:
https://stackblitz.com/edit/angular-l1qyro?file=src%2Fmain.ts
答案2
得分: 0
editPreamblesInput 元素在调用 ngAfterViewInit 时可用,您可以将您的代码包装在一个带有最小延迟的 setTimeout 函数中。就像这样:
ngAfterViewInit() {
setTimeout(() => {
const result = this.editPreamblesInput.nativeElement;
console.log(result);
}, 0);
}
另外,
@ViewChild('editPreamblesInput', { static: false }) editPreamblesInput: ElementRef;
{ static: false } 选项用于查询的元素位于结构性指令内,例如 ngIf 或 ngFor。这确保元素在运行时动态解析。
希望它能够工作。
英文:
editPreamblesInput element is available when ngAfterViewInit is called, you can wrap your code in a setTimeout function with a minimal delay. like
ngAfterViewInit() {
setTimeout(() => {
const result = this.editPreamblesInput.nativeElement;
console.log(result);
}, 0);
}
Additionally
@ViewChild('editPreamblesInput', { static: false }) editPreamblesInput: ElementRef;
{ static: false } option is used when the queried element is inside a structural directive such as *ngIf or *ngFor. This ensures that the element is resolved dynamically during runtime.
hope it's work
答案3
得分: 0
这不是最佳代码,但它会工作:
ngAfterViewInit() {
const interval = setInterval(() => {
const result = this.editPreamblesInput.nativeElement;
if (result != null) {
console.log(result);
clearInterval(interval);
}
}, 100)
}
这段代码将每100毫秒执行一次,直到result不为null和undefined为止!这不是最佳代码,因为保持执行代码会有性能成本,但考虑到`setInterval`内部的代码相对较轻,应该没问题。
英文:
This is not the best code but it will work:
ngAfterViewInit() {
const interval = setInterval(() => {
const result = this.editPreamblesInput.nativeElement;
if (result != null) {
console.log(result);
clearInterval(interval);
}
}, 100)
}
This code will keep executing every 100ms until result is not null and not undefined! Not the best code because there's a performance cost to keep executing code but given that the code inside setInterval
is fairly lightweight you should be OK.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论