3

I am having some trouble using AngularFire / Firebase to get an individual record from a collection (and then, after I have it, $remove'ing it from the collection). I believe I'm following proper documentation located here: https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray

NOTE: a lot of documentation / blogs / answers I have found appear to use the deprecated $firebase service (with the $asArray method) - however, more recent docs identify that $firebaseArray is the correct service to use, FYI.

For some reason, even though I can accurately pull my polls collection, I cannot extract an individual element (although the official docs appear to have the same syntax I'm using).

Docs for $remove (https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray-removerecordorindex):

## official docs ##

$remove(recordOrIndex)
Remove a record from Firebase and from the local data. This method returns 
a promise that resolves after the record is deleted at the server. It will 
contain a Firebase reference to the deleted record. It accepts either an 
array index or a reference to an item that exists in the array.

var list = $firebaseArray(ref);
var item = list[2];
list.$remove(item).then(function(ref) {
  ref.key() === item.$id; // true
});

My code (see console.log's below):

.service('pollsData', function($firebaseArray){
    var fireRef = new Firebase('<-my-firebase-ref-url>');
    var polls = $firebaseArray(fireRef.child('polls'));
    var service = this;

    this.clearPolls = clearPolls;
    this.setInitialPolls = setInitialPolls;
    this.getPolls = getPolls;

    function clearPolls() {
      console.log("length: ", polls.length);  <--- I get a length of 0
      console.log(polls);  <-- I get a $firebaseArray object including the methods in the API docs
      console.log(polls[0], polls[1], polls[2]); <--- all 3 are undefined even though I can see several in the firebase data dashboard

      var poll = polls[1];
      console.log("poll?: ", poll);
      polls.$remove(poll);
    }

    function getPolls() {
      polls = polls || $firebaseArray(fireRef.child('polls'));
      return polls;  <-- I can successfully ng-repeat over this returned selection in the template
    }

    function setInitialPolls() {
      service.clearPolls();
      polls.$add({
        one: {
          name: "fantastic pollllllls",
          selection_one: {
            name: "pizza",
            count: 0
          },
          selection_two: {
            name: "fries",
            count: 0
          }
        },
        two: {
          name: "mediocre poll",
          selection_one: {
            name: "blue",
            count: 0
          },
          selection_two: {
            name: "green",
            count: 0
          }
        }
      });
    }

    setInitialPolls();
});

Any insights as to why the brackets [] notation to pull out a record from the $firebaseArray would not work as expected per the AngularFire documentation?

Updated: the responses provided were still helpful since this appeared to be in conflict with my understanding of the newer documentation for $firebaseArray and the example given for the $remove section in the API docs. Understand this is still fundamentally an async concern, but since the $firebase service was deprecated and I was referencing the updated docs, this updated Question/Solution felt necessary.

DigV
  • 75
  • 2
  • 10
  • After tinkering around some more, it does appear to be an async issue. That said, I'm not entirely sure *when/where* I would be able to resolve after firebase returns, especially since (per the documentation I paste above) the docs don't indicate the async nature here. – DigV Mar 12 '15 at 00:09
  • 1
    Check out [`$loaded()`](https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray-loaded) – sbolel Mar 12 '15 at 03:19
  • possible duplicate of [Asynchronous access to an array in Firebase](http://stackoverflow.com/questions/27049342/asynchronous-access-to-an-array-in-firebase) – Kato Mar 12 '15 at 19:32
  • 1
    @SinanBolel is correct here, but it may not be immediately obvious why. See the duplicate link for detailed information. Essentially, you've made an asynchronous request to the server for data, but then immediately tried to utilize said data without waiting for it to load. – Kato Mar 12 '15 at 19:33
  • Thanks for the expanded answer @Kato – sbolel Mar 12 '15 at 19:34
  • Got it, so I should fire my init function upon $loaded being resolved. Makes sense. Thank you! – DigV Mar 12 '15 at 22:54

1 Answers1

2

There are three methods to retrieve a record out of the $firebaseArray object.

  1. $getRecord(key)
  2. $keyAt(recordOrIndex)
  3. $indexFor(key)

I would look more closely at the documentation on each of these, but from what you have described, you probably want to use $keyAt. Keep in mind, though, that $firebaseArray is not a strict array, and the available methods provide more options/flexibility than what you would be used to having in 'just an array'.

Also, as mentioned in the comments, you want to work inside of a promise method to handle the three way data bind for you.

var arrayRef = new Firebase(firebase_location).child(child_location);
var theList = $firebase(arrayRef).$asArray();
theList.$loaded(function (list) {
  var x = list.$keyAt(list[target_position]);

  //use other methods for the $firebaseArray object
});
getglad
  • 2,035
  • 1
  • 20
  • 39
  • `$keyAt()` isn't necessary here. The record or its `$id` can be passed into $remove. This also isn't a "three-way data binding" as defined in the AngularFire docs. That is established using `$bindTo` and has a different behavior. This is more of a one-way data binding from Firebase to local JavaScript variables. Ultimately, your solution, utilizing `$loaded` is the correct answer here, but I'll refrain from upvoting this until the rest is technically correct. – Kato Mar 12 '15 at 19:36