简体   繁体   中英

How to Inject Angular2 Http service into es6/7 Class?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM