How to Inject Angular2 Http service into es6/7 Cla

2019-01-12 05:44发布

If I use es6/7 (babel - stage 1) instead of TypeScript, how are services, and specifically Http, injected?

Here's my component JS:

import {Component, Inject, View, CORE_DIRECTIVES, ViewEncapsulation} from 'angular2/angular2';
import {Http} from 'angular2/http';

@Component({
  selector: 'login'
})
@View({
  templateUrl: './components/login/login.html',
  styleUrls: ['components/login/login.css'],
  directives: [CORE_DIRECTIVES],
  encapsulation: ViewEncapsulation.Emulated
})
export class Login {
  constructor(@Inject(Http) http) {
    console.log('http', http);
  }

  authenticate(username, password) {
    // this.http.get('/login');
  }
}

I have tried:

export class Login {
  constructor(@Inject(Http) http) {
    console.log('http', http);
  }
}
/********************/
@Inject(Http)
export class Login {
  constructor(http) {
    console.log('http', http);
  }
}
/********************/
export class Login {
  constructor(Http: http) {
    console.log('http', http);
  }
}
/********************/
export class Login {
  constructor(http = Http) {
    console.log('http', http);
  }
}
/********************/
export class Login {
  constructor(Http) {
    this.http = new Http()
    console.log('http', this.http);
  }
}
/********************/
export class Login {
  constructor(http = new Http()) {
    console.log('http', http);
  }
}

All but the first compiles. Others give me access to either the Http class or an http instance. But none works.

I tried to following the discussion referenced by Eric Martinez in his comment. Login.js now:

import {Component, Inject, View, CORE_DIRECTIVES, ViewEncapsulation} from 'angular2/angular2';
import {HTTP_BINDINGS, Http, BaseRequestOptions, RequestOptions, RequestMethods} from 'angular2/http';

@Component({
  selector: 'login'
})
@View({
  templateUrl: './components/login/login.html',
  styleUrls: ['components/login/login.css'],
  directives: [CORE_DIRECTIVES],
  encapsulation: ViewEncapsulation.Emulated,
  bindings: [Http]
})
export class Login {

  constructor(http) {
    this.http = http;
    console.log('http', http);
  }

  authenticate(usernameEl, passwordEl) {
    var username = usernameEl.value;
    var password = passwordEl.value;
    console.log('username', username, password);

    // this.http.get('/login');
  }
}

Login.parameters = [Http];

It compiles now but generates the following error:

Uncaught (in promise) NoBindingError {message: "No provider for Http! (Login -> Http)", stack: "Error: DI Exception↵ at NoBindingError.BaseExce…or._new (http://localhost:3000/bundle.js:7319:22)", keys: Array[2], injectors: Array[2]}constructResolvingMessage: (keys)arguments: (...)caller: (...)length: 1name: ""prototype: Object__proto__: ()context: (...)injectors: Array[2]0: Injector1: Injectorlength: 2__proto__: Array[0]keys: Array[2]message: "No provider for Http! (Login -> Http)"stack: "Error: DI Exception↵ at NoBindingError.BaseException [as constructor] (http://localhost:3000/bundle.js:8400:24)↵ at NoBindingError.AbstractBindingError [as constructor] (http://localhost:3000/bundle.js:9066:17)↵ at new NoBindingError (http://localhost:3000/bundle.js:9102:17)↵ at Injector._throwOrNull (http://localhost:3000/bundle.js:7469:20)↵ at Injector._getByKeyDefault (http://localhost:3000/bundle.js:7516:22)↵
at Injector._getByKey (http://localhost:3000/bundle.js:7461:26)↵ at Injector._getByDependency (http://localhost:3000/bundle.js:7447:26)↵
at Injector._instantiate (http://localhost:3000/bundle.js:7339:37)↵
at Injector._instantiateBinding (http://localhost:3000/bundle.js:7330:26)↵ at Injector._new (http://localhost:3000/bundle.js:7319:22)"proto: __

4条回答
我只想做你的唯一
2楼-- · 2019-01-12 06:14

How I've already answered it here, If you write code in ES7, use static getter for parameters property to specify injections into constructor of your component. For example:

import { Http } from 'angular2/http';
// other imports ...

// component decorators ...
export class Login {

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

  constructor(http) {
    this.http = http;
    console.log('http', http);
  }

  // other methods
}

I think it most concise method at this moment.

Remember there is no proposal to support parameter decorators in ES7 at this moment (for example see this issue for Babel).

查看更多
放荡不羁爱自由
3楼-- · 2019-01-12 06:18

Since you have @Decorators enabled in Babel

...I'll fine-tune this answer to work with your specific setup.

1. You're missing HTTP_PROVIDERS

The HTTP_PROVIDERS constant includes a number of functions required to handle HTTP requests/responses.

import {Http, HTTP_PROVIDERS} from 'angular2/http';    

@Component({
  selector: 'login',
  providers: [ HTTP_PROVIDERS ]
})

2. You need to desugar the DI (Dependency Injection) syntax

As mentioned in @alexpods' answer.

Remove the static typing

constructor(http) {

@Inject handles DI implicitly but is only supported in Angular2+Typescript. Since you're using Angular2+ES6 you need to attach a static getter parameter to your class to provide the ES6-specific equivalent.

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

3. You need to bind the Http instance to your class in the constructor

By doing this, it will become accessible in your authenticate() method.

constructor(http) {
    this.http = http;
    console.log('http', this.http);
}

...and the full implementation:

import {Component, Inject, View, CORE_DIRECTIVES, ViewEncapsulation} from 'angular2/angular2';
import {Http, HTTP_PROVIDERS} from 'angular2/http';

@Component({
  selector: 'login',
  // required for Http
  providers: [ HTTP_PROVIDERS ]
})
@View({
  templateUrl: './components/login/login.html',
  styleUrls: ['components/login/login.css'],
  directives: [CORE_DIRECTIVES],
  encapsulation: ViewEncapsulation.Emulated
})
export class Login {
  constructor(http) {
    // bind http to your class during construction
    //   so it's available to authenticate()
    this.http = http;
  }

  // Angular2 DI desugar'd
  static get parameters() {
    return [[Http]];
  }

  authenticate(username, password) {
    this.http.get('/login');
  }
}

Aside: I know for a fact this works because I'm using it for the <ng2-markdown> component on EvanPlaice.com.

查看更多
欢心
4楼-- · 2019-01-12 06:23

Method from the official API Review works for me:

import {Http, HTTP_PROVIDERS} from 'angular2/http';
@Component({
  selector: 'http-app',
  viewProviders: [HTTP_PROVIDERS],
  templateUrl: 'people.html'
})
class PeopleComponent {
  constructor(http: Http) {
    http.get('people.json')
      .map(res => res.json())
      .subscribe(people => this.people = people);
  }
}
查看更多
劳资没心,怎么记你
5楼-- · 2019-01-12 06:23

With babel-plugin-angular2-annotations, you can inject services with constructor parameter type annotations just like TypeScript.

Install babel plugins:

npm install -D babel-plugin-angular2-annotations babel-plugin-transform-decorators-legacy babel-plugin-transform-class-properties babel-plugin-transform-flow-strip-types babel-preset-es2015

.babelrc:

{
  "plugins": [
    "angular2-annotations",
    "transform-decorators-legacy",
    "transform-class-properties",
    "transform-flow-strip-types"
  ],
  "presets": [
    "es2015"
  ]
}

and voila!

import {Component, View, CORE_DIRECTIVES, ViewEncapsulation} from 'angular2/angular2';
import {Http} from 'angular2/http';

@Component({
  selector: 'login'
})
@View({
  templateUrl: './components/login/login.html',
  styleUrls: ['components/login/login.css'],
  directives: [CORE_DIRECTIVES],
  encapsulation: ViewEncapsulation.Emulated
})
export class Login {
  constructor(http: Http) {
    console.log('http', http);
    this.http = http;
  }

  authenticate(username, password) {
    this.http.get('/login');
  }
}

Note that the type signature is used only for a hint for dependency injection and not used for type-checking.

查看更多
登录 后发表回答