TypeScript ile Angular2'deki http verilerinden RxJS Observables zincirleme


99

Şu anda son 4 yıldır AngularJS 1 ile mutlu bir şekilde çalıştıktan sonra kendime Angular2 ve TypeScript'i öğretmeye çalışıyorum! Bundan nefret ettiğimi itiraf etmeliyim ama eureka anımın hemen köşede olduğundan eminim ... neyse, kukla uygulamamda JSON'a hizmet eden yazdığım sahte bir arka uçtan http verilerini alacak bir hizmet yazdım.

import {Injectable} from 'angular2/core';
import {Http, Headers, Response} from 'angular2/http';
import {Observable} from 'rxjs';

@Injectable()
export class UserData {

    constructor(public http: Http) {
    }

    getUserStatus(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/userstatus', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserInfo(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/profile/info', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserPhotos(myId): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get(`restservice/profile/pictures/overview/${ myId }`, {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    private handleError(error: Response) {
        // just logging to the console for now...
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }   
}

Şimdi bir Bileşen ben dilek hem çalıştırın (veya zincir) için getUserInfo()ve getUserPhotos(myId)yöntemler. AngularJS'de bu, kontrolörümde "Kıyamet Piramidi" nden kaçınmak için böyle bir şey yapacağım gibi kolaydı ...

// Good old AngularJS 1.*
UserData.getUserInfo().then(function(resp) {
    return UserData.getUserPhotos(resp.UserId);
}).then(function (resp) {
    // do more stuff...
}); 

Şimdi benim bileşeninde benzer bir şey yapıyor çalıştı (yerine gelmiş .theniçin .subscribebenim hata konsolu çıldırıyor ancak)!

@Component({
    selector: 'profile',
    template: require('app/components/profile/profile.html'),
    providers: [],
    directives: [],
    pipes: []
})
export class Profile implements OnInit {

    userPhotos: any;
    userInfo: any;

    // UserData is my service
    constructor(private userData: UserData) {
    }

    ngOnInit() {

        // I need to pass my own ID here...
        this.userData.getUserPhotos('123456') // ToDo: Get this from parent or UserData Service
            .subscribe(
            (data) => {
                this.userPhotos = data;
            }
        ).getUserInfo().subscribe(
            (data) => {
                this.userInfo = data;
            });
    }

}

Belli ki yanlış bir şey yapıyorum ... Observables ve RxJS ile en iyi nasıl olurum? Aptalca sorular soruyorsam özür dilerim ... ama şimdiden yardım için teşekkürler! Http başlıklarımı bildirirken işlevlerimde tekrarlanan kodu da fark ettim ...

Yanıtlar:


141

Kullanım durumunuz için, flatMapihtiyacınız olan şeyin operatör olduğunu düşünüyorum :

this.userData.getUserPhotos('123456').flatMap(data => {
  this.userPhotos = data;
  return this.userData.getUserInfo();
}).subscribe(data => {
  this.userInfo = data;
});

Bu şekilde, birincisi alındığında ikinci isteği yerine getireceksiniz. flatMapBaşka bir tane yürütmek için önceki isteği (önceki olayın) sonucunu kullanmak istediğinizde operatör özellikle yararlıdır. Kullanabilmek için operatörü içe aktarmayı unutmayın:

import 'rxjs/add/operator/flatMap';

Bu cevap size daha fazla ayrıntı verebilir:

Yalnızca subscribeyöntemi kullanmak istiyorsanız , bunun gibi bir şey kullanırsınız:

this.userData.getUserPhotos('123456')
    .subscribe(
      (data) => {
        this.userPhotos = data;

        this.userData.getUserInfo().subscribe(
          (data) => {
            this.userInfo = data;
          });
      });

Bitirmek için, her iki isteği de paralel olarak yürütmek ve tüm sonuçlar geldiğinde bilgilendirilmek istiyorsanız, şunu kullanmayı düşünmelisiniz Observable.forkJoin(eklemeniz gerekir import 'rxjs/add/observable/forkJoin'):

Observable.forkJoin([
  this.userData.getUserPhotos(),
  this.userData.getUserInfo()]).subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});

Ancak 'TypeError: source.subscribe, [null] içinde bir işlev değil' 'hatasını alıyorum
Mike Sav

Bu hatayı nerede alıyorsunuz? Ararken this.userData.getUserInfo()mi?
Thierry Templier

3
Oh! Cevabımda bir yazım hatası vardı: this.userData.getUserPhotos(), this.userData.getUserInfo()yerine this.userData.getUserPhotos, this.userData.getUserInfo(). Afedersiniz!
Thierry Templier

1
neden flatMap? Neden SwitchMap yapmıyorsunuz? İlk GET isteği aniden Kullanıcı için başka bir değer
verirse

4
Buna bakan ve neden çalışmadığını merak eden herkes için: RxJS 6'da import ve forkJoin sözdizimi biraz değişti. Şimdi import { forkJoin } from 'rxjs';işlevi içe aktarmak için eklemeniz gerekir . Ayrıca forkJoin artık Observable'ın bir üyesi değil, ayrı bir işlevdir. Yani bunun yerine Observable.forkJoin()sadece forkJoin().
Bas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.