0

Within Firebase, I have a list of 'ideas.' If a user presses a button associated with the idea, I'd like a value to be appended to that idea under an attribute called 'newValue.'

For example, the below html, uses ng-repeat to show the array of ideas and creates an associated button called 'Append Value.' I want a new value to be appended to the idea's attribute called 'newValue' every time a user presses 'Append Value.'

<body ng-controller="ctrl">
  <table>
  <tr class="item" ng-repeat="(id,item) in ideas">
    <td>{{item.idea}}</td>
    <td><input ng-model="newValue"></td>
    <td><button ng-click="ValueAppend(id,newValue)">Append Value</button></td>
    </tr>
  </table>
</body>

Below is my attempt to create this function.

var app = angular.module("app", ["firebase"]);

app.factory("Ideas", ["$firebase", function($firebase) {
  var Ref = new Firebase('https://crowdfluttr.firebaseio.com/');
  var childRef = Ref.child('ideas');
  return $firebase(childRef).$asArray();
}]);

app.controller("ctrl", ["$scope","Ideas", function($scope,Ideas) {
  $scope.ideas = Ideas;
  $scope.idea = "";

  $scope.ValueAppend = function (id,newValue) {   
    var URL = "https://crowdfluttr.firebaseio.com/ideas/" + id + "newValue";
    var IdeaRef = new Firebase(URL);
    var IdeaData = $firebase(IdeaRef);
    $scope.IdeaAttributes = IdeaData.$asArray();
    $scope.IdeaAttributes.$add({
        newValue: newValue,
        timestamp: Date.now()
      });
  };

}]);

See my codepen for my working example: http://codepen.io/chriscruz/pen/PwZWKG

More Notes: I understnad that AngularFire provides $add() and $save() to modify this array, but how could I use these methods so that I can add a new 'string' under an item in an array.

Chris
  • 5,444
  • 16
  • 63
  • 119
  • The codepen is giving "ReferenceError: $firebase is not defined", because you're failing to inject it into the controller. After fixing that it seems to work, but you might be missing a slash before newValue in this URL: `var URL = "https://crowdfluttr.firebaseio.com/ideas/" + id + "newValue";`. – Frank van Puffelen Dec 06 '14 at 22:58

1 Answers1

3

I'm not sure if these are your problems, but they are two typoes of mistakes in the code above and the codepen: typos and conceptual.

Typos

You forgot to inject $firebase into the controller, which leads to:

"ReferenceError: $firebase is not defined"

Solution is simply of course:

app.controller("ctrl", ["$scope","Ideas", "$firebase",  function($scope,Ideas,$firebase) {

In addition you seem to be missing a slash before newValue, which means that you're trying to create a new idea instead of adding the value to an existing one. Solution is simple again, add a slash before newIdea as in:

    var URL = "https://crowdfluttr.firebaseio.com/ideas/" + id + "/newValue";

If you find yourself making this mistake more often, you might be better server by the child function. Although it typically is a bit more code, it lends itself less to this typo of typo. Creating the ref to the newValue node becomes:

    var URL = "https://crowdfluttr.firebaseio.com/ideas/";
    var IdeaRef = new Firebase(URL).child(id).child("newValue");

Conceptual

With those trivial typos out of the way, we can focus on the real problem: which is easiest to see if you console.log the URL that you generate:

https://crowdfluttr.firebaseio.com/ideas/0/newValue

Yet if you look up the same data in the Firebase forge (by going to https://crowdfluttr.firebaseio.com/ideas/ in your browser), you'll see that the correct URL is:

https://crowdfluttr.firebaseio.com/ideas/-JbSSmv_rJufUKukdZ5c/newValue

That '0' that you're using comes from the id and it is the index of the idea in the AngularJS array. But it is not the key that Firebase uses for this idea. When AngularFire loads your data with $asArray it maps the Firebase keys to Angular indexes. We need to perform the reverse operation to write the new value to the idea: we need to map the array index (in id) back to the Firebase key. For that you can call [$keyAt(id)][1]. Since you keep the array of ideas in Ideas, it is simply:

    var URL = "https://crowdfluttr.firebaseio.com/ideas/";
    var IdeaRef = new Firebase(URL).child(Ideas.$keyAt(id)).child("newValue");

So the controller now becomes:

app.controller("ctrl", ["$scope","Ideas", function($scope,Ideas) {
  $scope.ideas = Ideas;
  $scope.idea = "";

  $scope.ValueAppend = function (id,newValue) {   
    var URL = "https://crowdfluttr.firebaseio.com/ideas/";
    var IdeaRef = new Firebase(URL).child(Ideas.$keyAt(id)).child("newValue");
    var IdeaData = $firebase(IdeaRef);
    $scope.IdeaAttributes = IdeaData.$asArray();
    $scope.IdeaAttributes.$add({
        newValue: newValue,
        timestamp: Date.now()
      });
  };
}]);

I quickly gave it a spin in your codepen and this seems to work.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807