12

I use AngularFire2 to get data from Firebase Database (realtime).

What I have done:

  • Firebase Database

{ “class” : { “student” : { “Tom” : “male”, “Mary” : “female”, “Peter” : “male”, “Laura” : “female” }, "numberOfStudent” : 10 } }

  • app.component.ts

    import { AngularFireDatabase } from 'angularfire2/database';
    import { Observable } from 'rxjs/Observable';
    
    ...
    export class AppComponent {
    
       class: Observable<any>;
       students: Observable<any[]>;
    
    constructor(private db: AngularFireDatabase) {
       this.class = db.object(‘class’).valueChanges();
       this.students = db.list(‘class/student’).snapshotChanges();
     }
    
    } 
    
  • app.component.html:

<h2>Class size: {{ (class | async)?.numberOfStudent }}</h2>
<ul>
  <li *ngFor="let i of students | async">
    {{i.key}} : {{i.value}}
  </li>
</ul>

What happened:

Class size: 10

Tom :

Mary :

Peter :

Laura :

It doesn't return the value of list.

Any suggestion is appreciated.

Phong Vu
  • 2,726
  • 6
  • 24
  • 52

7 Answers7

15

UPD

with new Angular 6 and RxJS 6 you'll do this:

import { map } from 'rxjs/operators';
// ...
return this.fb.list(`/path/to/list`)
  .snapshotChanges()
  .pipe(map(items => { .            // <== new way of chaining
    return items.map(a => {
      const data = a.payload.val();
      const key = a.payload.key;
      return {key, data};           // or {key, ...data} in case data is Obj
    });
  }));
Ivan
  • 852
  • 1
  • 12
  • 29
  • `Property 'subscribe' does not exist on type '() => Observable<{ key: string; }[]>'.` I cant subscribe to this return. any idea? – Omar Jun 28 '18 at 14:54
7

AngularFire2 library has gone through some breaking changes since @rickdroio's answer. The following is an updated version of the solution:

afs.collection<Shirt>('class/student').snapshotChanges().map(actions => {
  return actions.map(a => {
    const data = a.payload.val();
    const id = a.payload.id;
    return { id, ...data };
  });
});
  • 1
    getting this error `ERROR TypeError: this.fb.list(...).snapshotChanges(...).map is not a function at ...` I assume it's because of the RxJS 6 version. Does anyone know how to fix it? – Ivan Jun 07 '18 at 06:27
  • see response below – Ivan Jun 07 '18 at 06:44
6

I managed to get the key and value of list. Just follow some tips below:

  • Make sure using snapshotChanges()

<li *ngFor="let i of seats | async">
    {{i.key}} : {{i.payload.val()}}
</li>

It worked for me, but I am still opening to receive more best practices

Phong Vu
  • 2,726
  • 6
  • 24
  • 52
2

According to guideline available on https://github.com/angular/angularfire2/blob/master/docs/firestore/collections.md you could do something like that:

afs.collection<Shirt>('class/student').snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data();
        const id = a.payload.doc.id;
        return { id, ...data };
      });
    });

It will return a similar array like previous Firebase db.

rickdroio
  • 505
  • 4
  • 6
1

your problem is your JSON object students is not an array, and you are trying to loop through it.

    "student" : { “Tom” : “male”, “Mary” : “female”, “Peter” : “male”, “Laura” :
“female” }, "numberOfStudent” : 10 }

you need to make your students a list of objects in order to loop through them, like so:

   "student" :
[ { "name" : "Tom", "sex" : male}, {"name" : "Mary, "sex" : "female" }, ... ]

the loop through let i of student | async and access the name and sex i?.name, i?.sex

FussinHussin
  • 1,718
  • 4
  • 19
  • 39
  • I got your point, but this JSON is generated from Firebase Database. I handle data by using AngularFire2, not handle data thru the JSON. – Phong Vu Oct 05 '17 at 14:40
  • I understand, but the way your data is formatted is a bad practice, best practice would be to put it into a list of objects format – FussinHussin Oct 05 '17 at 15:54
1

With Angular 6
Breakdown:

  1. I created a Map to store the key/values for future queries.

  2. Fetched the values and added them to the previously created Map

  3. Created two helper methods to get the key or the value separately.

todosKeyValues: Map<string, Todo> = new Map();

constructor(private databaseFB: AngularFireDatabase) {
    this.fetchKeyValues();
 }

private fetchKeyValues() {
    this.databaseFB.list('/').snapshotChanges().subscribe(actions => {
      actions.forEach(action => {
        const value = action.payload.val();
        const id = action.payload.key;
        this.todosKeyValues.set(id, value);
      });
    });
  }


 private getKey(id: number): string {
 const foundEntry = Array.from(this.todosKeyValues.entries())
    .filter(entry =>entry[1].id === id).pop();
   return foundEntry ? foundEntry[0] : undefined;
  }

  private getTodo(id: number): Todo {
    const foundEntry = Array.from(this.todosKeyValues.entries())
    .filter(entry => entry[1].id === id).pop();
      //index 0 is the key, index 1 is the value
    return foundEntry ? foundEntry[1] : undefined;
  }
  ...
Jorciney
  • 674
  • 10
  • 11
0

I tried all of these above, none of this worked as of Angular 6 this worked for me

   const m = this.firestore.collection("class/student").snapshotChanges();
    m.subscribe(res =>{
      console.log(res)
      res.forEach(res => {
        const value = res.payload.doc.data();
        const id = res.payload.doc.id;
        console.log(value," ",id)
      });
    })

A lot of methods of angular fire went obsolete. The key lied in vs code suggestion, in future if this doesn't work you would have to explore the provided similarly. For now

res.payload.doc.data()
res.payload.id

Would work.

Harsh Nagarkar
  • 697
  • 7
  • 23