javascript Injeção de dependência angular 2 em ES5 e ES6



angularjs export controller (2)

Decorador Injectable é específico para o tipo TypeScript de Angular 2. Ele permite que um construtor de classe seja implicitamente anotado para DI através de anotações do tipo TypeScript. É redundante em TS e desnecessário em JS para dependências injetadas que são anotadas com Inject .

Angular 2 injetáveis ​​(classes e funções construtoras) devem ser anotados com annotations e parameters propriedades estáticas sob o capô.

annotations é uma matriz que contém new decoradores ed para classe injetável:

function SomeComponent(...) {}
SomeComponent.annotations = [new Componenent(...)];

parameters é uma matriz que contém decoradores para parâmetros de construtor, cada elemento é uma matriz que contém uma lista de new decoradores ed para a respectiva propriedade de construtor (similarmente à anotação explícita da propriedade $inject em Angular 1.x):

function Service(someService, anotherService) {}
Service.parameters = [
  [new Inject(SomeService)],
  [new Inject(AnotherService), new Optional, new SkipSelf]
];

Todos os decoradores de classes são estendidos do TypeDecorator , o que significa que eles podem ser chamados como funções. Neste caso, é usada a chamada sintaxe DSL, que permite encadear um decorador com a função auxiliar de Class :

var SomeComponent = Componenent(...).Class(...);

Class também está disponível separadamente, ela constrói uma nova classe a partir de determinado objeto de definição e permite anotar o método constructor com array (similarmente à anotação explícita da matriz inline no Angular 1.x):

var SomeService = Class({
  constructor: [[new Inject(SomeService)], function (someService) {}]
});

Class auxiliar de Class foi descontinuado nas versões mais recentes do framework. É suposto ser substituído por funções brutas ou ajudantes de classe de terceiros no ES5. Decoradores suportam encadeamento direto com funções de classe, Componenent(...)(ComponentClass) .

Angular 2/4 ES6 com System.import

Um example :

Promise.all([
  System.import('@angular/core'),
  System.import('@angular/platform-browser'),
  System.import('@angular/platform-browser-dynamic')
])
.then(([
  {Component, Inject, Injectable, Optional, NgModule, OpaqueToken},
  {BrowserModule},
  {platformBrowserDynamic}
]) => {

  const CONSTANT = { value: 'constant' };
  const CONSTANT_TOKEN = new OpaqueToken;
  const CONSTANT_PROVIDER = { provide: CONSTANT_TOKEN, useValue: CONSTANT };

  class Service {
    constructor(constant) {}
  }
  Service.parameters = [[new Inject(CONSTANT_TOKEN)]];

  class AppComponent {
    constructor(service, constant) {}
  }
  AppComponent.annotations = [new Component({
    selector: 'app',
    template: '...',
    providers: [Service, CONSTANT_PROVIDER]
  })];
  AppComponent.parameters = [[new Inject(Service)], [new Inject(CONSTANT_TOKEN)]];

  class AppModule {}
  AppModule.annotations = [new NgModule({
    imports: [BrowserModule],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
  })];

  platformBrowserDynamic().bootstrapModule(AppModule);

})
.catch((err) => console.error(err));

Angular 2/4 ES5 com módulos UMD e ng global

Um example :

var Class = ng.core.Class;
var Component = ng.core.Component;
var Inject = ng.core.Inject;
var Injectable = ng.core.Injectable;
var NgModule = ng.core.NgModule;
var OpaqueToken = ng.core.OpaqueToken;

var BrowserModule = ng.platformBrowser.BrowserModule;
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;

var CONSTANT = { value: 'constant' };
var CONSTANT_TOKEN = new OpaqueToken;
var CONSTANT_PROVIDER = { provide: CONSTANT_TOKEN, useValue: CONSTANT };

// Class helper function that uses A1-flavoured inline array DI annotations
// and creates an annotated constructor
var Service = Class({
  constructor: [[new Inject(CONSTANT_TOKEN)], function (constant) {
    console.log('Service constructor', constant);
  }]
});
// can also be
// function Service(constant) {};
// Service.parameters = [[new Inject(...)], ...];

// when not being `new`ed, Component is a chainable factory that has Class helper method
var AppComponent = Component({
  selector: 'app', 
  template: '...',
  providers: [Service, CONSTANT_PROVIDER]
})
.Class({
  constructor: [
    [new Inject(Service)],
    [new Inject(CONSTANT_TOKEN)],
    function (service, constant) {
      console.log('AppComponent constructor', service, constant);
    }
  ]
});
// can also be
// function AppComponent(...) {};
// AppComponent.annotations = [new Component(...)];
// AppComponent.parameters = [[new Inject(...)], ...];

var AppModule = NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
.Class({ constructor: function () {} });
// can also be
// function AppModule() {};
// AppModule.annotations = [new NgModule(...)];

platformBrowserDynamic().bootstrapModule(AppModule);

Aqui está um exemplo básico de TypeScript / ES.next que usa decoradores para DI e segue a sintaxe sugerida pelo manual do framework:

import {Component, Inject, Injectable, NgModule, OpaqueToken} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

const CONSTANT = { value: 'constant' };
const CONSTANT_TOKEN = new OpaqueToken;
const CONSTANT_PROVIDER = { provide: CONSTANT_TOKEN, useValue: CONSTANT };

@Injectable()
class Service {
  constructor(@Inject(CONSTANT_TOKEN) constant) {
    console.log('Service constructor', constant);
  }
}

@Component({
  selector: 'app',
  template: '...',
  providers: [Service, CONSTANT_PROVIDER]
})
class AppComponent {
  constructor(@Inject(Service) service: Service, @Inject(CONSTANT_TOKEN) constant) {
    console.log('AppComponent constructor', service, constant);    
  }
}

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
class AppModule {}

platformBrowserDynamic().bootstrapModule(AppModule);

Como seria escrito no ES5?

Como seria a mesma coisa no ES6 / ES2015 não transferido?

Como os decoradores Injectable e Inject traduzidos nesses casos?

A questão se aplica particularmente a implementações do navegador ES6 do mundo real que possuem classes, mas podem usar require ou System.import vez de importações do ES6.


Answer #1

Para usar o Angular 2 com o ES5, você precisa deste script:

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/2.0.0-beta.3/angular2-all.umd.js"></script>

Isso fornece uma variável global que contém todo o Angular 2. Agora você pode escrever ng.core.Component vez da anotação @Component . Os primeiros parâmetros do construtor são os injetáveis.

var Component = ng.core
  Component({
    selector: 'hello-cmp',
    template: 'Hello World!',
    viewProviders: [Service]
  .Class({
    constructor: [Service, function (service) { 
      ...
    }],
  });

E diga ao injector que nosso parâmetro de serviço é uma instância do Service

Component.parameters = [[new ng.core.Inject(Service)]];


O Exapmle a seguir mostra o uso de angular2 com o ES6 :

import {Component} from 'angular2/core';
import {Service} from './example.service';

let componentAnnotation = new Component({
  selector: 'world-time',
  inputs: ['timeZones'],
  providers: [Service],
  template: `
    ...
  `
});
export class ComponentExample {
   constructor(service) {
    this._service = service;

   }
...

}

WorldTimeComponent.annotations = [componentAnnotation];
WorldTimeComponent.parameters = [[Service]];

Neste plunkr você pode encontrar um exemplo de ES6 funcional.

Mas você pode usar decoradores usando o Babel . Ativando os optional[]=es7.decorators (no webpack) ou definindo sua configuração para o stage:1 .





ecmascript-6