【问题标题】:Angular 2: How Should We Be Handling Dependency Injection with ES6/ES7?Angular 2:我们应该如何使用 ES6/ES7 处理依赖注入?
【发布时间】:2016-01-29 16:12:52
【问题描述】:

由于工作限制,我一直在 Angular 2 中开发一个自定义组件,因为我试图在使用 ES6/ES7 的同时学习绳索并进行切换。假设我有一个这样定义的组件:

// Import Inject, Component and View constructor (for metadata)
import {Inject, Injectable} from 'angular2/core';
import {Component, View} from 'angular2/core';
// Import NgClass directive
import {NgClass} from 'angular2/common';

import { InjectMetadata } from 'angular2/core';

// # Accordion Component

@Component({
  selector: 'accordion, [accordion]',

  // Modify the `host` element with a css class designator
  host: {
    'class': 'panel-group'
  }
})

// Define the view of our `Component` using one or more
// `View` annotations
@View({

  // Link to our external template file
  templateUrl: './components/accordion/accordion.html'
})

// Create and export `Component` class
export class Accordion {

  constructor() {

    this.groups = [];
  }

  // Function to register groups
  addGroup(group) {
    this.groups.push(group);
  }

  closeOthers(openGroup) {
    this.groups.forEach((group) => {
      if(group !== openGroup) {
        group.isOpen = false;
      }
    });
  }

  removeGroup(group) {
    let index = this.groups.indexOf(group);

    if(index !== -1) {
      this.groups.splice(index, 1);
    }
  }
}

我需要将其传递给另一个名为 AccordionGroup 的组件,但是当我按照此 Stack Overflow Thread 中的答案并尝试像使用构造函数一样进行注入时:

// # AccordionGroup Component

// Annotate AccordionGroup class with `Component`
@Component({
  selector: 'accordion-group, [accordion-group]',
  inputs: ['heading', 'isOpen'],

  // Let Angular know about `Accordion`
  providers: [Accordion]
})

// Define the view of our `Component` using one or more
// `View` annotations
@View({

  // Link to our external template file
  templateUrl: './components/accordion/accordion-group.html',

  // Specify which directives our `Component` will utilize with
  // the `directive` property of the `View` annotation
  directives: [NgClass]
})

// Create and export `Component` class
export class AccordionGroup {

  constructor(accordion) {

    this.isOpen = false;

    this.accordion = accordion;

    this.accordion.addGroup(this);
  }

  // Angular 2 DI desugar'd
  // Reference: https://stackoverflow.com/questions/33026015/how-to-inject-angular2-http-service-into-es6-7-class
  static get parameters() {
    return [[Accordion]];
  }

  toggleOpen(event) {
    event.preventDefault();
    this.isOpen = !this.isOpen;
    this.accordion.closeOthers(this);
  }

  onDestroy() {
    this.accordion.removeGroup(this);
  }
}

使用

static get parameters() {
  return [[Accordion]];
}

在进行第一条评论中注明的更正后呈现我的组件。

使用以下任何一种渲染组件:

AccordionGroup.parameters = [[Accordion]];

AccordionGroup.parameters = [new Inject(Accordion)];

甚至

// Use reflect metadata as an attempt to inject appropriate
// dependency
@Reflect.metadata('parameters', [[new InjectMetadata(Accordion)]])

但问题仍然存在,在我们可以在 ES7 中使用参数装饰器之前,使用哪种方法是合适的。

顺便说一句,很多代码都来自这个特定的教程,它使用 TypeScript 演示了所有 Angular 2 的东西,所以我只是简单地将它调整到使用 Webpack 的 es6/es7 环境 | Migrating Directives to Angular 2

【问题讨论】:

  • 您的 Accordion 类是一个组件,您应该通过directives 传递它,而不是通过providers。然后使用@ViewChildren 查询它
  • 啊,谢谢你。令人惊讶的是,即使经过几天的修补,你也会错过诸如此类的小事。但是,我的组件功能仍然不起作用。

标签: angular angular2-di


【解决方案1】:

您需要在构造函数参数上添加@Inject() 装饰器。 由于 ES7 规范不支持这一点(当前规范 AFAIK 中只允许使用类、属性和方法装饰器),因此您需要为您的转译器提供某种插件。

如果您使用 Babel 进行转译,您可以使用 babel-plugin-angular2-annotations 插件来允许并正确转译代码。

import {Inject} from 'angular2/core';

export class AccordionGroup {
  constructor(@Inject(Accordion) accordion) {
    // ...
  }
}

【讨论】:

  • 嗯...集成这个插件给了我dom_element_schema_registry.ts抛出的错误Uncaught Error: Cannot find module "../components/accordion/accordion.component.js"。我相信我正在为 ES6/ES7 环境正确注入,我只是不能使用 @Inject 装饰器,而是必须使用 desugar'd 版本。现在的问题是为什么组件本身不工作。
  • 至于组件本身为什么不能运行的问题,我做了这个SO:stackoverflow.com/questions/35076907/…
【解决方案2】:

除了 Eric 在评论中所说的之外,也许你错过了 AccordionGroup 构造函数中的 @Inject 装饰器

import {Inject} from 'angular2/core';

export class AccordionGroup {
  constructor(@Inject(Accordion) accordion) {
    (...)
  }
}

希望对你有帮助 蒂埃里

【讨论】:

  • @Inject 仅适用于TypeScript,据我所知,ES7 没有这种类型的注射器的规格。至少现在还没有。
  • @Inject 是Angular2核心提供的装饰器,不是吗?同样的方式@Component 是......我猜......你试过了吗?
  • 在 TypeScript 中,装饰器只对应一个被调用来装饰目标的函数(添加元数据,...)...
  • 是的,我开始尝试使用@Injector。但是,此功能仅适用于 TypeScript,因为它甚至还没有在 ES7 中指定。 constructor(@Inject(Http) http) {} 之类的东西在 TypeScript 之外不起作用。 ES6/ES7 拥有的是类和属性装饰器,这就是为什么我可以转译代码中存在的装饰器。
  • 一种解决方法是显式使用Injector 类。你可以看看这个页面:angular.io/docs/ts/latest/api/core/InjectMetadata-class.html.
猜你喜欢
  • 2016-12-15
  • 2016-02-15
  • 1970-01-01
  • 2018-04-07
  • 2017-11-13
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
相关资源
最近更新 更多