问题
For a JWT authentification, I make a post request to get the token using the new Http
module working with Observables now.
I have a simple Login
component showing the form:
@Component({
selector: 'my-login',
template: `<form (submit)="submitForm($event)">
<input [(ngModel)]="cred.username" type="text" required autofocus>
<input [(ngModel)]="cred.password" type="password" required>
<button type="submit">Connexion</button>
</form>`
})
export class LoginComponent {
private cred: CredentialsModel = new CredentialsModel();
constructor(public auth: Auth) {}
submitForm(e: MouseEvent) {
e.preventDefault();
this.auth.authentificate(this.cred);
}
}
I have a Auth
service making the request:
@Injectable()
export class Auth {
constructor(public http: Http) {}
public authentificate(credentials: CredentialsModel) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
.map(res => res.json())
.subscribe(
data => this._saveJwt(data.id_token),
err => console.log(err)
);
}
}
Works well but now I want to display error messages inside my component so I need to subscribe in 2 places (Auth
for managing success and Login
for managing error).
I achieved it using share
operator:
public authentificate(credentials: CredentialsModel) : Observable<Response> {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
const auth$ = this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
.map(res => res.json()).share();
auth$.subscribe(data => this._saveJwt(data.id_token), () => {});
return auth$;
}
And inside the component:
submitForm(e: MouseEvent) {
e.preventDefault();
this.auth.authentificate(this.cred).subscribe(() => {}, (err) => {
console.log('ERROR component', err);
});
}
It works but I feel doing it wrong..
I just transpose the way we did it with angular1 and promises
, do you see better way to achieve it?
回答1:
Why would you subscribe to in sharedService
, when this approach can be used !
@Injectable()
export class Auth {
constructor(public http: Http) {}
public authentificate(credentials: CredentialsModel) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers}) //added return
.map(res => res.json());
//.subscribe(
// data => this._saveJwt(data.id_token),
// err => console.log(err)
//);
}
}
@Component({
selector: 'my-login',
template: `<form (submit)="submitForm($event)">
<input [(ngModel)]="cred.username" type="text" required autofocus>
<input [(ngModel)]="cred.password" type="password" required>
<button type="submit">Connexion</button>
</form>`
})
export class LoginComponent {
private cred: CredentialsModel = new CredentialsModel();
constructor(public auth: Auth) {}
submitForm(e: MouseEvent) {
e.preventDefault();
this.auth.authentificate(this.cred).subscribe(
(data) => {this.auth._saveJwt(data.id_token)}, //changed
(err)=>console.log(err),
()=>console.log("Done")
);
}
}
Edit
still if you want to subscribe in
sharedService
and component
you can surely go with this approach. But I'd not recommend this rather before edited section seems perfect to me.
I can't test it with your code. but look at my example here(tested). click on myFriends tab
,check browser console and UI. browser console shows subscription result of sharedService
& UI shows subscription result of component
.
@Injectable()
export class Auth {
constructor(public http: Http) {}
public authentificate(credentials: CredentialsModel) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
var sub = this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers}) //added return
.map(res => res.json());
sub.subscribe(
data => this._saveJwt(data.id_token),
err => console.log(err)
);
return sub;
}
}
export class LoginComponent {
private cred: CredentialsModel = new CredentialsModel();
constructor(public auth: Auth) {}
submitForm(e: MouseEvent) {
e.preventDefault();
this.auth.authentificate(this.cred).subscribe(
(data) => {this.auth._saveJwt(data.id_token)}, //not necessary to call _saveJwt from here now.
(err)=>console.log(err),
()=>console.log("Done")
);
}
}
回答2:
You can only subscribe to event in the service and return the corresponding observable:
public authentificate(credentials: CredentialsModel) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
var obs = this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
.map(res => res.json())
.subscribe(
data => this._saveJwt(data.id_token)
);
return obs;
}
If errors occur, you can catch it using the catch
operator:
submitForm(e: MouseEvent) {
e.preventDefault();
this.auth.authentificate(this.cred).catch((err) => {
console.log('ERROR component', err);
});
}
Edit
If you want to subscribe twice to an observable, you need to make it "hot" by calling the share
method.
You could also leverage the do
operator and only subscribe in the component:
public authentificate(credentials: CredentialsModel) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
.map(res => res.json())
.do(
data => this._saveJwt(data.id_token)
);
}
来源:https://stackoverflow.com/questions/35888531/angular2-how-to-subscribe-to-http-post-observable-inside-a-service-and-a-compon