Easily sync data between your mobile and web apps using Firebase and Trigger.io
One of the great things about being able to build mobile apps using JavaScript is that you can use fantastic new libraries and services designed for the web.
Here, we’ll show you how can use Firebase to easily sync data between your web and mobile app, both built on Trigger.io. We’re psyched to partner with them: you can use the two products together right now and we’ll announce more integrations and examples in the near future. Check out their blog post also.
Before we get started, you can see the synching in action in this short screencast:
As you can see Firebase is like Dropbox for JavaScript objects, and makes the syncing part dead-simple without you having to worry about creating your own server-side stack or network connectivity / cacheing on the client-side.
In this post we’ll show you how to:
Integrate Firebase into your Trigger.io mobile app
Update your Backbone.js models based on changes
Branch your code to give different views of the data on mobile and web
Build and test your codebase for both mobile, and the web using Trigger.io’s build to web feature
To show all this, we’ll use the wine app that I’ve been working on that also includes native UI components – I blogged about that a couple of weeks back. You can see the code for that app on github here, so you can build it for yourself to see the Firebase integration in action.
Integrate and initialize Firebase
You’ll need to sign-up with Firebase on their website and create a namespace for your app – ‘winebox’ for our example. Once you’ve done that, integrating Firebase is a simple as saving their firebase.js library and referencing from the index.html of your Trigger.io app along with other libraries you’ll want to use:
Simple as that! Now as part of our initialization code in wine.js we setup the Firebase objects we need and our Backbone collection:
forge.logging.log(‘… Start initStorage’);
//Initialize Firebase
wine.publicFirebase = new Firebase(‘http://gamma.firebase.com/winebox/public’);
wine.userFirebase = new Firebase(‘http://gamma.firebase.com/winebox/’+wine.user);
wine.photos = new wine.collections.Photos();
In models.js we defined wine.collections.Photos() to be our Backbone collection.
And we’ve created two Firebase objects – one for our public stream and one for the user-specific stream. The Wine Box app is designed to let you take photos of wine labels at restaurants so you can rate the wine you’ve drunk. Within the mobile app you’ll see a list of the wine you’ve personally rated, while there’ll be a public list on the web.
To get the idea of the app, try it for yourself by installing it from the App Store or Google Play.
For this purpose we’ll denormalize the data, so when we add new models, we’ll add them to both the public and user-specific object. Here’s what the winebox object will look like in Firebase’s graphical debugger with two users have added a wine object each:
Listen and react to changes in data
Next we need to initialize our Backbone model so we can show the right list of wine photos and ratings on mobile and web, and listen for changes so the public list on the web updates automatically when a new rating is made in the mobile app.
To do that, we first need to branch our code depending on whether we’re on mobile or the web. Doing that is easy with the forge.is API:
if (forge.is.web()) {
} else {
//We must be on mobile
}
In the mobile branch, we use Firebase’s once method to read the data snapshot for the user:
wine.userFirebase.once(‘value’, function(snapshot) {
forge.logging.log(‘firebase.once triggered’);
$(‘#loading’).remove();
snapshot.forEach(function(photo) {
var photo_model = wine.addPhotoFromFirebase(photo);
if (!photo_model.has(‘dataurl’)) {
wine.setDataUrl(photo_model.get(‘url’), photo_model.get(‘timestamp’));
}
});
});
For every object in the user-specific Firebase object, we call our own ‘addPhotoFromFirebase’ method in wine.js to populate our Backbone model.
The way we show the photo on the web is to convert it into a data url on the mobile device and then add it to the Firebase model – in case we didn’t manage to complete that process when the photo was originally taken, you can see us check for, and if necessary, populate the ‘dataurl’ attribute with a call to our ‘setDataUrl’ method in wine.js.
To complete the picture for the mobile app, we need to make sure that if a wine rating is deleted within the app, the appropriate Firebase model is updated so the change can be replicated elsewhere:
wine.photos.on(“remove”, function(photo) {
state.get(‘list’).remove(photo.get(‘timestamp’));
wine.publicFirebase.child(photo.get(‘timestamp’)).remove();
wine.userFirebase.child(photo.get(‘timestamp’)).remove();
});
In the web branch, we not only want to populate the public list of wine photos and ratings, but also listen for updates so the list on the web can change dynamically according to user actions in the mobile app. For that, we use Firebase’s on method:
wine.publicFirebase.on(‘child_added’, function(photo) {
forge.logging.log(‘firebase on child_added triggered’);
$(‘#loading’).remove();
wine.addPhotoFromFirebase(photo);
});
wine.publicFirebase.on(‘child_removed’, function(photo) {
forge.logging.log(‘firebase on child_removed triggered’);
forge.logging.log(‘removing from list with timestamp: ‘+photo.val().timestamp);
state.get(‘list’).remove(photo.val().timestamp);
});
wine.publicFirebase.on(‘child_changed’, function(photo) {
forge.logging.log(‘firebase on child_changed triggered’);
forge.logging.log(‘updating image with timestamp: ‘+photo.val().timestamp);
forge.logging.log(‘using dataurl: ‘+photo.val().dataurl);
wine.photos.where({timestamp: photo.val().timestamp})[0].set(“dataurl”, photo.val().dataurl);
state.get(‘list’).addImage(photo.val());
});
This code ensures that whenever an item is added, deleted or updated within the mobile app, the change is replicated in the model that we use for our list of wine photos and ratings on the web. It’s as simple as that.
Build for mobile and web
Ok, so how do we try this out for mobile and web. Trigger.io makes that dead simple. With our toolkit installed you can click a couple of links to build and run this code as both a web app, and as a native iPhone app in the emulator or on device – in the latter case you don’t even need a Mac to test the iPhone app.
Here’s how it looks. You can also watch the short screencast at the top to see the app, and data synching in action.
That’s it
We hope this has inspired you to build mobile and web apps with Trigger.io, using Firebase to simply synch the data. Just download the toolkit to get started!
Any problems at any point? Ask the community on StackOverflow or contact [email protected].