2016-11-10 12 views
1

我想創建一個通用指令,它將採用類類型進行規則驗證,並根據類中的規則指令將顯示或隱藏元素。在指令中手動獲取從注入器的依賴關係

這是我迄今的嘗試。

PLUNKER演示

myIf-Directive.ts

@Directive({ 
    selector: '[myIf]' 
}) 
export class MyIfDirective { 
    constructor(private _viewContainer: ViewContainerRef, 
    private _template: TemplateRef<Object>) 
    { } 

    @Input() set myIf(rule: string) { 
    //rule class type will come as string 
    //how can I use string token to get dependency from injector? 
    //currently harcoded 
    //will the injector create new instance or pass on instance from parent? 
    let injector = ReflectiveInjector.resolveAndCreate([AdminOnly]); 
    let adminOnly : IRule = injector.get(AdminOnly); 
    let show = adminOnly.shouldShowElement(); 
    show ? this.showItem() : this.hideItem(); 
    } 
    private showItem() { 
    this._viewContainer.createEmbeddedView(this._template); 
    } 

    private hideItem() { 
    this._viewContainer.clear(); 
    } 
} 


APP-component.ts

@Component({ 
    selector: 'my-app', 
    template: ` 
    <div *myIf="'AdminOnly'"> 
     <h2>Hello {{name}}</h2> 
    </div> 
    `, 
}) 
export class App { 
    name:string; 
    constructor() { 
    this.name = 'Angular2' 
    } 
} 

但我被困在兩個地方:

  1. 我不斷收到錯誤No Provider for AuthService
  2. 我不知道我怎麼可以從注射器使用類名作爲字符串,而不是類型

任何建議,這是否是正確的方式來獲得的依賴做到這一點,或者我錯誤的地方是高度讚賞。

+0

*我不知道我怎麼可以從注射器使用類名作爲字符串,而不是類型得到的依賴*您可以「T。見http://stackoverflow.com/a/40063568/3731501 – estus

+0

@estus所以,無論如何,我可以將'AdminOnly'類型傳遞給'my-if'指令而不是字符串? – lbrahim

+0

我不確定這個指令應該如何工作。但是你必須傳遞組件構造函數,而不是一個字符串。如果你想把它作爲一個字符串傳遞,應該像上面顯示的那樣使用組件和它們的字符串表示的映射。 – estus

回答

2

您需要通過父注射器狀

export class MyIfDirective { 
    constructor(private injector:Injector, private _viewContainer: ViewContainerRef, 
    private _template: TemplateRef<Object>) 
    { } 

    @Input() set myIf(rule: string) { 
    let resolvedProviders = ReflectiveInjector.resolve([AdminOnly]); 
    let childInjector = ReflectiveInjector.fromResolvedProviders(resolvedProviders, this.injector); 

    let adminOnly : IRule = childInjector.get(AdminOnly); 
    let show = adminOnly.shouldShowElement(); 
    show ? this.showItem() : this.hideItem(); 
    } 
    private showItem() { 
    this._viewContainer.createEmbeddedView(this._template); 
    } 

    private hideItem() { 
    this._viewContainer.clear(); 
    } 
} 

參見Inject service with ReflectiveInjector without specifying all classes in the dependency tree

+0

這解決了我的第一個問題。謝謝。你能否爲第二個問題提出一些建議? – lbrahim

+2

你需要通過像'{provide:'someName',useClass:SomeClass}''這樣的字符串來註冊它,然後你可以像'injector.get('someName')'這樣的名字來獲得它。或者,你可以維護一個類型爲'let type = {'someName':SomeClass','foo':Foo,'bar':Bar}'的地圖,然後你可以像'injector.get(this.types [ 'someName'])' –

+0

我喜歡第一種方式。但在這種情況下,這不會工作'讓resolveProviders = ReflectiveInjector.resolve(['AdminOnly']);' – lbrahim