1

I would like to know how to call a Firebase array using Angular 2. In my example here, I have an array addnote in my Firebase DB. There are two separate iterations of Do the dishes, and I would like to print them out to my HTML's unordered list.

The [] in my private addsnotes throws errors, and I didn't really expect otherwise. In the absence of understanding how to output the array, I am using it to illustrate what I am trying to achieve. I have also marked the relevant area where the call is being made.

My rainbow.component.html

<div><ul>
    <li *ngFor="let addsnote of addsnotes">{{addsnote}}</li>
</ul></div>

My firebase schema: enter image description here

My rainbow.component.ts

export class Rainbow implements OnInit{
private addsnotes: [];
private username: string;

ngOnInit(){
    var self = this;
    var user = firebase.auth().currentUser;
    var getUserInfo = firebase.database().ref('users/' + user.uid); 
    setTimeout(acquisition, 1000);

    function acquisition(){
    if (user){
        getUserInfo.once('value', function(snapshot){
                self.username = snapshot.val().username;
                self.addsnotes = snapshot.val().addnote; //incorrect
            });     
        }
    }
}

}
2
  • 1
    Any reason to not use AngularFire2? Even if you'd prefer to not use the library, it might be a good idea to browse the code since it handles the situation you're trying to handle and many more. Commented Sep 28, 2016 at 13:08
  • So using AngularFire2, would my array request look something like: export class Rainbow{ addsnotes: Observable addnote; constructor(af: AngularFire){this.addsnotes = af.list('/users')} } Commented Sep 28, 2016 at 13:13

2 Answers 2

1

If you want the AngularFire2 makes is easy to tune into the power of Observables so you can detect changes on the firebase end and auto-update your user notes. With AngularFire2, your solution would look more like this...

rainbow.component.html

<div>
  <ul>
    <li *ngFor="let addsnote of addsnotes$ | async">{{ addsnote.$value }}</li>
  </ul>
</div>

rainbow.component.ts

import { Injectable } from '@angular/core';
import { AngularFire } from 'angularfire2';
import { Observable } from 'rxjs/Observable';

export class RainbowComponent implements OnInit {
  private addsnotes$: Observable<string[]>;
  private username$: Observable<string>;

  constructor (
    private af: AngularFire
  ) {}

  ngOnInit () {
    let user = firebase.auth().currentUser,
        userNamePath = `users/${user.uid}/username`,
        notesPath = `users/${user.uid}/addnote`;

    this.username$ = this.af.database.object(userNamePath);
    this.addsnotes$ = this.af.database.list(notesPath);
  }
}

You will need the async pipe when using Observables in your template HTML. It will auto subscribe to extract the data. The big difference with this and the previous code is that anytime your addsnotes data changes, it will automatically show the changes on the HTML view. If you want to keep it like the previous code where you are limiting it to one call using once('value'), you can add a .take(1) to the end of this.af.database.list(notesPath) to just take the list values one time.

In addition, I would recommend adding a sub field to your notes such as order so that you can sort your list in an order that you want. You can find info on how to sort with AngularFire2 here.

Hope this helps.

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

4 Comments

I am not sure why but for each call for both users and addsnotes I get [object Object] instead of the value.
I forgot that your child nodes are primitive strings, so you will also need to add .$value to your template HTML to access the string data of each addsnote.
oh wow. that fixed it. How would I implement the same thing for an object observable? I have an <h4>{{username$ | async}}</h4> and changing it to {{username$.$value | async}} does not seem to do the trick. It returns [object Object].
The async pipe needs to come before the $value suffix. You can think of it as evaluating the firebase reference value then pulling the $value data out of it after it's synchronized. {{ (username$ | async)?.$value }}. The ? question mark makes sure that the username$ has been evaluated first before attempting to pull the $value data.
1

If you wanted to stick with Web Firebase API (no angularfire2), to get the addsnotes to work, it might look something like this.

ngOnInit () {
  let user = firebase.auth().currentUser;

  // Used ES6 arrow function instead, which is built into Typescript
  setTimeout(() => {
    // Make sure user and user.uid are defined
    if (user && user.uid) {
      let userRef = firebase.database().ref(`users/${user.uid}`);
      userRef.once('value', (snapshot) => {
        let userInfo = snapshot.val() || {};
        this.username = userInfo['username'];
        this.addsnotes = [];

        // Traverse each child for 'addnote'
        snapshot.child('addnote').forEach((childSnapshot) => {
          let addnoteKey = childSnapshot.key,
              addnote = childSnapshot.val();

          addnote['id'] = addnoteKey;  // Saving the reference key if you want reference it later
          self.addsnotes.push(addnote);
        });
      }
    }
  }, 1000);
}

1 Comment

I'm honestly not opposed to AngularFire 2. A lot of this is new to me so I don't necessarily know the right questions to ask.

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.