टाइपस्क्रिप्ट के साथ Angular2 में http डेटा से RxJS वेधशालाओं का पीछा करते हुए


96

मैं वर्तमान में अपने आप को Angular2S टाइप करने की कोशिश कर रहा हूँ और पिछले 4 वर्षों से AngularJS 1. * के साथ टाइपस्क्रिप्ट काम कर रहा हूँ! मुझे यह मानना ​​होगा कि मैं इससे नफरत कर रहा हूं, लेकिन मुझे यकीन है कि मेरा यूरेका पल कोने के आसपास ही है ... वैसे भी, मैंने अपने डमी ऐप में एक सेवा लिखी है जो पीएचएन बैकएंड से http डेटा प्राप्त करेगा जो मैंने लिखा था कि JSON परोसता है।

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');
    }   
}

अब एक घटक में मैं (या श्रृंखला) दोनों getUserInfo()और getUserPhotos(myId)विधियों को चलाना चाहता हूं । AngularJS में यह मेरे नियंत्रक के रूप में आसान था, मैं "कयामत के पिरामिड" से बचने के लिए कुछ ऐसा करूंगा ...

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

अब मैंने अपने कंपोनेंट (रिप्लेस ) में कुछ ऐसा ही करने की कोशिश की है .then, .subscribeलेकिन मेरी गलती कंसोल पागल हो रही है!

@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;
            });
    }

}

मैं स्पष्ट रूप से कुछ गलत कर रहा हूं ... मैं ऑब्जर्वबल्स और आरएक्सजेएस के साथ कैसे सर्वश्रेष्ठ करूंगा? क्षमा करें अगर मैं बेवकूफ सवाल पूछ रहा हूँ ... लेकिन अग्रिम में मदद के लिए धन्यवाद! मैंने अपने HTTP हेडर की घोषणा करते समय अपने कार्यों में बार-बार कोड भी देखा है ...

जवाबों:


138

आपके उपयोग के मामले में, मुझे लगता है कि flatMapऑपरेटर को आपकी आवश्यकता है:

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

इस तरह, आप पहले अनुरोध प्राप्त होने के बाद दूसरे अनुरोध पर अमल करेंगे। flatMapजब आप पिछले अनुरोध (पिछले घटना) का परिणाम का उपयोग करने के एक और एक पर अमल करना चाहते हैं ऑपरेटर विशेष रूप से उपयोगी है। इसका उपयोग करने में सक्षम होने के लिए ऑपरेटर को आयात करना न भूलें:

import 'rxjs/add/operator/flatMap';

यह उत्तर आपको अधिक जानकारी दे सकता है:

यदि आप केवल subscribeविधि का उपयोग करना चाहते हैं , तो आप कुछ इस तरह का उपयोग करते हैं:

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

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

समाप्त करने के लिए, यदि आप समानांतर में दोनों अनुरोधों को निष्पादित करना चाहते हैं और अधिसूचित किया जाएगा जब सभी परिणाम होंगे, तो आपको उपयोग करने पर विचार करना चाहिए Observable.forkJoin(आपको जोड़ने की आवश्यकता है import 'rxjs/add/observable/forkJoin'):

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

हालाँकि मुझे यह त्रुटि मिलती है 'TypeError: source.subscribe [null] में एक फंक्शन नहीं है
माइक सेव

आपके पास यह त्रुटि कहां है? कब बुला रहे हो this.userData.getUserInfo()?
थिएरी टेम्पलियर

3
ओह! मेरे जवाब में एक टाइपो था: this.userData.getUserPhotos(), this.userData.getUserInfo()इसके बजाय this.userData.getUserPhotos, this.userData.getUserInfo()। माफ़ करना!
थियरी टेम्पलर

1
क्यों फ्लैटपोट क्यों नहीं स्विचपॉइंट? मुझे लगता है कि यदि प्रारंभिक GET अनुरोध अचानक उपयोगकर्ता के लिए एक और मान प्रदान करता है, तो आप उपयोगकर्ता के पिछले मूल्य के लिए छवियां प्राप्त नहीं करना चाहेंगे
f.khantsis

4
किसी को भी यह देखकर और सोच में पड़ जाता है कि यह काम क्यों नहीं कर रहा है: RxJS 6 में आयात और forkJoin सिंटैक्स थोड़ा बदल गया है। अब आपको import { forkJoin } from 'rxjs';फ़ंक्शन आयात करने के लिए जोड़ना होगा। इसके अलावा, forkJoin अब ऑब्जर्वेबल का सदस्य नहीं है, बल्कि एक अलग फ़ंक्शन है। इसलिए इसके बजाय Observable.forkJoin()बस forkJoin()
बास
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.