Ben Jensen
Ben Jensen

Reputation: 1

AngularFire, extended $firebaseArray save errors with 'Invalid key $id (cannot contain .$[]#)'

When extending $firebaseArray I get the error 'invalid key $id (cannot contain .$[]#)'

The issue is with the $id property on the book object. When calling $save on the array and passing the modified book in, the factory doesn't recognize $id as the id field like it normally would prior to extending.

Html

<ul>
    <li ng-repeat="book in bookList"> <a href="#" ng-click="loadBook(book)">{{book.$id}}: {{book.date|date:"medium"}}</a> 
        <button ng-click="setDate(book)">set date</button>
    </li>
</ul>
<pre>{{book|json}}</pre>

Javascript

// reference to our Firebase instance
var fb = new Firebase('YourUrl');

function Book(snap) {
    // records in synchronized arrays must have a $id property
    this.$id = snap.key();
    this.update(snap);
}

Book.prototype.update = function (snap) {
    angular.extend(this, snap.val());
    // convert json dates to Date objects
    this.date = new Date(this.date||0);
    this.$priority = snap.getPriority();
};

Book.prototype.toJSON = function() {
    return angular.extend({}, this, {
        // revert Date objects to json data
        date: this.date.getTime()
    });
};

var app = angular.module('app', ['firebase']);
app.controller('ctrl', function ($scope, bookFactory) {    
    // create a synchronized array with a customized version 
    // of $FirebaseArray

    $scope.bookList = new bookFactory(fb);


    // loads a single record for display
    $scope.book = "Click on a book id";
    $scope.loadBook = function (book) {
        $scope.book = book;
    };

    // changes the date on a book record, note that we're working
    // with Date objects here
    $scope.setDate = function(book) {
        book.date = new Date();
        $scope.bookList.$save(book);
    };
});

app.factory('bookFactory', function ($firebaseArray, $firebaseUtils) {
    return $firebaseArray.$extend({
        // override $$added to return a Book object
        $$added: function (snap, prevChild) {
            return new Book(snap);
        },

        // override $$updated to update the book object
        $$updated: function (snap) {
          var rec = this.$getRecord(snap.name());
          if(angular.isObject(rec) ) {
            book.update(snap);
          }
        }
    });
});

Made a fiddle showing the error, just press 'Set Date' on any of the books. https://jsfiddle.net/jensenben/h98mjsoz/

This can be remedied if make the book object use id instead of $id and add a $$getKey method to the $extend call to tell it what field has the id in it, but I'd prefer to stick with the traditional $id field that I use when not extending a $firebaseArray.

function Book(snap) {
    // records in synchronized arrays must have a $id property
    this.id = snap.key();
    this.update(snap);
}

return $firebaseArray.$extend({
    $$getKey: function(rec) {
        return rec.id;
    },
...

Upvotes: 0

Views: 480

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599061

There's a bit much going on, so I'm not sure if this is your problem. But to get rid of the error, convert the $firebaseObject() to a regular JSON object when saving:

$scope.setDate = function(book) {
    book.date = new Date();
    $scope.bookList.$save(book.toJSON());
};

Note that the CSS and most of the JavaScript code are irrelevant to the problem.

Upvotes: 1

Related Questions