paivaric / firebase-resource

Angular wrapper for Firebase in the style of ng-resource and active-record

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

firebase-resource

Angular wrapper for Firebase in the style of ng-resource and active-record.

this is a very early release so please report any strangeness or suggestions

Features

  • Encapsulates Firebase to prevent dependency in controllers. Designed to be a drop-in replacement for ng-resource.
  • Handles associations using foreign-key references, following the tactics outlined here
  • Automatically timestamps objects when saving and updating
  • Handles pagination
  • Stores resources in memory to prevent having to request data from Firebase as often
  • Allows assigning of local attributes. Any attribute with a leading underscore will not be persisted to Firebase

planned features

  • Store resources in localStorage or indexedDB
  • Advanced querying options including searching
  • Remove reliance on Firebase and make it compatible with any realtime backend

####Getting Started Include firebase-resource.js in your index.html file. Suggest creating a services folder.

<script src="/services/firebase_resource.js"></script>

firebase-resource requires a firebase module be injected into it. So define one thusly somewhere in your project:

angular.module('exampleFirebase', []).
    value('firebase', (new Firebase('https://example.firebaseio.com/')));

firebase-resource relies on the existence of a safeApply method on $rootScope. In one of your controllers, define safeApply:

$rootScope.safeApply = function(fn) {
  var phase = this.$root.$$phase;
  if(phase == '$apply' || phase == '$digest') {
    if(fn && (typeof(fn) === 'function')) {
      fn();
    }
  } else {
    this.$apply(fn);
  }
}; 

firebase-resource assumes you are defining your models as separate modules, much like ng-resource assumes. Inject firebase-resource into your where you might otherwise inject ng-resource.

angular.module('Post', ['firebaseResource']).
  factory('Post', function (firebaseResource) {

  });

Create a resource using the resource factory defined in firebase-resource (again, like you would using ng-resource).

angular.module('Post', ['firebaseResource']).
  factory('Post', function (firebaseResource) {
  
    var Post = firebaseResource(
      {
        path: 'posts'
      }
    );
    
    return Post;
    
  });

Define options for the resource. These include

  • path - this is the actual Firebase path of the resource in question.
  • hasMany - an array of associations. These are other models defined as firebase-resources.
  • perPage - how many results are retrieved per page.
  • limit - used to limit number of results coming back from a query. Redundant when using pagination.
  • belongsTo - determines whether a resource is defined within the context of a parent resource.

Inject the resource into controllers where needed

angular.module('PostsCtrl', []).
  controller('PostsCtrl', function($scope, Post) {
    
    $scope.posts = Post.query({page: 1});
    
  });

Defining and using associations:

angular.module('User', ['firebaseResource']).
  factory('User', function (firebaseResource) {
  
    var User = firebaseResource(
      {
        path: 'users',
        hasMany: ['Post']
      }
    );
    
    return User;
    
  });
  
angular.module('Post', ['firebaseResource']).
  factory('Post', function (firebaseResource) {
  
    var Post = firebaseResource(
      {
        path: 'posts',
        belongsTo: true,
        perPage: 10
      }
    );
    
    return Post;
    
  });
  
angular.module('PostsCtrl', []).
  controller('PostsCtrl', function($scope, Post, User) {
    
    User.query() // query() sets up the proper Firebase listeners for the model. Does not return the actual objects.
    $scope.user = User.all()[0]; // all() returns the actual objects pulled down from Firebase for this model
    $scope.user.posts().query({page: 1});
    $scope.posts = $scope.user.posts().all();
    
  });

Creating content in context of an assocation:

var post = user.posts().new({content: 'hello world!'});
post.save().
then(function() {
  // do something
 })

Define lifecycle callbacks within the model definition:

angular.module('Post', ['firebaseResource']).
  factory('Post', function (firebaseResource) {
  
    var Post = firebaseResource(
      {
        path: 'posts',
      }
    );
    
    Post.prototype.init = function(error) {
        // happens when model is instantiated from Firebase data
    };
    
    Post.prototype.afterCreate = function(error) {
        // happens only the first time an object is added to Firebase
    };
    
    Post.prototype.beforeSave = function(error) {
        // happens immediately before saving data to Firebase
    };
    
    Post.prototype.afterSave = function(error) {
        // happens after data is written to Firebase
    };
    
    return Post;
    
  });

Instance Methods:

  • save() // saves resource to Firebase and returns a promise that is resolved upon success
  • delete() // delets resource from local stores and Firebase. Returns a promise that is resolved on success
  • getTimestamp(attr) // returns a javascript date of the provided timestamp. Accepts "created_at" or "updated_at"

Class Methods:

  • getName() // returns the result of the firebase name() function
  • getPath() // returns the result of the firebase path() function
  • clearAll() // clears all resources out of memory
  • find(id) // returns a resource from memory for a given id, but will not go to Firebase for it
  • findAsync(id) // returns a resource from memory if available or Firebase if not. Returns a promise.
  • all() // returns all resources in memory. options include limit and parent.
  • query() // establishes firebase listeners for the resource given a set of options and stores results in resource stores.

About

Angular wrapper for Firebase in the style of ng-resource and active-record