TypeScript를 사용하여 Angular2의 http 데이터에서 RxJS Observables 연결


96

저는 지난 4 년 동안 AngularJS 1. *를 즐겁게 작업 한 후 현재 Angular2와 TypeScript를 가르치려고 노력하고 있습니다! 나는 그것을 싫어한다는 것을 인정해야하지만 내 유레카 순간이 곧 다가오고 있다고 확신합니다 ... 어쨌든 JSON을 제공하는 전화 백엔드에서 http 데이터를 가져 오는 더미 앱에 서비스를 작성했습니다.

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에서는 컨트롤러에서 "Pyramid of Doom"을 피하기 위해 이와 같은 작업을 수행하는 것처럼 쉬웠습니다.

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

}

나는 분명히 뭔가 잘못하고 있습니다 ... Observables와 RxJS로 어떻게 최선을 다할까요? 어리석은 질문을하면 미안하지만 미리 도와 주셔서 감사합니다! 또한 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 is not a function in [null]'오류가 발생합니다.
Mike Sav

이 오류는 어디에 있습니까? 전화 할 때 this.userData.getUserInfo()?
Thierry Templier 2016

3
오! 내 대답에 오타가 있습니다. this.userData.getUserPhotos(), this.userData.getUserInfo()대신 this.userData.getUserPhotos, this.userData.getUserInfo(). 죄송합니다!
Thierry Templier 2016

1
왜 flatMap? switchMap이 아닌 이유는 무엇입니까? 초기 GET 요청이 갑자기 User에 대한 또 다른 값을 출력한다면, User의 이전 값에 대한 이미지를 계속 가져오고 싶지 않을 것이라고 가정합니다
f.khantsis

4
이것을보고 왜 작동하지 않는지 궁금해하는 사람을 위해 : RxJS 6에서 import 및 forkJoin 구문이 약간 변경되었습니다. 이제 import { forkJoin } from 'rxjs';함수를 가져 오기 위해 추가해야 합니다. 또한 forkJoin은 더 이상 Observable의 구성원이 아니라 별도의 함수입니다. 그래서 대신 Observable.forkJoin()그냥 forkJoin().
Bas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.