2

I am trying to display nested data from Firebase to Ionic project. I have the following data structure in firebase:

enter image description here

My query:

let dbRefLists = firebase.database().ref('lists/');
var self = this; 
dbRefLists.on('value', (querySnapshot) => {
    this.lists = Object.keys(querySnapshot.val()).map(key => querySnapshot.val()[key]);
    querySnapshot.forEach((data) => {
      var listItem = data.val().id;
      dbRefLists.child(`${listItem}/listItems`).on('value', (snapshotVal) => {
        if (snapshotVal.val() !== null) {
          self.lists.listItems = Object.keys(snapshotVal.val()).map(key => snapshotVal.val()[key]);
        }
      })
      return self.lists.listItems;
    })
    return lists;
});

My HTML:

<ul>
  <li *ngFor="let list of lists; let i=index" text-wrap (click)="toggleGroup(i)" [ngClass]="{active: isGroupShown(i)}">
    <h2>
      <span>{{list.title}}</span> 
    </h2>
    <ul *ngIf="isGroupShown(i)">
      <li *ngFor="let listItem of lists.listItems">
        <span>{{listItem.title}}</span> 
      </li>
    </ul>
  </li>
</ul>

The result is that I receive list items in all the lists (List1 and List2), instead of only in List1:

enter image description here

Where is my mistake? Thanks

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
stefan007
  • 19
  • 1
  • 6

1 Answers1

2

If you flatten your data base structure like this:

database structure

queuing will become much easier. First let me create classes, they will be in the Firebase service file that showed below:

export class myList {
  listId: string
  elClass: string;
  title: string;
  items?: myItem[];

  constructor(listId: string,elClass: string,title: string, items?: myItem[]){
    this.listId=listId;
    this.elClass=elClass;
    this.title=title;
    if(items){
      this.items = items;
    }
  }
}

export class myItem {
  listId: string;
  title: string;

  constructor(listId: string,title: string){
    this.listId=listId;
    this.title=title;
  }
}

Getting the data:

data: myList[] = [];

onGetListsWithItems(){
  let ref = firebase.database().ref('/');

  ref.child('lists/').on('child_added', (snapshot)=>{
    let list: myList = new myList(snapshot.key, snapshot.val().elClass, snapshot.val().title);
    let items: myItem[] = [];
    let listId = snapshot.key;
    ref.child('listItems/')
      .orderByChild('listId')
      .equalTo(listId)
      .on('child_added', (item)=>{
        items.push(new myItem(item.val().listId, item.val().title));
      });
    list.items = items;
    this.data.push(list);
  });
}

This will give you(console.log of data):

[myList, myList]
0:{
  elClass:"inActive",
  listId:"randomlistId1",
  title:"List1",
  items: {
    0:{
      listId:"randomlistId1",
      title:"Item2"},
    1:{
      listId:"randomlistId1",
      title:"Item1"}
},
1:{
  elClass:"inActive",
  listId:"randomlistId2",
  title:"List2",
  items:{ 
    0:{
      listId:"randomlistId2",
      title:"Item2"}
}

and finally you can display it in HTML like this:

<ul>
  <li *ngFor="let list of data">
    <h3>{{list.title}}</h3>
    <ul>
      <li *ngFor="let item of list.items">
        <p>{{item.title}}</p>
      </li>
    </ul>
  </li>
</ul>

the result looks like this:

printed result

Let me know if you will need any comments thought the code or you will have any questions.

P.S. You can read about flatting the database here new docs and here old docs

Arttu
  • 351
  • 2
  • 14
  • Thanks @Arttu, your solution works perfect. I changed my database structure and obviously flatten data base structures are better to quering. Thanks a lot. – stefan007 Jan 20 '18 at 09:27
  • There is still place for improvements. For example by using Observables. But I am new to ionic and I am not sure how it will behave with them. That is why I gave a simpler version. – Arttu Jan 20 '18 at 12:37