2016-12-08 52 views
4

角度2 v2.0.1では、onInitが2回呼び出されます。 (もちろん、私も一度呼ばれていたときにも、何か間違ったことをやっているが、それは今の問題ではありません)角度2 httpが2回呼び出されて観測可能になる

はここに私のPlunkerです:http://plnkr.co/edit/SqAiY3j7ZDlFc8q3I212?p=preview

ここではサービスコードです:

import {Injectable} from '@angular/core'; 
import {Http, Response} from '@angular/http'; 
import {Observable} from 'rxjs/Rx'; 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/do'; 

@Injectable() 
export class DemoService { 


    constructor(private http:Http) { } 

    // Uses http.get() to load a single JSON file 
    getData() { 
    return this.http.get('./src/data.json') 
     .map((res:Response) => res.json()) 
     .do(data => console.log(data)) 
     .subscribe(data => { 
     return <PageContent[]>data; 
     }, error => console.log("there was an error!")); 
    } 
} 

export class PageContent { 
    constructor(public _id: string, 
    public tag: string, 
    public title: string, 
    public body?:string, 
    public image?: string) {} 
} 

は...それを使用する単純なコンポーネントです。

//our root app component 
import {Component, NgModule, OnInit } from '@angular/core' 
import {BrowserModule} from '@angular/platform-browser' 
import { DemoService, PageContent } from './service'; 
import { HttpModule } from '@angular/http'; 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <div> 
     <h2>Hello {{name}}</h2> 
    </div> 
    <div *ngFor="let page of pages"> 
     {{ page.title }} 
    </div> 
    ` 
}) 
export class App implements OnInit { 
    name:string; 
    pages: PageContent[] = []; 

    constructor(private _service: DemoService) { 
    this.name = 'Angular2' 
    this.loadData(); // <-- this is called once 
    } 

    ngOnInit() { 
    //this.loadData(); // <-- this is called twice 
    } 

    loadData(){ 
    this.pages = this._service.getData(); 
    console.log(this.pages); 
    } 
} 

@NgModule({ 
    imports: [ BrowserModule, HttpModule ], 
    declarations: [ App ], 
    providers: [DemoService], 
    bootstrap: [ App ] 
}) 
export class AppModule {} 

免責事項:それはアウトerroringですが、あなたはそれがサービスメソッドがコンストラクタから呼び出されているときに一度提供されていますが、それはngOnInitフックの内側だとき、それが二回呼び出さ見ることができます。

私の質問は、なぜOnInit関数から2回呼び出されているのですか?

UPDATE:すべての答えから解決策:

これは、新しいサービスメソッドです:

getData() { 
    return this.http.get('./src/data.json') 
     .map((res:Response) => res.json() as PageContent[]); 
} 

...と、これは新しいコンポーネントのメソッドです:

loadData(){ 
    this._service.getData() 
     .subscribe(data => this.pages = data); 
} 
+1

削除テンプレートの一部がngForを使用してアプリケーションを失敗させ、通常の状況では1度だけ呼び出されることがわかります。 –

+0

@JBNizet - しかし、データを表示するには* ngForが必要です。 –

答えて

4

subscribeはサービスの代わりにコンポーネントに入れてください。あなたのコンポーネントである理由は、サービスから返されたデータを購読して、後で必要に応じて、退会やコントロールを追加することができます。コードは変更後にこのようになります。あなたのコンポーネントで

ngOnInit() { 
    this.loadData(); 
    } 



    loadData(){ 
    this._service.getData().subscribe(data => this.pages = data); 
    } 
あなたのサービスで

:英語で

getData() { 
    return this.http.get('./src/data.json') 
     .map((res:Response) => res.json()); 
    } 
+0

私はこれを元にしようとしたが動作しなかったので、私は別の何かを試しました。私はそれを元に戻したので、それはあなたのものと似ていますが、それでも1)データを返さない、それは繰り返し可能な配列が必要である、2)まだ2回呼び出されていると言います。 ngOnInit()の "hi" console.logに注目してください。私はrc 4で作業していました。 –

+0

@ KingWilder、私は私の答えで説明した変更であなたのプランナーを修正しました。 これをチェックしてくださいhttp://plnkr.co/edit/aLKI3cPthuKmcvU32BgF?p=preview –

+0

はい、回答とSoywodに基づいてPlunkを修正しました。 –

1

this._service.getData()を返しますSubject、PageContentリストではありません。

loadData() { 
    this._service.getData().subscribe(data => this.pages = data); 
    console.log("Load data !"); 
} 

と(DemoServiceから)あなたのgetData方法のsubscribe一部を削除する:あなたは、あなたがloadDataのように変更することができます。これをテストしたところ、ngOnInitが一度呼び出されました

+0

私のコメントはAnthony C.に書いたのと同じです。実際に強い型付けのためにPageContent配列を返す必要があります。私は角2文書あたりのPlunkを更新しましたが、それでも動作しません。まだ失われています。 –

0

、あなたはストリーム(Observable)に加入したときにサブスクライブブロック内の最初の関数内のコードは次のようになりますその観測値がデータを放出するときに実行される。

あなたが二回購読している場合、それは二回呼び出されます、など

あなたは購読ブロック内で複数回に(次の関数と呼ばれます)最初の関数をサブスクライブしているので、複数回実行されます。

ストリームを購読するのは、ngOnInitの中に1回だけです。

データをストリームに出力する場合は、RXJS Subjectを使用して、RXJSフラットマップを使用してサブジェクトしたストリームにサブジェクトを後で出力することができます。

+0

しかし、私は2度購読しているところはわかりません。 OK、私はそのサービスに加入していましたが、私はそのコンポーネントにそれを持っていませんでした。また、SubjectではなくPageContentオブジェクトの配列を返す必要があります。私はA2のドキュメントごとにPlunkを更新しましたが、変更はありません。 –

0

OK私の第二の答え...このことができますかどうかを確認...

対象は、あなたが(subject.nextと()メソッド)に放出されているRXJS対象である
return subject.asObservable().flatMap((emit: any) => { 

    return this.http[method](url, emit, this.options) 
    .timeout(Config.http.timeout, new Error('timeout')) 
    // emit provides access to the data emitted within the callback 
    .map((response: any) => { 
     return {emit, response}; 
    }) 
    .map(httpResponseMapCallback) 
    .catch((err: any) => { 
     return Observable.from([err.message || `${err.status} ${err.statusText}`]); 
    }); 
}).publish().refCount(); 

関連する問題