【发布时间】:2017-11-16 10:20:13
【问题描述】:
在以下情况下,我无法正确初始化 @ViewChild 注释字段:
@ViewChild 带注释的字段在某些情况下会保留undefined:
-
X类型的父组件实现了XBase类型的抽象基类,它具有三个抽象字段 -
X类型的组件用@ChildView类型A、B和C注释这些字段 -
C反过来也扩展了XBase,但使用与X不同的模板和选择器 -
A和B类型的字段在X类型的组件中初始化 -
C类型的字段未定义
这是我的代码的缩短版
@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 和 UserGridBodyComponent 等效于 Drive-Components。
这里是html模板的相关部分:
drive-view.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
<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
<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>
所以我要做的是在DriveViewComponent 中以DriveMembersModalComponent 的形式重用GridView<T>。当用户想要查看驱动器的成员时,它应该在弹出的引导模式中呈现类似的网格。
但是DriveViewComponent 的driveMembersModal 没有完全初始化。它的
@ViewChild(UserGridComponent)
public grid: UserGridComponent;
保持未定义。似乎 Angular 在模板中找不到匹配的元素。我试过不同的选择器没有效果。我还尝试了@ViewChild(<reference>) 语法,其中将#reference 属性添加到元素中。然而,这给了我一个ElementRef,我不知道如何处理。它似乎只是一个 DOM 引用,而不是一个角度组件。
编辑:
我从我的应用中创建了一个 plunker 示例:https://embed.plnkr.co/083a5AnkaiCG796adTkR/
按照这些说明重现错误:
- 打开浏览器的调试模式以查看控制台输出
- 点击“驱动器”标签
- 控制台将打印
DriveMembersModalComponent,它对应于上面提到的组件C。grid字段为undefined。打印在DriveViewComponent的ngAfterViewInit()中执行
【问题讨论】:
标签: angular angular-components viewchild