如何使用AngularDart根据类型和名称进行依赖注入?

时间:2014-01-20 21:36:41

标签: dart angular-dart

我有两个服务,每个服务都使用不同的 WebSocket作为构造函数参数。我想使用AngularDart的依赖注入传递WebSocket连接,但我不能单独依赖类型(因为我有两个WebSockets)。

如何为每个服务注释或指定哪个特定的WebSocket连接?

让我假装我:

class ServiceOne {
  WebSocket socketOne;
  ServiceOne(this.socketOne);
}

class ServiceTwo {
  WebSocket socketTwo; // different connection
  ServiceTwo(this.socketTwo);
}

谢谢!

3 个答案:

答案 0 :(得分:4)

如果你看看GUICE,这个问题就很好理解了。 (https://code.google.com/p/google-guice/)问题是当你检索一个实例时,你需要有某种Key(这就是GUICE所说的)。有几种方法可以获得Key

在AngularJS中,我们简化了问题,并说参数名称为Key。由于JS在源代码中没有类型,因此这是Key的唯一选择。

在AngualDart中,我们对其进行了改进,并使用Type作为Key。这样做的好处是参数名称无关紧要。但是它会产生一个问题,你只能注入其中一个Type。对于自定义类型,这不是什么大问题,但只有一个String配置类型成为问题。

此问题的解决方案是在类型之上添加注释。因此Annotation + TypeKey。这可能是这样的:

注意这些都不存在,它只是一个提案,它将如何解决。

class MyClass {
  MyClass(@Url String url, @Secret String secret) { ... }
}

Module module = new Module();
module.value(key(String, [Url]), 'http://server.com/...');
module.value(key(String, [Secret]), 'A89B42C');

请求由于这些都尚未实施,如果您热衷于帮助AngularDart并希望帮助实现这一目标,请与我联系。

答案 1 :(得分:3)

我还没有看到关于类型名称注入的任何信息。这是'对JS的重大改进,Dart中不再有名字了。 您可以将服务或套接字嵌入两个不同的类中以区分它们。

没有看到一些代码,提出建议有点困难。

示例

library main;

import 'dart:html';
import 'package:angular/angular.dart';
import 'package:di/di.dart';


/**
 * usage examples
 */

class ServiceOne {
  WebSocketWrapper1 socketOne;
  ServiceOne(this.socketOne);

  void doSomething() {
    socketOne.ws.xxx();
  }
}

class ServiceTwo {
  WebSocketWrapper2 socketTwo; // different connection
  ServiceTwo(this.socketTwo);

    void doSomething() {
      socketTwo.ws.xxx();
    }
  }
}    

@NgController(
    selector: '[ng-controller=alert-demo-ctrl]',
    publishAs: 'ctrl')
class AlertDemoController {
  WebSocketOnDemandWrapper1 _wsodw1;

  AlertDemoController(this._wsodw1) {
  }

  String sendData() {
    _wsodw1.ws.send("somedata");
  }
}

@NgController(
    selector: '[ng-controller=accordion-demo-ctrl]',
    publishAs: 'ctrl')
class AccordionDemoController {
  WebSocketOnDemandWrapper2 _wsodw2;

  AccordionDemoController(this._wsodw2) {
  }

  String sendData() {
    _wsodw2.ws.send("somedata");
  }
}


/**
 * injectable WebSockets
 */

class WebSocketWrapper1 {
  WebSocket ws;
  WebSocketWrapper1(this.ws);
}

class WebSocketWrapper2 {
  WebSocket ws;
  WebSocketWrapper2(this.ws);
}

class WebSocketOnDemandWrapper1 {
  WebSocket ws;
  WebSocketOnDemandWrapper1(){
    ws = new WebSocket('ws://127.0.0.1:1337/ws');
  }
}

class WebSocketOnDemandWrapper2 {
  WebSocket ws;
  WebSocketOnDemandWrapper2(){
    ws = new WebSocket('ws://127.0.0.1:3173/ws');
  }
}


class MyAppModule extends Module {
  MyAppModule() {
    type(ServiceOne);
    type(ServiceTwo);
    type(AlertDemoController);
    type(AccordionDemoController);
    type(WebSocketOnDemandWrapper1); // connect on demand
    type(WebSocketOnDemandWrapper2); // connect on demand

    // start connection on app startup and provide this connection when requested
    value(WebSocketWrapper1, new WebSocketWrapper1(new WebSocket('ws://127.0.0.1:1337/ws'))); 
    value(WebSocketWrapper2, new WebSocketWrapper2(new WebSocket('ws://127.0.0.1:3173/ws')));
  }
}

void main() {
  ngBootstrap(module: new MyAppModule());
}

答案 2 :(得分:1)

DI 0.0.34使用注释

获得了对此用例的特别支持

不支持带参数的注释。我不确定这是否仍有计划(https://github.com/angular/di.dart/issues/46

我还添加了一个示例,说明如何将原语与DI一起使用。 (不确定这是否有用)

import 'package:di/di.dart';
import 'package:di/dynamic_injector.dart';

/**
 * Annotation used to mark classes for which static type factory must be
 * generated. For testing purposes not all classes are marked with this
 * annotation, some classes are included in @Injectables at the top.
 */
class Injectable {
  const Injectable();
}

/**
 * Some dummy WebSocket class (just for demonstration)
 */
@Injectable()
class WebSocket {
  String url;
  WebSocket(this.url);
}

/**
 * Allows to mark an injectable as 'one'
 */
class One {
  const One();
}

/**
 * Allows to mark an injectable as 'two'
 */
class Two {
  const Two();
}

/**
 * A class that implements updates.
 * It needs a websocket marked as 'one'
 */
class Updates {
  WebSocket ws;
  Updates(@One() this.ws);
}


/**
 * A class that implements chats.
 * It needs a websocket marked as 'two'
 */
class Chat {
  WebSocket ws;
  Chat(@Two() this.ws);
}

/**
 * The application module
 */
class AppModule extends Module {
  AppModule() {
    value(String, 'http://www.google.com', withAnnotation: AjaxUrl);
    value(int, 8080, withAnnotation: ServerPort);
    value(int, 1000);
    factory(WebSocket, (Injector i) => new WebSocket('ws://game.example.com:12010/updates'), withAnnotation: One);
    factory(WebSocket, (Injector i) => new WebSocket('ws://chat.example.com/games'), withAnnotation: Two);
    type(Chat);
    type(Updates);
  }

  Injector _injector;
  Injector get injector {
    if (_injector == null) {
      _injector = new DynamicInjector(modules: [this]);

      // Static injector => comment in and comment out above
      //      _injector = new StaticInjector(modules: [this],
      // typeFactories: type_factories_gen.typeFactories);
    }
    return _injector;
  }
}

/**
 * Allows to mark a String as ajax url
 * Just to demonstrate how to use primitive types with DI
 */
class AjaxUrl {
  const AjaxUrl();
}

/**
 * Allows to mark an int as server port
 * Just to demonstrate how to use primitive types with DI
 */
class ServerPort {
  const ServerPort();
}


void main(List<String> args) {
  var module = new AppModule();

  print('AjaxUrl: ${module.injector.get(String, AjaxUrl)}');
  print('ServerPort: ${module.injector.get(int, ServerPort)}');
  // primitives without annotation are not supported and throw an exception
  // print('int: ${module.injector.get(int)}'); 
  print('Chat: ${module.injector.get(Chat).ws.url}');
  print('Updates: ${module.injector.get(Updates).ws.url}');
}