AngularJS and Firebase
Written by Preston Lamb
Posted on Jun 7, 2014
I recently found a pretty cool new piece of web development technology: Firebase. You can read more on their site, but basically Firebase is a way to instantly sync data across devices. If you make a change on your computer, it instantly shows up on your phone. They take care of all the details; you just add, update, or delete and you're good to go.
The first thing I did was to take the AngularFire Seed Project that Firebase developed and added a few things that I like (Bootstrap mostly). I now have that project right here. Make sure you're on the angular-firebase branch. To get this going, clone the project, change into the directory, run
npm install followed by
npm start. With that you'll have a local server running and you'll be ready to go.
A couple things to be aware of:
- To do this, you should sign up with Firebase before getting into this. They give you a free account for development. If you are going to deploy, you can look at those options.
- In the `app/js/config.js` file in the project, you need to set the constant `FBURL` to match the URL for your Firebase app. That's used throughout the project, and if you don't have the correct URL you won't get very far.
Okay, so now we're all set up and ready to go. I decided to go back to an old project that I'd done while in school. My sister-in-law likes to cook, so when I needed an idea for an Android App Development class final project, she suggested I make a recipe book app. I figured this would be a perfect time to revisit that project and make it into a web app that also synced across devices. It's a good practice and gives several good use cases to work on.
Before doing anything with Firebase, I got the AngularJS part of the app to work. The following image is the page where you can add a recipe. AngularJS makes it really easy to add and delete items from a list. Also, with Angular UI Sortable, it was very easy to be able to reorder the ingredients or the directions. In addition, after adding each ingredient or direction, you can edit it directly in its spot in the list.
After setting that up, it was time to start saving the data to Firebase. Because of the Firebase's angularFire seed project, that wasn't too hard. All I had to do was:
var path = '/user-data/' + $scope.curUser.uid + '/recipes/' + $scope.recipeType; $scope.recipes = syncDataLimit(path, 10); var recipe = $scope.newRecipe; recipe.ingredients = $scope.ingredients; recipe.directions = $scope.directions; recipe.name = $scope.name; $scope.recipes.$add(recipe);
In a nutshell, what happens there is the
syncDataLimit(path, 10) part is a service that comes with the seed. It takes a specified path and limits the number of returned items stored at that path in Firebase. With that returned object, you can add recipes at that position in Firebase. So, as can be seen, I make a new object,
var recipe = $scope.newRecipe;, and set its attributes to be the information that the user entered. Then, I just have to save that recipe by doing
$scope.recipes.$add(recipe);. Immediately that data is available to me on any device I am looking at.
One of the hard parts for me on this project was learning how to organize my data in Firebase. Coming from a SQL world, I wanted to save a recipe and attach the
userId of whoever created it. I tried that at first, but was unable to then query Firebase with the equivalent
SELECT * FROM RECIPES WHERE userId = aNumber. I was stuck for a few days. Then, when I dug back in, I found this article. It talks about the proper way to order your data, since querying like my previous example doesn't work. So I reworked the way I was saving data. Now, I was saving data in
user-data/:userId/recipes/:recipeType. This allowed me to just get the current user's ID, plug that into my path that I used above, get the recipe type from the radio buttons, and save it. Now, I can get a user's recipes by following that pattern, and I'll only ever get the current user's data.
$scope.appetizerType = 'appetizer'; var appetizers = basePath + $scope.appetizerType; $scope.recipeApps = syncData(appetizers, 10);
The above image shows the simplified version of how to get data back from Firebase for the list of recipes a user has created. In this case, I'm getting the recipes from Firebase that have a type of
appetizer. That will allow me to get all the appetizers back from Firebase and list them for a user to see.
Deleting in Firebase is really simple as well. All you need is the path to where that item sits. So, for example,
'user-data/:userId/recipes/:recipeType/:recipeId'. Then, use
$firebase, which is loaded in as part of the angularfire module and in the project, to make a Firebase reference to that recipe. Then:
$scope.recipeReference.$remove();. Updates are done in this same way, but with
var deletePath = new Firebase(FBURL + basePath + recipeType + '/' + id); var deleteRef = $firebase(deletePath); deleteRef.$remove();
After working with Firebase, it is one of the cooler technologies I've seen. The ability to have devices sync data automatically and instantly without having to write any backend code on your own saves a lot of time. And with the ability to have Firebase host your /static files for you, it makes it simple to deploy as well. For me, it's making a little old recipe book app much more user friendly by letting them use it on whatever device they choose.