可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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: __
回答1:
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.
回答2:
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:
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);
}
}
回答4:
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.