admin管理员组

文章数量:1200965

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: __

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: __

Share Improve this question edited Mar 22, 2016 at 14:32 ssuperczynski 3,4163 gold badges46 silver badges64 bronze badges asked Oct 8, 2015 at 21:11 rob_hicksrob_hicks 1,7343 gold badges24 silver badges35 bronze badges 3
  • See this issue and @brandonroberts comments – Eric Martinez Commented Oct 8, 2015 at 21:34
  • @EricMartinez Thanks for the reference. I modified it to match my understanding of the discussion. Unfortunately, I'm getting an error. – rob_hicks Commented Oct 9, 2015 at 0:27
  • Change this line bindings: [Http] to bindings: [HTTP_BINDINGS] and put it in @Component annotation and give it another try. – Eric Martinez Commented Oct 9, 2015 at 1:28
Add a comment  | 

4 Answers 4

Reset to default 13

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.

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

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

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.

本文标签: javascriptHow to Inject Angular2 Http service into es67 ClassStack Overflow