簡體   English   中英

Angular 4 - 嵌套的 @ViewChild 未定義

[英]Angular 4 - nested @ViewChild is undefined

在以下情況下,我無法正確初始化@ViewChild注釋的字段:

在某些情況下, @ViewChild注釋字段保持undefined

  • X類型的父組件實現了XBase類型的抽象基類,它具有三個抽象字段
  • X類型的組件使用ABC類型A @ChildView注釋這些字段
  • C反過來也擴展了XBase ,但使用了與X不同的模板和選擇器
  • 類型AB字段在類型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;
}

UserGridHeaderComponentUserGridBodyComponent等同於Drive-組件。

以下是 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>

網格.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>

驅動成員-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">&times;</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> 當用戶想要查看驅動器的成員時,它應該在彈出的引導模式中呈現類似的網格。

但是DriveViewComponentdriveMembersModal沒有完全初始化。 它的

@ViewChild(UserGridComponent)
public grid: UserGridComponent;

保持未定義。 似乎 angular 在模板中找不到匹配的元素。 我試過不同的選擇器,但沒有效果。 我還嘗試了@ViewChild(<reference>)語法,其中將#reference屬性添加到元素中。 但是,這給了我一個ElementRef ,我不知道如何處理。 它似乎只是一個 DOM 引用,而不是一個角度組件。

編輯:

我從我的應用程序中創建了一個 plunker 示例: https ://embed.plnkr.co/083a5AnkaiCG796adTkR/

請按照以下說明重現錯誤:

  • 打開瀏覽器的調試模式以查看控制台輸出
  • 單擊“驅動器”選項卡
  • 控制台將打印DriveMembersModalComponent ,它對應於上面提到的組件C grid字段undefined 打印在DriveViewComponentngAfterViewInit()

在將上面的示例分解為最少的代碼后,我找出了@ViewChild保持未定義的原因:

盡管我缺少導入的模塊的導出語句,但 Angular 沒有拋出任何錯誤。 當您不為模板使用顯式 html 標記時,就會發生這種情況。

您可以在簡短的 plunker 之后觀察這種行為:

https://plnkr.co/edit/kPKSbPS86iJ1oVCA4WSj?p=preview

如果您取消注釋src/module.ts的第 26 行, App@ViewChild將正確呈現。 僅當您將模板的<div>標記更改為<component-a>才會引發錯誤。 然后 Angular 會抱怨未知元素並要求你檢查它是否是一個 Angular 組件。

我有一個類似的錯誤,但這只是因為我是一個菜鳥。 事實證明,如果您嘗試在組件的構造函數中訪問ViewChild ,它尚不存在,並且未定義...

我將訪問我的ViewChild的代碼移動到ngAfterViewInit ,它就像一個魅力。

PS 任何像 ngIf/ngFor 這樣的離子指令似乎也不喜歡被綁定,我想這是有道理的,因為它們的存在無論如何都是依賴的。

在核心導入中添加 ViewChild

import { Component, OnInit,ViewChild } from '@angular/core';

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM