用基类装饰器扩展组件装饰器 [英] Extending component decorator with base class decorator

查看:105
本文介绍了用基类装饰器扩展组件装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个在每个组件上重复的组件装饰器声明,例如:

I have several component decorator declarations that I repeat on every component, for example:

@Component({
    moduleId: module.id,
    directives: [BootstrapInputDirective]
})

如何将这些声明应用于我的所有组件?我试图用此装饰器创建一个基类,并用它扩展其他类,但是基类装饰似乎不适用于派生类.

How can I apply these declarations to all my components? I tried to create a base class with this decorator and extend other classes with it but base class decorations doesn't seem to apply to derivative classes.

推荐答案

@Component是修饰符.这意味着它通过利用反射元数据库添加一些元数据来处理它所应用的类. Angular2不在父类上查找元数据.因此,无法在父类上使用装饰器.

@Component is a decorator. This means that it handles the class it applies on by adding some metadata data leveraging the reflect-metadata library. Angular2 doesn't look for metadata on parent classes. For this reason, it's not possible to use decorators on parent classes.

关于BootstrapInputDirective指令,可以将其定义为平台指令.这样,您无需每次都将其包含在组件的directives属性中.

Regarding the BootstrapInputDirective directive, you could define it as a platform one. This way you wouldn't need to include it each time into the directives attribute of your components.

以下是示例:

(...)
import {PLATFORM_DIRECTIVES} from 'angular2/core';

bootstrap(AppComponent, [
  provide(PLATFORM_DIRECTIVES, {useValue: [BootstrapInputDirective], multi:true})
]);

修改

是的,您可以创建自己的装饰器以实现此目的.这是一个示例:

Yes, you could create your own decorator to implement this. Here is a sample:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = annotation.parent;
    delete annotation.parent;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        annotation[key] = parentAnnotation[key];
      }
    });
    var metadata = new ComponentMetadata(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

CustomComponent装饰器将以这种方式使用:

The CustomComponent decorator will be used this way:

@Component({
  template: `
    <div>Test</div>
  `
})
export class AbstractComponent {
}

@CustomComponent({
  selector: 'sub',
  parent: AbstractComponent
})
export class SubComponent extends AbstractComponent {
}

请注意,我们需要提供父类作为装饰器的输入,因为我们可以在装饰器中找到该父类.通过反射元数据,只有此类的原型,但元数据才应用于该类,而不应用于相关的原型.

Note that we need to provide the parent class as input of the decorator since we can find out this parent class within the decorator. Only the prototype of this class but the metadata are applied on the class and not on the associated prototype by reflect-metadata.

Edit2

感谢尼察姆的回答,这是一个即兴表演:

Thanks to Nitzam's answer, here is an improvment:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        annotation[key] = parentAnnotation[key];
      }
    });
    var metadata = new ComponentMetadata(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

不需要parent属性来引用自定义装饰器中的父类.

There is no need for a parent attribute to reference the parent class in the custom decorator.

请参阅以下示例: https://plnkr.co/edit/ks1iK41sIBFlYDb4aTHG?p=preview .

看到这个问题:

这篇关于用基类装饰器扩展组件装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆