1. ホーム
  2. angular

[解決済み] Angular 2 ServiceからObservableを作成し返す

2022-05-11 20:39:19

質問

これはベストプラクティスというより、質問です。3人のプレイヤーがいます。 Component , a ServiceModel . は ComponentService を呼び出してデータベースからデータを取得しています。その Service が使われています。

this.people = http.get('api/people.json').map(res => res.json());

を返すように Observable .

Component をサブスクライブすることができます。 Observable :

    peopleService.people
        .subscribe(people => this.people = people);
      }

しかし、私が本当に欲しいのは Service を返すことです。 Array of Model のデータから作成されたオブジェクトを返します。 Service がデータベースから取得したデータから作成されたオブジェクトです。私は、この Component はこの配列を subscribe メソッドで作成することもできますが、サービス側がそれを行って Component .

どのようにすれば Service は新しい Observable を作成し、その配列を含んで、それを返しますか?

どのように解決するのですか?

UPDATE: 9/24/16 Angular 2.0 Stable(安定版)。

この質問はまだ多くのトラフィックを得るので、私はそれを更新したいと思いました。Alpha、Beta、および7つのRC候補からの変更の狂気によって、私は、安定するまで私のSO回答を更新するのを止めました。

これは 件名 再生の対象

I 個人的に を好んで使用します。 ReplaySubject(1) を使うことを好みます。これは、新しい購読者の登録が遅れた場合でも、最後に保存された値を渡すことができるからです。

let project = new ReplaySubject(1);

//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));

http.get('path/to/whatever/projects/1234').subscribe(result => {
    //push onto subject
    project.next(result));

    //add delayed subscription AFTER loaded
    setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});

//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234

そのため、遅れて添付したり、後でロードする必要がある場合でも、常に最新の呼び出しを取得でき、コールバックを見逃す心配がありません。

これはまた、プッシュダウンするために同じストリームを使用することができます。

project.next(5678);
//output
//Subscription Streaming: 5678

しかし、100%確実に、一度だけ呼び出す必要がある場合はどうでしょうか?オープンなサブジェクトやオブザーバブルを残しておくのは良くないですが、常に What If?"。

そこで AsyncSubject の出番です。

let project = new AsyncSubject();

//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
                  err => console.log(err),
                  () => console.log('Completed'));

http.get('path/to/whatever/projects/1234').subscribe(result => {
    //push onto subject and complete
    project.next(result));
    project.complete();

    //add a subscription even though completed
    setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});

//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234

すごい! 件名を閉じたにもかかわらず、最後に読み込んだもので返信しています。

もうひとつは、httpコールをどのように購読し、レスポンスを処理したかです。 マップ はレスポンスを処理するのに適しています。

public call = http.get(whatever).map(res => res.json())

しかし、これらの呼び出しをネストする必要がある場合はどうでしょうか?そうです、特別な関数でサブジェクトを使用することができます。

getThing() {
    resultSubject = new ReplaySubject(1);

    http.get('path').subscribe(result1 => {
        http.get('other/path/' + result1).get.subscribe(response2 => {
            http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
        })
    })
    return resultSubject;
}
var myThing = getThing();

しかし、それはたくさんあり、それを行うための関数が必要であることを意味します。入る フラットマップ :

var myThing = http.get('path').flatMap(result1 => 
                    http.get('other/' + result1).flatMap(response2 => 
                        http.get('another/' + response2)));

甘い、その var は最終的な http 呼び出しからデータを取得する observable です。

OKそれは素晴らしいですが、私はangular2サービスが欲しいです!

私はあなたを得た。

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';

@Injectable()
export class ProjectService {

  public activeProject:ReplaySubject<any> = new ReplaySubject(1);

  constructor(private http: Http) {}

  //load the project
  public load(projectId) {
    console.log('Loading Project:' + projectId, Date.now());
    this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
    return this.activeProject;
  }

 }

 //component

@Component({
    selector: 'nav',
    template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
 export class navComponent implements OnInit {
    public project:any;

    constructor(private projectService:ProjectService) {}

    ngOnInit() {
        this.projectService.activeProject.subscribe(active => this.project = active);
    }

    public load(projectId:string) {
        this.projectService.load(projectId);
    }

 }

私はオブザーバとオブザーバブルの大ファンなので、このアップデートがお役に立てれば幸いです。

オリジナルの回答

を使うユースケースだと思います。 観測可能なサブジェクト で、あるいは Angular2EventEmitter .

あなたのサービスでは EventEmitter を作成し、その上に値をプッシュできるようにします。で アルファ45 で変換する必要があります。 toRx() で変換する必要があるのですが、それをなくそうと動いていたのは知っていたので α46 を単純に返すことができるかもしれません。 EvenEmitter .

class EventService {
  _emitter: EventEmitter = new EventEmitter();
  rxEmitter: any;
  constructor() {
    this.rxEmitter = this._emitter.toRx();
  }
  doSomething(data){
    this.rxEmitter.next(data);
  }
}

この方法では、単一の EventEmitter にプッシュすることができます。

もし、呼び出しから直接observableを返したければ、次のようにすることができます。

myHttpCall(path) {
    return Observable.create(observer => {
        http.get(path).map(res => res.json()).subscribe((result) => {
            //do something with result. 
            var newResultArray = mySpecialArrayFunction(result);
            observer.next(newResultArray);
            //call complete if you want to close this stream (like a promise)
            observer.complete();
        });
    });
}

そうすると、コンポーネントの中でこんなことができるようになります。 peopleService.myHttpCall('path').subscribe(people => this.people = people);

そして、サービス内で呼び出しの結果をいじります。

を作るのが好きです。 EventEmitter ストリームを単独で作成するのが好きなのですが、他のコンポーネントからアクセスする必要がある場合に備えて、両方の方法が機能しているのを確認できました...

イベントエミッターを持つ基本的なサービスを示すプランカーです。 プランカー