关于dom:Angular 2 @ViewChild返回未定义

Angular 2 @ViewChild returns undefined

我看了几篇相关的文章和文档,但是似乎仍然无法从@ViewChild获得预期的行为。

最终,我试图设置div的滚动位置。这个元素不是组件,而是HTML中的普通div。

为此,我尝试使用@ViewChild来获取所需的DOM元素并设置其滚动值。 (顺便说一句,如果您知道一种无需@ViewChild(或jQuery)的更好的方法,将非常感谢您提供答案!)

目前,@ ViewChild仅返回未定义。通过一些虚拟检查:
-我在AfterViewInit中访问我的元素
-在此元素上,我没有任何其他指令,例如* ngIf或* ngFor。

这是控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
    selector: 'portfolio-page',
    templateUrl: './portfolio-page.component.html',
    styleUrls: ['./portfolio-page.component.scss']
})

export class PortfolioPageComponent implements AfterViewInit{
    @ViewChild('gallery-container') galleryContainer: ElementRef;

    ngAfterViewInit(){
        console.log('My element: ' + this.galleryContainer);
    }
}

和模板:

1
2
    <img class='gallery-image' src='{{ coverPhotoVm }}' />
    <img class='gallery-image' src='{{ imagepath }}' *ngFor='let imagepath of imagesVm' />

我的输出很简单:我的元素:未定义。

如您所见,我当前正在尝试通过ID访问元素,但是也尝试过使用类名。任何人都可以提供有关ViewChild选择器查询的更多详细信息吗?

我也看到了一些示例,其中使用哈希值'#'作为@ViewChild使用的选择符标识符--但这会导致#gallery-container对我造成模板解析错误。

我想不到这里可能有其他错误的地方。感谢所有帮助,谢谢!

此处提供完整代码:https://github.com/aconfee/KimbyArting/tree/master/client/KimbyArting/components/portfolio-page


尝试在模板中使用ref:

1
2
    <img class='gallery-image' src='{{ coverPhotoVm }}' />
    <img class='gallery-image' src='{{ imagepath }}' *ngFor='let imagepath of imagesVm' />

并使用ref名称作为参数:

1
@ViewChild('galleryContainer') galleryContainer: ElementRef;

编辑

忘了提及如此声明的任何视图子级仅在视图初始化后可用。第一次发生这种情况是在ngAfterViewInit中(导入并实现AfterViewInit接口)。

引用名称不得包含破折号,否则将不起作用


有时,如果在访问组件时尚未对其进行初始化,则会收到一条错误消息,指出子组件未定义。

但是,即使您访问AfterViewInit中的子组件,有时@ViewChild仍返回null。该问题可能是由* ngIf或其他指令引起的。

解决方案是使用@ViewChildren而不是@ViewChild并订阅在组件就绪时执行的更改订阅。

例如,如果要在父组件ParentComponent中访问子组件MyComponent。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, ViewChildren, AfterViewInit, QueryList } from '@angular/core';
import { MyComponent } from './mycomponent.component';

export class ParentComponent implements AfterViewInit
{
  //other code emitted for clarity

  @ViewChildren(MyComponent) childrenComponent: QueryList<MyComponent>;

  public ngAfterViewInit(): void
  {
    this.childrenComponent.changes.subscribe((comps: QueryList<MyComponent>) =>
    {
      // Now you can access the child component
    });
  }
}


订阅变更

1
@ViewChildren(MyComponent) childrenComponent: QueryList<MyComponent>

确定有效,并结合setTimeout()notifyOnChanges()并仔细检查null

任何其他方法都会产生不可靠的结果,并且难以测试。


这是ViewChild使用DOM元素的.ts文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({

    selector: 'portfolio-page',
    templateUrl: './portfolio-page.component.html',
    styleUrls: ['./portfolio-page.component.scss']
})

export class PortfolioPageComponent implements AfterViewInit{

    @ViewChild('galleryContainer') galleryContainer: ElementRef;

    ngAfterViewInit(){
        console.log('My element: ' + this.galleryContainer);
    }
}

这是您的.html文件代码

1
2
    <img class='gallery-image' src='{{ coverPhotoVm }}' />
    <img class='gallery-image' src='{{ imagepath }}' *ngFor='let imagepath of imagesVm' />

希望能帮助到你!


另一种可能的情况是,当您在有角度或离子性的框架中使用打字稿,并从具有类似于签名的javascript的函数中调用ViewChild元素时。请改用类似函数签名的打字稿(例如,使用粗箭头=>)。
例如

1
2
3
accessViewChild(){
    console.log(this.galleryContainer.nativeElement.innerHTML);
}

将显示未定义的打印

1
2
3
accessViewChild = ()=>{
    console.log(this.galleryContainer.nativeElement.innerHTML);
}

将打印内部html。


我今天有同样的问题。奇怪地使用setTimeout为我工作。

试试看:

1
2
3
ngAfterViewInit(){
    setTimeout(_ => console.log('My element: ' + this.galleryContainer), 0);
}


我有一个类似的问题。与您不同,我的@ViewChild返回了一个有效的ElementRef,但是当我尝试访问其nativeElement时,它是undefined

我通过将视图id设置为#content,而不是#content ="ngModel"来解决此问题。

1
2
3
4
5
6
<textarea type ="text"
    id ="content"
    name ="content"
    #content
    [(ngModel)] ="article.content"
    required></textarea>