简体   繁体   中英

Angular 2, mystery with dependency injection

I consider myself an ng2 expert (heavy into my 2nd application) and yet every once in a while I would run into a gotcha... and here is one

I have a simple table component called simpleGridTable:

<simpleGridTable #userSimpleGridTable>
<thead>
<tr>
  <th sortableHeader="name" [sort]="sort">name</th>
  <th sortableHeader="businessId" [sort]="sort">business</th>
  <th>access keys [0-7]</th>
  <th>privileges (id)</th>
  <th>privileges (name)</th>
</tr>
</thead>
<tbody>
<tr class="simpleGridRecord" [table]="userSimpleGridTable" simpleGridRecord *ngFor="#item of m_businesses | OrderBy:sort.field:sort.desc; #index=index" [item]="item" [index]="index">
  <td style="width: 20%" simpleGridData (labelEdited)="onLabelEdited($event,'name')" editable="true" field="name" [item]="item"></td>
  <td style="width: 8%" simpleGridData field="businessId" [item]="item"></td>
  <td style="width: 20%" simpleGridDataChecks (changed)="setAccessMask($event)" [item]="item" [checkboxes]="getAccessMask(item)"></td>
  <td style="width: 12%" simpleGridData field="privilegeId" [item]="item"></td>
  <td style="width: 40%" simpleGridDataDropdown [testSelection]="selectedPriveleges()" (changed)="setPriveleges($event)" field="name" [item]="item" [dropdown]="m_priveleges"></td>
  <!-- <td simpleGridDataImage color="dodgerblue" [field]="item.getKey('studioLite') == '0' ? 'fa-circle' : 'fa-circle-o'" [item]="item"></td> -->
</tr>
</tbody>

inside of it I have a simpleGridRecord which you can see its directive above in:

<tr class="simpleGridRecord" [table]="userSimpleGridTable" simpleGridRecord *ngFor="#item of m_businesses | OrderBy:sort.field:sort.desc; #index=index" [item]="item" [index]="index">

the component of simpleGridRecord is as follows (and tried to dependency inject the parent SimpleGridTable:

import {Component, Injectable, Input, Output, ChangeDetectionStrategy, HostListener, HostBinding, EventEmitter} from 'angular2/core'

import {SimpleGridTable} from "./SimpleGridTable";

   @Component({
      selector: 'tr[simpleGridRecord]',
      changeDetection: ChangeDetectionStrategy.OnPush,
      template: `
          <ng-content></ng-content>
    `
})
export class SimpleGridRecord {

    constructor(tb:SimpleGridTable){
        console.log(tb);
    }
    ....

and my SimpleGridTable component:

@Component({
selector: 'simpleGridTable',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [SimpleGridTable],
pipes: [OrderBy],
directives: [COMMON_DIRECTIVES, SimpleGridSortableHeader, SimpleGridRecord, SimpleGridData],
styleUrls: [`../comps/simplegrid/SimpleGrid.css`],
template: `
    <table class="table simpleTable">
        <ng-content></ng-content>
    </table>      
`....
})
export class SimpleGridTable {
...

and yet the simpleGridRecord cannot seem to be able to inject its parent table as I get an error of:

在此处输入图片说明

I don't use @Inject as I am using TypeScript... I do [provide] the table to its decedents

the entire class can be seen here: https://github.com/born2net/studioDashboard/tree/master/src/comps/simplegrid

tx for reading

Sean

Whenever you're injecting a parent into a child, especially if the parent and child are defined in different files, you'll very likely need to wrap any reference to the parent class in the child class in a forwardRef , like so:

constructor(@Inject(forwardRef(() => SimpleGridTable) tb: SimpleGridTable ){
    console.log(tb);
}

This is a workaround for the fact that it is impossible for the parent class to be loaded at the time the child class (which has to be loaded first) is loaded.

Also,

I don't use @Inject as I am using TypeScript... I do [provide] the table to its decedents

Note that there are circumstances where @Inject is necessary in Typescript apps - this being one of them.

It also bears mentioning that I've never seen a component type included in providers as you've done here, and I would encourage you to verify that this is doing what you think it's doing. In any case, FWIW, what you're doing with it isn't very clear to me as a reader of your code, and IMHO using @Inject with constructor injection is a cleaner and more idiomatic approach to injecting parent components into their children.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM