Angular 2 dependency injection in ES5 and ES6

匿名 (未验证) 提交于 2019-12-03 01:49:02

问题:

Here is a basic TypeScript/ES.next example that uses decorators for DI and follows the syntax suggested by the framework manual:

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); 

How would it be written in in ES5?

How would the same thing be done in untranspiled ES6/ES2015?

How are Injectable and Inject decorators translated in these cases?

The question particularly applies to real-world ES6 browser implementations that have classes but may use require or System.import instead of ES6 imports.

回答1:

To use Angular 2 with ES5 you need this script:

This provides an global variable that contains all of Angular 2. Now you can write ng.core.Component instead of the @Component annotation. The first parameters of the Constructor are the injectables.

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

And tell the injector that our service parameter is a instance of Service

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


The following Exapmle shows the usage of angular2 with 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]]; 

In this plunkr you can find a working ES6 example.

But you can use decorators by using Babel. Enabling the optional[]=es7.decorators (in webpack) or by setting your configuration to stage:1.



回答2:

Injectable decorator is specific to TypeScript flavour of Angular 2. It enables a class constructor to be implicitly annotated for DI through TypeScript type annotations. It is redundant in TS and unneeded in JS for injected dependencies that are annotated with Inject.

Angular 2 injectables (classes and constructor functions) are supposed to be annotated with annotations and parameters static properties under the hood.

annotations is an array that contains newed decorators for injectable class:

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

parameters is an array that contains decorators for constructor parameters, each element is an array that contains a list of newed decorators for respective constructor property (similarly to $inject property explicit annotation in Angular 1.x):

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

All class decorators are extended from TypeDecorator, meaning that they can be called as functions. In this case so-called DSL syntax is used that allows to chain a decorator with Class helper function:

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

Class is also available separately, it constructs a new class from given definition object and allows to annotate constructor method with array (similarly to inline array explicit annotation in Angular 1.x):

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

Angular 2/4 ES6 with System.import

An 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 with UMD modules and ng global

An 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); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!