1

I'm trying to work with angulafire2 to use my data stored in Firebase Database in my Angular app and I'm having some trouble with nested arrays.

I have an structure that looks like this:

items{
    item1{
        name: item1,
        subitems{
            subitem1{
                name: subitem1
            },
            subitem2{
                name: subitem2
            }
        }
    }
}

I'm using a FirebaseListObservable to get the items array.

items: FirebaseListObservable<any>;
[...]
this.items = this.af.database.list('/items');

And the problem appears when I try to display the data.

<div *ngFor="let item of items | async">
    <span>{{(item)?.name}}</span>

    <div *ngFor="let subitem of (item)?.subitems">
        <span>{{(subitem)?.name}}</span>
    </div>

</div>

I get an error because item.subitems is not recognized as an array.

Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.


EDIT: I made a plunker that uses a test database in Firebase as the example above. HERE

Carlos Rivero
  • 342
  • 2
  • 17

3 Answers3

0

I got the same issue, not with firebase but that doesn't matter in this case.

items: FirebaseListObservable<any>;
[...]
this.items = this.af.database.list('/items');
this.items.forEach(record => {
  console.Debug(record); // show output
  record.subitems.forEach(subRecord => { 
    console.Debug(subRecord); // show output too
  });
});

When excuting this, you get console logs right? In my case I do and I got same construction in view. I'm watching this issue in case it get solved.

Albert Hoekstra
  • 128
  • 2
  • 12
  • Already tried that and should use `suscribe()` method because those are asynchronous arrays. But still don't understand how to display the data without using complicated structures. – Carlos Rivero Jan 13 '17 at 12:59
0

I solved it in my case.

<div *ngFor="let item of items">
    {{item.prop}}
    <table>
      <tr *ngFor="let subitem of item.subItems">
        <td>{{subitem.prop}}</td>
      </tr>
    </table>
  </div>

Try it like this first, this is working after changing some property names. After that, replace the elements for your own elements and test it after every change to see if it's still working.

Albert Hoekstra
  • 128
  • 2
  • 12
0

Firebase structures should generally avoid being deeply nested. The deeper your structure is the more complicated they are.

But you can map over the structure and convert an object to an array using something like Object.keys(obj) or the experimental Object.value(obj) or write you own function as further on below

For example to convert the keys for a level

this.items = db.list('/items').map(items => {
  return items.map(item => {
    return {
       item: Object.keys(item.subitem)
    }
  });
});

You can also do something like this using a function in the ngFor loop found in this stack question

<li *ngFor="let o of obj">
   <p *ngFor="let item of generateArray(o)">{{item.key}}: {{item.value}}  </p>
</li>

using this function

generateArray(obj){
    return Object.keys(obj).map((key)=>{ return {key:key, value:obj[key]}});
}

Which should give you the keys and the values

Mangopop
  • 329
  • 2
  • 12