I am trying to bind my template to the value which was returned from subscription via callback. But there is no change detection invoked.
//authorisation service public login(data,callbackFromLogin : (msg) => void): void { this.http.httpPost(ApiRoutes.LoginRoute,data).subscribe(result => { callbackFromLogin(msg); }); } //and then in login component onSubmit(request) { this.authService.login(request,(message) => { alert(NgZone.isInAngularZone()); if(message) { this.ngZone.run( () => { this.message = message; alert(NgZone.isInAngularZone()); }); } }); }
<div>{{message}}</div>
The message does not change, though It gets a value from a service. I guess this issue is related to Zone.
I don't know exactly why this not happen.
But some question below.
Who is set msg
to the callback?
Maybe you want to do callbackFromLogin(result);
?
But I think you could try to implement another solution.
Why you are pass a callback to service and not do the function inside the subscription on the component?
Something like this:
// authorisation service
public login(data) {
return this.http.httpPost(ApiRoutes.LoginRoute, data);
// if you want manipulate the message you could use `pipe` method here
}
// and then in login component
onSubmit(request) {
this.authService.login().subscribe((message) => {
if(message){
this.message = message;
}
});
}
I used your advise and change my code to this:
//Service public login(data): Observable<any> { return this.http.httpPost(ApiRoutes.LoginRoute,data).pipe(map(result=>{ if (result && result.status == 200) { /// }else{ let msg = `my message`; return {msg:msg}; } })); } //login component onSubmit(request){ this.authService.login(request).subscribe((result) => { if(result.msg){ this.message = result.msg; alert( this.message ) } }); }
<div>{{message}}</div>
Same issue , the message is passed to result ,when I call to alert( this.message ) function , the message is shown above..but there is no change in a template Interpolation however.
Try this and let me know.
loginRequest: Observable<any>;
onSubmit()
: onSubmit(request){ this.loginRequest = this.authService.login(request); }
In your template,
<div>
{{ (loginRequest | async)?.msg }}
</div>
Here's a simple Http call.
import {HttpClient} from '@angular/common/http';
class SomeService {
constructor(private _http: HttpClient){}
postSomething() {
return this._http.post('url', toPost);
}
}
Yes..here is an AuthService:
import { SessionService } from '../session/session.service'; import { environment } from './../../../environments/environment'; import { IUser, UserType } from '../../../../../contracts/IUser'; import { IEmployee } from '../../../../../contracts/IEmployee'; import { Injectable,Inject } from '@angular/core'; import { Router } from '@angular/router'; import 'rxjs/add/operator/filter'; import * as auth0 from 'auth0-js'; import { Http } from '@angular/http'; import {ReplaySubject, Observable} from 'rxjs/Rx'; import { ApiService } from '../api/api.service'; import { ActivityService } from '../activity/activity.service'; import { UserActivityAction } from '../../../../../contracts/Library'; import { ApiRoutes } from '../../../../../contracts/ApiRoutes'; import { AlertService} from '../alert/alert.service'; import { MessageService} from '../message/message.service'; import {Events} from '../../../../../contracts/Library'; import { map } from 'rxjs/operators'; @Injectable() export class AuthService { private userIsLoggedIn : boolean; constructor(public http: ApiService,private rHttp: Http, private session:SessionService, @Inject('BASE_URL') public baseUrl: string, public router: Router, private alertService: AlertService, private activity: ActivityService, private messageService : MessageService) { this.session = session; } // logIn attempts to log in a user handleAuthentication() : void { let auth = this.http.httpGetAll(ApiRoutes.AuthRoute); auth.subscribe( data => { let results = data.json(); switch(results.status) { case 401: { this.routeAfterLogin(false); this.messageService.sendMessage('',Events.UserLogout); break; } case 402: { break; } case 200: { //when success break; } default: { this.routeAfterLogin(false); break; } } }, error => { console.log(error); }); this.router.navigate(['/home']); } public login(data): Observable<any> { return this.http.httpPost(ApiRoutes.LoginRoute,data).pipe(map(result=>{ if (result && result.status == 200) { //when success }else{ let msg = "some error message"; this.routeAfterLogin(false); return {msg:msg}; } })); } private routeAfterLogin(state:boolean) { this.userIsLoggedIn = state; if(this.userIsLoggedIn){ this.router.navigate(['/home']); console.log("Login"); } else { this.router.navigate(['/login']); console.log("Failure Login"); } } public logout(): void { let auth = this.http.httpGetAll(ApiRoutes.LogoutRoute); auth.subscribe( data => { console.log("Logout"); this.messageService.sendMessage('',Events.UserLogout); this.router.navigate(['/login']); }, error => { console.log(error); }); } public isAuthenticated(): boolean { return this.userIsLoggedIn; } public fillFileDownloadPass(){ let getUploadPath$ = this.http.httpGetAll(ApiRoutes.DownloaPathdRout); getUploadPath$.subscribe( data => { let results = data.json(); switch(results.status) { case 200: { this.session.download101AtchFilePath = results.filehDownloadPat; this.session.approvedFormsPath = results.approvedFormsPath; break; } case 400: { console.log("didn't find an upload path"); break; } default: { break; } } }, error => { console.log(error); }); } }
The handleAuthentication() function is called from the app.component..
ngOnInit() { this.authService.handleAuthentication(); this.subscription = this.messageService.getMessage().subscribe(message => { switch (message.type) { case Events.UserLogin: this.showNav = true; break; case Events.UserLogout: this.showNav = false; break; case Events.FirstEntrance : //some message break; } }); }
The ApiService's httpPost function wraps the http:
httpPost(url:string,data:any):Observable<Response | any> { return this._http.post(`${this.baseUrl}${url}`, data ) .map(this.parseData) .catch(this.handleError.bind(this)); } private parseData(res: Response) { return res.json() || []; }
I think it is a Zone related issue as you suggested..in that case:
onSubmit(request){ this.message="outer message" this.loginRequest = this.authService.login(request); this.loginRequest.subscribe((result) => { if(result.msg){ this.message ="inner message" // alert(this.message) } }); }
When onSubmit() fires , I see the "outer message" binding , but after entrance to subscription it disappears and the "inner message" is not shown at all.
I found the problem. In my AuthService, in login() function, which returns an Observable, I am making a call for a this.routeAfterLogin(false) . This function redirects my route to login page in case the error occurs. That redirection inside an observable messes the change detection. Actually I don't need it ,after removing it everything started to work fine. Thanks all for the help.
public login(data): Observable<any> { return this.rHttp.post(ApiRoutes.LoginRoute,data).pipe(map(result=>{ if(...){ // not relevant }else{ let msg = "error message"; this.alertService.error(msg); **this.routeAfterLogin(false);** this.messageService.sendMessage('',Events.UserLogout); return {msg:msg}; } })); } **private routeAfterLogin(state:boolean)** { this.userIsLoggedIn = state; if(this.userIsLoggedIn){ this.router.navigate(['/home']); console.log("Login"); } else { this.router.navigate(['/login']); console.log("Failure Login"); } }
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.