如何在不重复写入某些组件的情况下导入指令

时间:2016-05-03 08:19:14

标签: typescript angular

我正在使用带有TypeScript的Angular2创建Web应用程序。当我创建一些CustomElements(它的意思是组件和指令,验证器)时,我发现我为每个组件编写了directives: [...]代码,以便导入CustomElements,如下面的代码。

// my_comopnent_1.comopnent.ts
@Component({
  selector: 'my-component-1',
  directives: [
    ROUTER_DIRECTIVES,
    MyDirective1,
    MyDirective2,
    MyValidator1,
    MyValidator2,
    ...
  ],
})

// my_comopnent_2.comopnent.ts
@Component({
  selector: 'my-component-2',
  directives: [
    ROUTER_DIRECTIVES,
    MyDirective1,
    MyDirective2,
    MyValidator1,
    MyValidator2,
    ...
  ],
})

// my_comopnent_3.comopnent.ts
@Component({
  selector: 'my-component-3',
  directives: [
    ROUTER_DIRECTIVES,
    MyDirective1,
    MyDirective2,
    MyValidator1,
    MyValidator2,
    ...
  ],
})

是否存在如何导入一些CustomComopnents而不重复编写directives: [...],如事件冒泡或原型链? 我的理想是,当我将代码编写到父组件时,其子组件将它们包含在父组件的导入的CustomElements中。

// parent.component.ts
@Component({
  selector: 'parent',
  directives: [MyDirective1, ...],
})

// child.component.ts
@Component({
  selector: 'child',
  template: `
    // It's possible to use MyDirective because of importing by ParentComponent.
    <div my-directive></div>
  `,
})

2 个答案:

答案 0 :(得分:0)

您可以通过这种方式将它们定义为平台指令:

export const GENERAL_DIRECTIVES: any[] = [
  ROUTER_DIRECTIVES,
  MyDirective1,
  MyDirective2,
  MyValidator1,
  MyValidator2,
  (...)
];

bootstrap(App, [
  provide(PLATFORM_DIRECTIVES, {useValue: [GENERAL_DIRECTIVES], multi: true})
]);

这样您每次都不需要导入它们。

有关详细信息,请参阅此问题:

这种方法的主要缺点是它们对应用程序中的所有组件都是全局的。另一种方法包括创建一个自定义装饰器,扩展组件元数据(directives属性)以添加这些组件/指令。通过这种方式,您可以精确控制自动指定这些指令的位置。

这种机制可以依赖继承,即abtract root组件。

以下是一个示例:

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])) {
        if (key === 'directives') {
          // merge directives attributes
          let parentDirectives = parentAnnotation[key] || [];
          let currentDirectives = annotation[key] || [];
          currentDirectives.concat(parentDirectives);
        } else {
          annotation[key] = parentAnnotation[key];
        }
      }
    });
    var metadata = new ComponentMetadata(annotation);

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

并使用它:

@Component({
  directives: [
    ROUTER_DIRECTIVES,
    MyDirective1,
    MyDirective2,
    MyValidator1,
    MyValidator2,
    (...)
  ]
})
export class AbstractComponent {
}

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

@Component({
  selector: 'app',
  template: `
    <sub></sub>
  `,
  directives [ SubComponent ]
})
export class App {
}

有关详细信息,请参阅此问题:

答案 1 :(得分:0)

您可以全局提供指令和代码,例如

bootstrap(AppComponent, [
    provide(PLATFORM_DIRECTIVES, 
        {useValue: [
            ROUTER_DIRECTIVES, 
            MyDirective1, 
            MyDirective2, 
            MyValidator1, 
            MyValidator2
         ], multi: true}),

    provide(PLATFORM_PIPES, 
         {useValue: [RainbowizePipe], multi:true})

]);

您传递的指令和管道数组由Angulars DI自动展平,这允许传递任意嵌套数组。 例如,将模块的指令打包到数组中,然后最终将包含所有模块的数组的数组传递给provide()