2016-11-10 13 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