Matt Richard
Matt Richard

Reputation: 11

Angular 2 w/ TypeScript Firebase API returns array of objects in service but undefined in component

I am trying to use the Firebase API in my Angular 2 application.

Here is what I have in my Service:

fbGetData() {
        firebase.database().ref('/path/to/data').on('value',(snapshot) => {
            this.data = snapshot.val();
            console.log(this.data); //This logs my data
            return this.data;
        })
    }

This is what I have in my Component:

ngOnInit() {
        this.data = this.dataService.fbGetData();
        console.log(this.data); //This logs undefined
    }

The component logs undefined and then the service logs the array of objects. Thanks in advance for any help.

Upvotes: 0

Views: 653

Answers (2)

Mohammad S. Alam
Mohammad S. Alam

Reputation: 128

You can try the subscribe method to get data. The Observable can be subscribed ,mapped and can be converted into JSON.

Have a look at the code and see if you can get something.

public sessions(): any {
    return this.http.get('api/ResultsAPI')         //.get('api/vehicles.json')
        .map(
        (response: Response) => <any>response.json())
        .do
        (
        response => response
        );
}

To call the service use this

this.ApiService.sessions().subscribe(
data =>  {
   this.api = data;
   this.getdata(this.api);
}
);

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 599081

As @jonrsharpe commented: Firebase retrieves data from its servers asynchronous. Your browser won't wait for this result, as that would block the user from doing other actions. So you cannot return the data from fbGetData as it hasn't been loaded yet.

There are two ways to work with asynchronous loading:

  1. use a callback
  2. return a promise

use a callback

The trick for asynchronous loading is to reframe your solution from "first get the data, then print it" to "whenever the data is loaded, print it".

In code this translates to:

fbGetData() {
    firebase.database().ref('/path/to/data').on('value',(snapshot) => {
        this.data = snapshot.val();
        console.log(this.data);
    })
}

fbGetData();

So the logging is now purely in on() callback.

Of course you might want to do something different with the data at different times, so you can pass in a callback to fbGetData():

fbGetData(callback) {
    firebase.database().ref('/path/to/data').on('value',(snapshot) => {
        this.data = snapshot.val();
        callback(this.data);
    })
}

fbGetData(data => console.log(data));

Of course at this stage, you should consider if you shouldn't simply be invoking your own callback with a snapshot:

fbGetData(callback) {
    firebase.database().ref('/path/to/data').on('value',callback);
}

fbGetData(data => console.log(data.val()));

return a promise

In the above example the data will be printed when it is initially loaded from the server and whenever the data on the server is changed. This is part of the magic of the Firebase Database: it synchronizes both the current value and any changes to that value.

If you only care about the current value, you can also use once(). This method can take a callback, but it can alternatively also return a promise. That means that you have something that you can return from fbGetData:

fbGetData() {
    var promise = firebase.database().ref('/path/to/data').once('value');
    return promise;
}

fbGetData().then(snapshot => console.log(snapshot.cal());

With this snippet the value will only be printed (at most) once, since you're using once().

Upvotes: 1

Related Questions