2016-04-03 30 views
16

私は、初期化が完了する前に非同期作業を行う必要があるAngular 2サービスを使用しています。Angular 2サービスの非同期初期化

@Injectable() 
export class Api { 
    private user; 
    private storage; 

    constructor(private http: Http) { 
     this.storage = LocalStorage; 
     this.storage.get('user').then(json => { 
      if (json !== "") { 
       this.user = JSON.parse(json); 
      } 
     });   
    } 

    // one of many methods 
    public getSomethingFromServer() { 
     // make a http request that depends on this.user 
    } 
} 

現在のところ、このサービスは初期化されており、それを使用するコンポーネントにすぐに返されます。そのコンポーネントはngOnInitgetSomethingFromServer()を呼び出しますが、その時点でApi.userは初期化されていないため、間違った要求が送信されます。

ライフサイクルフック(OnInitOnActivateなど)はサービスでは使用できません。コンポーネントとディレクティブのみで動作しないため、使用できません。

get()からPromiseを保存するには、ユーザーがそれを待つためのさまざまな方法が必要となり、多くのコードの重複が発生します。

アンギュラ2でサービスを非同期初期化するにはどうすればよいですか?

答えて

5

ビットのためのティエリの回答で働いた後、私はそれが一度だけうまくいくことを発見し、それが正しい道に私を設定しました。私は代わりにユーザーの約束を保存し、新しい観察可能物を作成しなければならなかった。これはflatMap -edであった。

@Injectable() 
export class Api { 
    private userPromise: Promise<User>; 

    constructor(private http: Http) { 
    this.userPromise = LocalStorage.get('user').then(json => { 
     if (json !== "") { 
     return JSON.parse(json); 
     } 
     return null; 
    });   
    } 

    public getSomethingFromServer() { 
     return Observable.fromPromise(this.userPromise).flatMap((user) => { 
     return this.http.get(...).map(...); 
     }); 
    } 
    } 
} 

これはflatMap機能はティエリの回答のように、だけでなく、初めての、ユーザーが呼び出されるたびに取得することを保証します。

+0

ユーザーがLocalStorageに存在する場合はどうなりますか?毎回httpからそれを取得するつもりはありませんか? –

+0

@MadHollander httpコールを実行する前にOPがサービスのブートストラップを待っていただけで、httpコールがユーザーを取得することはなく、事前にユーザーが解決する必要がある – dannrob

5

flatMap演算子を使用して観測可能な観測値を利用することができます。ユーザーがそこにいない場合は、それを待ってターゲット要求をチェーンすることができます。ここで

はサンプルです:

@Injectable() 
export class Api { 
    private user; 
    private storage; 
    private userInitialized = new Subject(); 

    constructor(private http: Http) { 
    this.storage = LocalStorage; 
    this.storage.get('user').then(json => { 
     if (json !== "") { 
     this.user = JSON.parse(json); 
     this.userInitialized.next(this.user); 
     } 
    });   
    } 

    // one of many methods 
    public getSomethingFromServer(): Observable<...> { 
    // make a http request that depends on this.user 
    if (this.user) { 
     return this.http.get(...).map(...); 
    } else { 
     return this.userInitialized.flatMap((user) => { 
     return this.http.get(...).map(...); 
     }); 
    } 
    } 
} 
+1

考えが私に発生しました。しかし、私はこれらの 'getSomethingFromServer'の多くを持っています、そして、これはそれらのすべてがこの小さなダンスを行うことを必要とするでしょう。これには非同期のファクトリパターンのようなものがありますか? –

+1

このアプローチはあなたに興味があります:http://stackoverflow.com/questions/36365134/angular2-bootstrap-with-data-from-ajax-calls/36370302#36370302 and http://stackoverflow.com/questions/36180108/how -to-bootstrap-an-angular-2-application-asynchronously –

+0

これについてもっと考えればするほど、あなたのソリューションの音が良くなります。私はそれを実装に行くが、私は少し問題があります。 'Subject'はどこから来ますか?それは 'Rx.Subject'ですか?それは 'emit'メソッドを持っていないようです。一般に、私はこれにどのような輸入品が必要ですか? –

関連する問題