如何在Angular2指令上访问Component?

jps*_*sfs 15 typescript angular

我正在使用Angular 2进行一些测试,我有一个可以应用于我所有组件的指令(layout-item).

在该指令中,我希望能够读取组件上定义的一些元数据,但为此我需要访问组件的引用.

我尝试了以下方法,但我无法得到我需要的东西.有人有建议吗?

@Component({...})
@View({...})
@MyAnnotation({...})
export class MyComponentA {...}


// Somewhere in a template
<myComponentA layout-item="my config 1"></myComponentA>
<myComponentB layout-item="my config 2"></myComponentA>

// ----------------------

@ng.Directive({
    selector: "[layout-item]",
    properties: [
        "strOptions: layout-item"
    ],
    host: {

    }
})

export class LayoutItem {

    // What works
    constructor(@Optional() @Ancestor({self: true}) private component: MyComponent1) {

 // with the constructor defined like this, component is defined with myComponent1 instance.
Reflector.getMetadata("MyAnnotation", component.constructor); // > metadata is here!
    }

// What I needed
    constructor(@Optional() @Ancestor({self: true}) private component: any) {

 // This will crash the app. If instead of any I specify some other type, the app will not crash but component will be null.
 // This directive can be applied to any component, so specifying a type is not a solution. 
    }
}
Run Code Online (Sandbox Code Playgroud)

jps*_*sfs 9

更新:

自Beta 16以来,没有官方的方法来获得相同的行为.这里有一个非官方的解决方法:https://github.com/angular/angular/issues/8277#issuecomment-216206046


谢谢@Eric Martinez,你的指针对于让我走向正确的方向至关重要!

所以,采取Eric的方法,我设法做了以下事情:

HTML

<my-component layout-item="my first component config"></my-component>

<my-second-component layout-item="my second component config"></my-second-component>

<my-third-component layout-item="my third component config"></my-third-component>
Run Code Online (Sandbox Code Playgroud)

三个不同的组件,所有的共享相同 layout-item属性.

指示

@Directive({
  selector : '[layout-item]'
})
export class MyDirective {
  constructor(private _element: ElementRef, private _viewManager: AppViewManager) {
    let hostComponent = this._viewManager.getComponent(this._element);
    // on hostComponent we have our component! (my-component, my-second-component, my-third-component, ... and so on!
  }

}
Run Code Online (Sandbox Code Playgroud)


Eri*_*nez 5

忘记服务,有一个更简单的形式

选项1 (不是您需要的,但对其他用户可能有用)

HTML

<my-component layout-item="my first component config"></my-component>

<my-second-component layout-item="my second component config"></my-second-component>

<my-third-component layout-item="my third component config"></my-third-component>
Run Code Online (Sandbox Code Playgroud)

三个不同的组件,所有共享相同的layout-item属性.

指示

@Directive({
  selector : '[layout-item]',
  properties: ['myParentConfig: my-parent-config'] // See the components for this property
})
export class MyDirective {
  constructor() {

  }

  onInit() {
    console.log(this.myParentConfig);
  }
}
Run Code Online (Sandbox Code Playgroud)

很简单,这里解释不多

零件

@Component({
  selector : 'my-component',
  properties : ['myConfig: layout-item']
})
@View({
  template : `<div [my-parent-config]="myConfig" layout-item="my config"></div>`,
  directives : [MyDirective]
})
export class MyComponent {
  constructor() {
  }
}
Run Code Online (Sandbox Code Playgroud)

我很确定你理解这一点,但为了得到一个好的答案,我会解释它的作用

properties : ['myConfig: layout-item']`
Run Code Online (Sandbox Code Playgroud)

此行将layout-item属性分配给内部myConfig属性.

组件的模板

template : `<div [my-parent-config]="myConfig" layout-item="my config"></div>`,
Run Code Online (Sandbox Code Playgroud)

我们正在my-parent-config为指令创建一个属性,并将父级的配置分配给它.

就如此容易!所以现在我们可以使用(几乎)相同的代码添加更多组件

第二部分

@Component({
  selector : 'my-second-component',
  properties : ['myConfig: layout-item']
})
@View({
  template : `<div [my-parent-config]="myConfig" layout-item="my config"></div>`,
  directives : [MyDirective]
})
export class MySecondComponent {
  constructor() {
  }
}  
Run Code Online (Sandbox Code Playgroud)

看到?比我使用服务的想法容易得多(糟糕但"有效"的想法).

通过这种方式,它更简单,更清洁.这是plnkr所以你可以测试它.

(这不是你需要的:'()

UPDATE

选项2

因为我对你更新的问题的理解是你需要对组件的引用,所以我提出的与我原来的答案非常相似

我做了什么 :

  • 首先,我让组件对自己进行了引用
<my-cmp-a #pa [ref]="pa" layout-item="my first component config"></my-cmp-a>
<my-cmp-b #pb [ref]="pb" layout-item="my first component config"></my-cmp-b>
<my-cmp-c #pc [ref]="pc" layout-item="my first component config"></my-cmp-c>
Run Code Online (Sandbox Code Playgroud)
  • 然后我将每个引用传递给LayoutItem指令(在每个组件中注入,而不是在顶层)
@Component({
  selector : 'my-cmp-a',
  properties : ['ref: ref']
})
@View({
  template : '<div [parent-reference]="ref" layout-item=""></div>',
  directives : [LayoutItem]
})
@YourCustomAnnotation({})
export class MyCmpA {
  constructor() {

  }
}
Run Code Online (Sandbox Code Playgroud)
  • 最后在指令中你可以访问组件的构造函数(从你更新的问题我猜你需要获取它的元数据) (你必须在onInit中使用它,"引用"将不存在于构造函数中)
@Directive({
  selector : '[layout-item]',
  properties : ['reference: parent-reference']
})
export class LayoutItem {
  constructor() {
  }

  onInit() {
    console.log(this.reference.constructor);
    Reflector.getMetadata("YourCustomAnnotation", this.reference.constructor);
  }
}
Run Code Online (Sandbox Code Playgroud)

使用此plnkr进行测试.