Reputation: 57116
Everything works as expected BUT I cannot get the view to update.
I would expect the subscription inside ngOnInit() to update the view each time data comes down the stream.
However, whilst data is coming down the stream, the code this.user = user does not update the view :(
My component code is ...
import {Component, OnInit} from '@angular/core';
import {Subject, Observable} from 'rxjs/Rx';
import {AuthService} from '../../../services/auth.service';
import 'rxjs/add/operator/catch';
declare let auth2:any;
@Component({
selector: 'user',
templateUrl: 'build/routes/app/user/user.component.html',
styleUrls: ['build/routes/app/user/user.component.css'],
providers: [AuthService]
})
export class UserComponent implements OnInit {
private userSubject = new Subject<string>();
public user:any;
public userStream:Observable<any> = this.userSubject.asObservable().flatMap((code:any) => {
let restStream = this.authService.signIn(code)
.map((response:any) => {
return JSON.parse(response._body);
}).catch((err:any) => {
return Observable.throw(err);
});
return restStream;
}).publish().refCount();
constructor(public authService:AuthService) {
}
ngOnInit() {
this.userStream.subscribe((user:any) => {
console.log(user); // user is set
this.user = user; // this does not update the view :(
});
}
public googleSignIn() {
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then((authResult:any) => {
this.userSubject.next(authResult.code);
});
}
}
view is simply ...
<button (click)="googleSignIn()">Google Sign In</button>
<div>USER = {{user | json}}</div>
How do I get Angular2 to update the view?
Note: the global declaration auth2 refers to global Google OAuth2 - thanks
Upvotes: 1
Views: 177
Reputation: 57116
The problem is seen in this explanatory code snippet ..
public googleSignIn() {
this.user = {fred:5}; // BINDINGS UPDATE HERE
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then((authResult:any) => {
this.user = {fred:6}; // BINDINGS DO NOT UPDATE HERE
this.userSubject.next(authResult.code);
});
}
Any attempt to update data inside auth2.grantOfflineAccess or any function or stream resulting from it failed to update the view!
I finally fixed the problem using JavaScript events.
The main difference here is that inside this.userStream.subscribe an event is dispatched and the event listener sets this.user
Here is my final working solution ..
import {Component, OnInit} from '@angular/core';
import {Subject, Observable} from 'rxjs/Rx';
import {AuthService} from '../../../services/auth.service';
import 'rxjs/add/operator/catch';
declare let auth2:any;
@Component({
selector: 'user',
templateUrl: 'build/routes/app/user/user.component.html',
styleUrls: ['build/routes/app/user/user.component.css'],
providers: [AuthService]
})
export class UserComponent implements OnInit {
public user:any;
private userSubject = new Subject<string>();
public userStream:Observable<any> = this.userSubject.asObservable().flatMap((code:any) => {
let restStream = this.authService.signIn(code)
.map((response:any) => {
return JSON.parse(response._body);
}).catch((err:any) => {
return Observable.throw(err);
});
return restStream;
}).publish().refCount();
constructor(public authService:AuthService) {
}
ngOnInit() {
this.addUserEventListener();
this.subscribeToUserStream();
}
public googleSignIn() {
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then((authResult:any) => {
this.userSubject.next(authResult.code);
});
}
private addUserEventListener() {
document.addEventListener('userEvent', (e:CustomEvent) => {
this.user = e.detail;
});
}
private subscribeToUserStream() {
this.userStream.subscribe((user:any) => {
let userEvent = new CustomEvent('userEvent', {'detail': user});
document.dispatchEvent(userEvent);
});
}
}
This solution works but I have no idea why auth2.grantOfflineAccess causes such problems in Angular2.
Worth knowing that this outside auth2.grantOfflineAccess === this inside auth2.grantOfflineAccess
Upvotes: 0
Reputation: 4013
Let confirm if this.user is being set by adding another console log in subscribe.
console.log(this.user);
I think it would be set but UI is not updating is your issue. Just for starter you can try wrapping the user set in timeout and see if UI updates like
setTimeout( user => this.user = user, 0);
If this gets you working then your a setting the variable too early/too late for change detection to pick up.
setTimeout
is not an ideal way to achieve this so we should refactor your code in appropriate way to ensure angular2 change detection picks up the changes. If this gets you working post more details about the template or put up a plunker and we can see what could be a better way to achieve.
Upvotes: 1