I have a service that fetches some objects via firebase. It then populates an array which should then prompt angular to update the DOM with an *ngFor statement, but it doesn
I find a bit strange the way you use promises. It should be the reason of your problem. As a matter of fact, you return a promise resolved with an empty array. This array is directly used within the then
method on the other side. When the value
event is received, you return another promise within the callback which is never used.
I think you should return a promise and resolve it when the values are received within the callback for the value
event.
Here is the refactoring I would propose within the getTeachers
method to fix your problem:
getTeachers() {
return new Promise((resolve, reject) => {
this.teachersRef.on("value", function(snapshot) {
var tempArr = new Array(snapshot.numChildren());
snapshot.forEach(function(data) {
var teacher = {
name: data.key(),
position: data.val().stilling
}
tempArr.push(teacher);
});
resolve(tempArr);
});
});
}
Edit
After having some tests with your code on Firebase, it found out where the problem is. In fact, using promises isn't possible here since they are only called once. I mean the callback specified within the then
method will be called only for the first value
event. This is a drawback of promises.
To go over this restriction, you need to use observables. Here is the refactored version of the getTeachers
method:
import {Injectable} from 'angular2/core';
(...)
import {Observable} from 'rxjs/Rx';
@Injectable()
export class TeachersService {
(...)
getTeachers() {
return new Observable(observer => {
this.teachersRef.on("value", snapshot => {
var tempArr = [];
snapshot.forEach(function(data) {
var teacher = {
name: data.key(),
position: data.val().stilling
}
tempArr.push(teacher);
});
observer.next(tempArr);
}
});
}
Within the component you can call the getTeachers
method like this:
@Component({
(...)
template: `
(...)
<ul>
<li *ngFor="#teacher of teachers">
<strong>{{teacher.name}}</strong>
</li>
</ul>
`,
providers: [ TeachersService ]
})
export class AppComponent {
(...)
ngOnInit() {
this.populateTeachersArr();
}
populateTeachersArr() {
this._teachersService.getTeachers().subscribe(teachers =>
this.teachers = teachers;
);
}
}
or go further by leveraging the async
pipe (which will directly manages the observable object):
@Component({
(...)
template: `
(...)
<ul>
<li *ngFor="#teacher of (teachers | async)">
<strong>{{teacher.name}}</strong>
</li>
</ul>
`,
providers: [ TeachersService ]
})
export class AppComponent {
(...)
ngOnInit() {
this.populateTeachersArr();
}
populateTeachersArr() {
this.teachers = this._teachersService.getTeachers();
}
}
Hope it helps you, Thierry