[英]Angular 4 - nested @ViewChild is undefined
I'm having trouble to get a @ViewChild
annotated field properly initialized under following circumstance:在以下情况下,我无法正确初始化
@ViewChild
注释的字段:
A @ViewChild
annotated field stays undefined
under certain circumstances:在某些情况下,
@ViewChild
注释字段保持undefined
:
X
implements abstract base class of type XBase
, which has three abstract fields X
类型的父组件实现了XBase
类型的抽象基类,它具有三个抽象字段X
annotates these field with @ChildView
of types A
, B
and C
X
类型的组件使用A
、 B
和C
类型A
@ChildView
注释这些字段C
in turn also extends XBase
, but uses a different template and selector than X
C
反过来也扩展了XBase
,但使用了与X
不同的模板和选择器A
and B
get propery initialized in component of type X
A
和B
字段在类型X
组件中初始化C
stays undefined C
类型的字段保持未定义This is the shortened version of my code这是我的代码的缩短版本
@Component({
moduleId: module.id,
selector: 'drive-view'
templateUrl: './../../html/drive-view.html'
})
export class DriveViewComponent extends GridView<Drive>
{
@ViewChild(DriveGridComponent)
public grid: DriveGridComponent;
@ViewChild(DriveDetailsComponent)
public itemDetails: DriveDetailsComponent;
@ViewChild(DriveFilterModalComponent)
public filterModal: DriveFilterModalComponent;
@ViewChild(DriveMembersModalComponent)
public driveMembersModal: DriveMembersModalComponent;
}
export abstract class GridView<TEntity>
{
public abstract grid: Grid<TEntity>;
public abstract filterModal: IGridFilterModal;
public abstract itemDetails: IGridItemDetails<TEntity>;
}
export abstract class Grid<TEntity>
{
public abstract header: IGridHeader;
public abstract body: IGridBody<TEntity>;
}
@Component({
moduleId: module.id,
selector: '[drive-grid]',
templateUrl: './../../html/grid.html'
})
export class DriveGridComponent extends Grid<Drive>
{
@ViewChild(DriveGridHeaderComponent)
public header: DriveGridHeaderComponent;
@ViewChild(DriveGridBodyComponent)
public body: DriveGridBodyComponent;
}
@Component({
moduleId: module.id,
selector: 'thead [grid-header]',
templateUrl: './../../html/drive-grid-header.html'
})
export class DriveGridHeaderComponent implements IGridHeader
{
// nothing to see here...
}
@Component({
moduleId: module.id,
selector: 'tbody [grid-body]',
templateUrl: './../../html/drive-grid-body.html'
})
export class DriveGridBodyComponent implements IGridBody<Drive>
{
// nothing to see here...
}
@Component({
moduleId: module.id,
selector: '[drive-members-modal]',
templateUrl: './../../html/drive-members-modal.html'
})
export class DriveMembersModalComponent extends GridView<User>
{
@ViewChild(UserGridComponent)
public grid: UserGridComponent;
}
@Component({
moduleId: module.id,
selector: '[user-grid]',
templateUrl: './../../html/grid.html'
})
export class UserGridComponent extends Grid<User>
{
@ViewChild(UserGridHeaderComponent)
public header: UserGridHeaderComponent;
@ViewChild(UserGridBodyComponent)
public body: UserGridBodyComponent;
}
UserGridHeaderComponent
and UserGridBodyComponent
are equivalent to the Drive-
Components. UserGridHeaderComponent
和UserGridBodyComponent
等同于Drive-
组件。
And here are the relevant parts of html templates:以下是 html 模板的相关部分:
drive-view.html驱动器视图.html
<div class="row">
<div class="col-lg-12"
drive-filter-modal
(onFilterApplyButtonEmitter)="onFilterApplyButton()">
</div>
</div>
<div class="row">
<div class="col-lg-12"
drive-members-modal>
</div>
</div>
<div class="row" [hidden]="!grid.body?.items">
<div class="col-lg-12"
drive-grid
(onColumnHeaderToggledEmitter)="onColumnHeaderToggled($event)"
(onDetailsButtonEmitter)="onDetailsButton($event)">
</div>
</div>
<div class="row"
id="row-grid-item-details">
<div class="col-lg-12"
[@detailsSlideUpDown]="itemDetails.fadeInOutStatus">
<item-details (onOpenModalEmitter)="onDriveMembersButton()"></item-details>
</div>
</div>
grid.html网格.html
<div class="table-responsive">
<table class="grid table table-hover">
<thead grid-header (onColumnHeaderToggledEmitter)="onColumnHeaderToggled($event)"></thead>
<tbody grid-body (onDetailsButtonEmitter)="onDetailsButton($event)"
[ngClass]="{'fadeIn': body?.items, 'fadeOut': !body?.items}"
class="animated"></tbody>
</table>
</div>
drive-members-modal.html驱动成员-modal.html
<div class="modal fade" id="drive-members-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Members of 'NAME'</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-12"
user-grid
(onColumnHeaderToggledEmitter)="onColumnHeaderToggled($event)"
(onDetailsButtonEmitter)="onDetailsButton($event)">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
<span class="glyphicon glyphicon-chevron-left"></span> Back
</button>
</div>
</div>
</div>
</div>
</div>
So what I'm trying to do is to reuse the GridView<T>
in shape of the DriveMembersModalComponent
within the DriveViewComponent
.所以我想要做的是在
DriveViewComponent
中以DriveMembersModalComponent
形状重用GridView<T>
。 It is supposed to render a similar grid within the bootstrap modal that pops up, when the user wants to view the members of a drive.当用户想要查看驱动器的成员时,它应该在弹出的引导模式中呈现类似的网格。
However DriveViewComponent
's driveMembersModal
does not get fully initialized.但是
DriveViewComponent
的driveMembersModal
没有完全初始化。 Its它的
@ViewChild(UserGridComponent)
public grid: UserGridComponent;
stays undefined.保持未定义。 It seems like angular can't find a matching element in the template.
似乎 angular 在模板中找不到匹配的元素。 I've tried with different selectors with no effect.
我试过不同的选择器,但没有效果。 I've also tried the
@ViewChild(<reference>)
syntax, where a #reference
attribute is added to the element.我还尝试了
@ViewChild(<reference>)
语法,其中将#reference
属性添加到元素中。 However this gives me a ElementRef
, which I don't know how to handle.但是,这给了我一个
ElementRef
,我不知道如何处理。 It appears to be just a DOM-reference, but not an angular component.它似乎只是一个 DOM 引用,而不是一个角度组件。
EDIT:编辑:
I've created a plunker example from my app: https://embed.plnkr.co/083a5AnkaiCG796adTkR/我从我的应用程序中创建了一个 plunker 示例: https ://embed.plnkr.co/083a5AnkaiCG796adTkR/
Follow these instructions to reproduce the error:请按照以下说明重现错误:
DriveMembersModalComponent
, it corresponds to component C
mentioned above.DriveMembersModalComponent
,它对应于上面提到的组件C
The grid
field is undefined
. grid
字段undefined
。 The print is executed in the DriveViewComponent
's ngAfterViewInit()
DriveViewComponent
的ngAfterViewInit()
After breaking down the above example to a minimal piece of code, I figured out the reason for the @ViewChild
staying undefined:在将上面的示例分解为最少的代码后,我找出了
@ViewChild
保持未定义的原因:
Angular did not throw any error though I was missing an export statement for the module I imported.尽管我缺少导入的模块的导出语句,但 Angular 没有抛出任何错误。 This happens when you don't use an explicit html tag for your template.
当您不为模板使用显式 html 标记时,就会发生这种情况。
You can observe this behavior following short plunker:您可以在简短的 plunker 之后观察这种行为:
https://plnkr.co/edit/kPKSbPS86iJ1oVCA4WSj?p=preview https://plnkr.co/edit/kPKSbPS86iJ1oVCA4WSj?p=preview
If you uncomment line 26 in src/module.ts
, App
's @ViewChild
will be properly rendered.如果您取消注释
src/module.ts
的第 26 行, App
的@ViewChild
将正确呈现。 An error is only raised if you change the template's <div>
tag to <component-a>
.仅当您将模板的
<div>
标记更改为<component-a>
才会引发错误。 Then Angular will complain about the unknown element and ask you to check, whether it is an Angular component.然后 Angular 会抱怨未知元素并要求你检查它是否是一个 Angular 组件。
I had a similar error, but It was just because I'm a noob.我有一个类似的错误,但这只是因为我是一个菜鸟。 Turns out if you try to access a
ViewChild
in the constructor for a component, it doesn't exist yet, and is undefined...事实证明,如果您尝试在组件的构造函数中访问
ViewChild
,它尚不存在,并且未定义...
I moved the code that accessed my ViewChild
's to ngAfterViewInit
and it worked like a charm.我将访问我的
ViewChild
的代码移动到ngAfterViewInit
,它就像一个魅力。
PS Anything with an Ion Directive like ngIf/ngFor also seem to dislike being bound, which I guess makes sense since their existence is kind of dependant anyway. PS 任何像 ngIf/ngFor 这样的离子指令似乎也不喜欢被绑定,我想这是有道理的,因为它们的存在无论如何都是依赖的。
在核心导入中添加 ViewChild
import { Component, OnInit,ViewChild } from '@angular/core';
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.