2016-12-08 70 views
4

在Angular 2 v2.0.1中,onInit被調用兩次。 (很明顯,我也做一些錯誤的,當它被稱爲一次,但現在這不是問題)Angular 2 http可以被觀察到被調用兩次

這裏是我的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 {} 

免責聲明:它的示數出來,但你可以看到它被服務一次當正在從構造稱爲服務方法,但它被調用兩次當它是ngOnInit鉤內。

我的問題是,爲什麼它被從OnInit函數調用兩次?

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並導致應用程序失敗,並且您會在正常情況下看到它只被調用一次。 –

+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)它仍然被調用兩次。注意ngOnInit()中的「hi」console.log。我是有在RC工作4 –

+0

@KingWilder,我修改了plunker與我在答覆中描述的變化,它的工作對我罰款。 檢查了這一點http://plnkr.co/edit/aLKI3cPthuKmcvU32BgF?p=preview –

+0

是的,我修改了普拉克根據您的回答和Soywod,和它的工作。 –

1

this._service.getData()返回主題,而不是PageContent列表。你可以改變你loadData這樣的:

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

和(從DemoService)刪除您getData方法subscribe一部分。我剛剛測試過這個,並且ngOnInit被調用一次

+0

我的評論是爲我寫的安東尼C.同我確實需要返回PageContent數組強類型。我更新了每個Angular 2文檔中的Plunk,但它仍然無效。仍然處於虧損狀態。 –

0

在英語中,當您訂閱流(Observable)的第一個函數裏面的代碼裏面的訂閱塊會當可觀察者發射數據時執行。

如果您訂閱兩次將被調用兩次,等

因爲您訂閱多次認購塊內的第一功能(稱爲下一個函數)將被執行多次。

您應該只在ngOnInit內訂閱一次流。

當您想要將數據發送到流上時,您可以使用RXJS主體進行此操作,並使主體隨後使用RXJS平面映射發送到您訂閱的流。

+0

但我沒有看到我在哪裏訂閱兩次。好的,我在服務中訂閱了,但我沒有在組件中使用它。此外,我需要返回一組PageContent對象,而不是主題。我根據A2文檔更新了我的Plunk,並且沒有任何變化。 –

0

確定我的第二個答案......看看這有助於...

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(); 

,其中主題是,你要發射(與subject.next()方法)的RXJS主題