Angularfire: Get and show data from firebase references nodes

Created on 23 Jul 2017  路  7Comments  路  Source: angular/angularfire

Hi everyone, I am trying to display data from a referenced node in firebase and it did not seem to work well for me.
In firebase i have two nodes, applicants and students
sin titulo-1

And I need show the data of participants that are in the students node

This is my code in compent

import { Component, OnInit } from '@angular/core';
import { AngularFire, FirebaseListObservable } from 'angularfire2';

@Component({
  selector: 'app-students',
  templateUrl: './students.component.html',
  styleUrls: ['./students.component.css']
})
export class StudentsComponent implements OnInit {

  students: Array<any> = [];
  final_data: Array<any> = [];
  loading: boolean = true;
  constructor(private af: AngularFire) {
    af.database.list('/students', {
    }).subscribe(res => {
      this.students = res;
      this.final_data = this.students.map(function (key) {
        return af.database.list('/applicants/' + `${key.$key}`);
      });
      this.loading = false;
    });
  }

  ngOnInit() {
  }

}

And this is my code in template

{{final_data}}

<section class="contacto-main">
    <div class="container cont">
        <div *ngFor="let user of final_data">
            <b>{{user.name}}</b><br>
        </div>

    </div>
</section>

the result

sin titulo

Any help?

Thanks a lot

Most helpful comment

It looks like you are using a list when you don't want to be for that second database call. You should be using the object in this case. You are getting 14 lists instead of 14 objects. So your code should read

af.database.list('/students', {
    }).subscribe(res => {
        this.students = res;
        this.final_data = this.students.map(function (key) {
          return af.database.object('/applicants/' + `${key.$key}`);
      });
      this.loading = false;
    });
  }

And if I'm not mistaken, your template should make use of the async pipe since that data won't be available immediately. You're template should then be:

<section class="contacto-main">
    <div class="container cont">
        <div *ngFor="let user of final_data">
            <b>{{(user | async)?.name}}</b><br>
        </div>
    </div>
</section>

Honestly when I am querying 2 parts of the database and I need both pieces of data before I can display anything I start looking at some observable combinators to help with that type of issue. This would let you get data from both places and combine them into 1 observable without subscribing outside of a single async pipe in your template. It results in a little bit cleaner code I find, but it's up to you. In your case you need the list of students and then you use that list to get the info from the other node. You might try using combineLatest or zip, depending on how your data gets updated in the database.

Edit: Formatting was stupid

All 7 comments

It looks like you are using a list when you don't want to be for that second database call. You should be using the object in this case. You are getting 14 lists instead of 14 objects. So your code should read

af.database.list('/students', {
    }).subscribe(res => {
        this.students = res;
        this.final_data = this.students.map(function (key) {
          return af.database.object('/applicants/' + `${key.$key}`);
      });
      this.loading = false;
    });
  }

And if I'm not mistaken, your template should make use of the async pipe since that data won't be available immediately. You're template should then be:

<section class="contacto-main">
    <div class="container cont">
        <div *ngFor="let user of final_data">
            <b>{{(user | async)?.name}}</b><br>
        </div>
    </div>
</section>

Honestly when I am querying 2 parts of the database and I need both pieces of data before I can display anything I start looking at some observable combinators to help with that type of issue. This would let you get data from both places and combine them into 1 observable without subscribing outside of a single async pipe in your template. It results in a little bit cleaner code I find, but it's up to you. In your case you need the list of students and then you use that list to get the info from the other node. You might try using combineLatest or zip, depending on how your data gets updated in the database.

Edit: Formatting was stupid

I am not understanding your point very clearly, you would have some example code of the solution that you propose

@atinybeardedman Hi, As your upper comment can we do that with items: FirebaseListObservable; how to better code as below;
work with arrayItems:Array ,but not work with listObservable ,so it array is right rather than firebaseListObservable what different of them , please explain if possible .!

export class AppComponent {
  items: FirebaseListObservable<any>;
  wathlist: FirebaseListObservable<any>;
  arrayItems: Array<any> = [];
  arrayWathlist: Array<any> = [];
  newSubject: Subject<any>;

  constructor(db: AngularFireDatabase) {
    // this.items = db.list('/ktmarket');
    // this.items.subscribe(element => {
    //         console.log(element);
    // });
    // this.wathlist = db.list('/watchlist');
    // this.wathlist.subscribe(element => {
    //         console.log(element);
    // });

    db.list('/watchlist', {
    }).subscribe(res => {
      this.arrayWathlist = res;
      this.arrayItems = this.arrayWathlist.map(function (key) {
        return db.object('/ktmarket/' + `${key.$value}`);
        // console.log(`${key.$value}`);
      });
      // this.loading = false;
    });
    console.log(this.arrayItems);
  }

The solution is print in template as async
and retriev data as a object
Thanks

<div *ngFor="let user of final_data"> <b>{{(user | async)?.name}} </b><br> </div>

af.database.list('/students', { }).subscribe(res => { this.students = res; this.final_data = this.students.map(function (key) { return af.database.object('/applicants/' +${key.$key}); }); this.loading = false; });

Hi all,

I am trying to read the attribute of an object like the way specified above but I'm getting an error: Cannot read property dateCreated of null.

I was going to ask this question here but then I solved it so I'm writing the solution here. You can correct me if you want.
I solved the error by doing the following

<h5>Complaint Submitted on: {{ hello(item | async) }}</h5>
and in my typescript file:

hello(item) {
  if(item != null) {
      return item.dateCreated;
  }
}
Was this page helpful?
0 / 5 - 0 ratings