In Angular 2 v2.0.1 the onInit is called twice. (Obviously I'm also doing something wrong when it's called once, but that's not the issue right now)
Here's my Plunker: http://plnkr.co/edit/SqAiY3j7ZDlFc8q3I212?p=preview
Here's the service code:
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) {}
}
... and the simple component that uses it.
//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 {}
Disclaimer: it's erroring out, but you can see it's being served once when the service method is being called from the constructor, but it gets called twice when it's inside the ngOnInit hook.
My question is, why is it being called twice from the OnInit function?
UPDATE: solution from all answers:
This is the new service method:
getData() {
return this.http.get('./src/data.json')
.map((res:Response) => res.json() as PageContent[]);
}
... and this is the new component method:
loadData(){
this._service.getData()
.subscribe(data => this.pages = data);
}
this is happening because you subscribe to the observable twice, and observables execute every time they're subscribed to.
The most common reason for this is that you have called subscribe() multiple times. Every time it is called it adds a new message listener, even if that same listener is already registered for that event; when a message is received, every registered listener will be called with it.
Angular makes use of observables as an interface to handle a variety of common asynchronous operations. For example: The HTTP module uses observables to handle AJAX requests and responses. The Router and Forms modules use observables to listen for and respond to user-input events.
Your subscribe
should be put in the component instead of the service. Reason being your component is subscribed to the data returned from the service, and later on you can unsubscribe or add more control (such as denounce) if needed. The code will look like this after the changes.
In your component:
ngOnInit() {
this.loadData();
}
loadData(){
this._service.getData().subscribe(data => this.pages = data);
}
In you service:
getData() {
return this.http.get('./src/data.json')
.map((res:Response) => res.json());
}
this._service.getData()
returns a Subject, not a PageContent list. You could change your loadData
like :
loadData() {
this._service.getData().subscribe(data => this.pages = data);
console.log("Load data !");
}
and remove the subscribe
part of your getData
method (from DemoService
). I've just tested this, and the ngOnInit
is called once
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With