1

I'm trying to parse fetched data from firebase at Angular (Typescript).

My JSON data looks like this in firebase:

"customer" : {
  "customerId1" : {
    "documents" : {
      "documentId1" : {
        "documentName" : "file1.pdf",
        "documentUrl" : "someUrl1"
      },
      "documentId2" : {
        "documentName" : "file2.pdf",
        "documentUrl" : "someUrl2"
      }
    },
    "email" : "[email protected]",
    "name" : "Customer 1",
  },
  "customerId2" : {
    "documents" : {
      "documentId3" : {
        "documentName" : "file3.pdf",
        "documentUrl" : "someUrl3"
      },
      "documentId4" : {
        "documentName" : "file4.pdf",
        "documentUrl" : "someUrl4"
      }
    },
    "email" : "[email protected]",
    "name" : "Customer 2",
  }
}

As you can see, each customer has 3 properties, documents, email and name at the first level. At the second level, the document property has nested property documentName and documentUrl. And for parsing customer data I used the following code.

customer.component.ts:

...
export class CustomerComponent implements OnInit {

  customerObservable: Observable<any[]>;
  customerList: Customer[];

  constructor(db: AngularFireDatabase) {
    // Listen to customer data
    this.customerObservable.subscribe(data => {
      this.customerList = data;
    });
  }

}
...

With this code I can fetch and iterate data with the ngFor directive at html with customerList variable. The question is, how can I achieve something like this?

// Variable that contains array of an array of customer's document array
documentList: Document[][];
// Or this
// Variable that holds customer's documents
customerDocuments: Document[];

// Where Document model looks like this
export class Document {
    public documentName: string;
    public documentUrl: string;
}

Thank you for the support.

3
  • What have you tried? We don't do free labor bro Commented Jan 17, 2018 at 20:15
  • I already tried to get the value from documents property and assign into an array (Document []), but when I assign the value and try to display at html with ngFor, it appears the error "Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.". Commented Jan 17, 2018 at 20:20
  • Something I could observe is that the document property was an object instead of an array when I log the content. I want to parse that object into an array of my defined Document model. How could I achieve this? Thank you! Commented Jan 17, 2018 at 20:23

1 Answer 1

1

Here is the service code:

import {Injectable} from '@angular/core';
import {AngularFireDatabase} from 'angularfire2/database';   
//rxJS
import {Observable} from 'rxjs/Observable';
import 'rxjs/operator/switchMap';   

@Injectable()
export class FirebaseService {
  constructor(private angularFireDatabase: AngularFireDatabase) {}

  onGetUserDocuments(customer: string) {
    return this.angularFireDatabase.list(`customer/${customer}/documents`).valueChanges()
  }

  onGetUsersDocuments(){
    return this.angularFireDatabase.list('customer').snapshotChanges()
      .map((changes)=>{
        return changes.map((data) => {
          return data.payload.key
        });
      })
      .switchMap((usersId: string[]) => {
        return Observable.combineLatest( usersId.map((u)=>{
          return this.onGetUserDocuments(u);
        }))
      })
  }
}

Then in your component you can call:

import {Component, OnInit} from '@angular/core'; 
import {FirebaseService} from '../services/firebase.service';
@Component({
  selector: 'new',
  templateUrl: './new.component.html',
  styleUrls: ['./new.component.css']
})
export class NewComponent implements OnInit {
  constructor(private firebaseService: FirebaseService) {}

  ngOnInit(){
    this.firebaseService.onGetUsersDocuments().subscribe(data => console.log(data));
  }
}

That will give you:

[Array(2), Array(2)]
0: Array(2)
  0: {documentName: "file1.pdf", documentUrl: "someUrl1"}
  1: {documentName: "file2.pdf", documentUrl: "someUrl2"}
1: Array(2)
  0: {documentName: "file3.pdf", documentUrl: "someUrl3"}
  1: {documentName: "file4.pdf", documentUrl: "someUrl4"}

So you can use it like so:

<div *ngFor="let docs of data">
  <div *ngFor="let doc of docs">
    <p>file name: {{doc.documentName}}</p>
    <p>file url: {{doc.documentUrl}}</p>
  </div>
</div>

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

P.S. What you really have to now that nesting like this is not recommended by firebase, you should flaten you data. You can read about this here new docs and here old docs

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, I already went flatten way! Thank you anyway :D I will try your code for learning purpose.
With flattened database the code stays mostly the same. Let's say you now have: documents:{randomDocId:{customerId:"id1", documentName:"name"}}, then you just modify onGetUserDocuments return like this: return this.angularFireDatabase.list('documents', ref => ref.orderByChild('customerId').equalTo(customer}).valueChanges()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.