1

In typescript, it seems that the RxJS Observable.flatMap is not behaving correctly with Observable created with Observable.fromPromise(promise).

I suspect that it does not trigger the change detection.

I have these 2 functions (in _httpClient class) :

ObservableFromPremise() : Observable<boolean>{
        var promise =  this._storage.getJson('authToken').then((token) => {
            return true;
        });
        return Observable.fromPromise(promise)
}

BasicObservable() : Observable<boolean>{
     return Observable.create(observer => {
         observer.next(true);
         observer.complete();
     });
}

When I do this :

  public get = (url: string) : Observable<Response>  => {

       return this.ObservableFromPremise()
        .flatMap((x) => {
                return this.http.get(url, {headers:this._headers})
                    .map( (responseData) => {
                        return responseData.json();
                    });
           });
    }

My view in not updated, and I need to click somewhere (like a button) to have the retrieved data displayed.

But when I use BasicObservable() instead of ObservableFromPremise(), my view is updated.

Here is how I deal with the function get (in UserConnector class) :

public makeRequest = (id: number): Observable<User> => {
    return this._httpClient.get('http://jsonplaceholder.typicode.com/posts/1')
        .map((item:any) => {
            return new User({
                id: item.id,
                userId: item.userId,
                title: item.title,
                body: item.body
            });

        });
}

and in my page :

public myItems: User;

constructor(private userConnector: UserConnector) {

}

ngOnInit() {
        this.getAllItems();
}

private getAllItems(): void {
    this.userConnector
        .makeRequest(this.selectedItem.id)
        .subscribe((data:User) => {
            console.log(data);
            this.myItems = data;
        },
            error => console.log(error),
            () => {console.log('Get Item completed'); });
}

And here is the template :

     <div class="thumbnail" *ngIf="myItems">
         <div class="caption">
             <h3>{{myItems.title}}</h3>
             <p>{{myItems.body}}</p>
             <p>{{myItems.id}}</p>
             <p>{{myItems.userId}}</p>
         </div>
     </div>

In Both cases, I have the data retrieved logged in console, as well as "Get Item completed", but with ObservableFromPremise(), the data are not updated on the screen (until I click on a button).

My config : angular2 (2.0.0-rc.1), RxJS (5.0.0-beta.6), zone.js (0.6.12), e6-shim (0.35.00)

What can I do about this? Is it a bug in my code? in zone.js? in RxJS?

Thx for your help

Edit 1 : As suggested by @Richard-Silveira I will use NgZone as a temporary workaround :

.subscribe((data:User) => {
   this._ngZone.run(() => {
      this.myItems = data;
   });
}

I hope that someone will share a real solution =)

2
  • when is this._storage.getJson('authToken') resolving? Commented May 20, 2016 at 17:54
  • I guess that it is resolved when the data is retrieved. It comes from 'ionic-angular' : --> import {Storage, SqlStorage} from 'ionic-angular' and then -->this._storage = new Storage(SqlStorage); Commented May 20, 2016 at 18:06

2 Answers 2

2

Should you use NgZone to update the UI as follow:

private update() {
    this._zone.run(() => {
        console.log('auth updated!');
    });
}

...and after the return in your subscribe call this update function:

.subscribe((data:User) => {
            this.update();
            this.myItems = data;
        },
Sign up to request clarification or add additional context in comments.

2 Comments

@GeoffreyD, if you found an answer, even by yourself post it here, please, i really can't confirm to you that it is not a workaround, i think that is not, but i'm really curious about this issue, because i solved with this, but if there is a another more elegant way i will change my code too...
ok no problem, but I really need a solution as I will use it on every call to my API
0

Doesn't let me comment yet, guess I should build rep. Answering for Angular 4, in case you're still on 2 for whatever reason.

This is not a RxJS problem from the sounds of it (as your console logs show). You don't post the relevant bits from your component (like the decorator), but I'm making the assumption that you're using the OnPush change detection strategy?? If so, then you'll need to mark myItems with the @Input() decorator.

@Input() public myItems: User;

Optionally, if you want to go the brute force route, you can inject a ChangeDetectorRef and call markForCheck() on it.

constructor(private changeRef: ChangeDetectorRef) {}
...
// in your subscribe()
this.myItems = data;
this.changeRef.markForCheck(); // or call detectChanges() to immediately do so 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.