Joining Paths Asynchronously
Join multiple paths asynchronously on a user ID in Firebase
by Kato Richardson
HTML
<script src="http://static.firebase.com/v0/firebase.js"></script>
<h3>Joining Paths Asynchronously</h3>
<div class="left">
<h5>Select a user</h5>
<ul></ul>
</div>
<div class="right">
<h5>Merged Record</h5>
<pre>Pick a user...</pre>
</div>
CSS
div {
float: left;
}
div.left { width: 30%; }
div.right { width: 69%; }
pre {
padding: 20px;
font-size: 20px;
border-radius: 15px;
background-color: #fafafa;
border: 1px solid #999;
font-family:'Courier New', 'Courier', monospaced;
}
h3 {
clear: both;
padding-top: 20px;
}
JavaScript
var fb = new Firebase("https://examples-sql-queries.firebaseio.com/");
listUsers();
function joinPaths(id, paths, callback) {
var returnCount = 0;
var expectedCount = paths.length;
var mergedObject = {};
paths.forEach(function (p) {
fb.child(p + '/' + id).once('value',
// success
function (snap) {
// add it to the merged data
extend(mergedObject, snap.val());
// when all paths have resolved, we invoke
// the callback (jQuery.when would be handy here)
if (++returnCount === expectedCount) {
callback(null, mergedObject);
}
},
// error
function (error) {
returnCount = expectedCount + 1; // abort counters
callback(error, null);
}
);
});
}
function loadUser(userId) {
joinPaths(userId, ['user', 'media', 'interests'], show);
}
function show(error, obj) {
$('pre').text(error || JSON.stringify(obj, null, 2));
}
function listUsers() {
var $ul = $('ul');
fb.child('user').on('child_added', function (snap) {
$('<li></li>').appendTo($ul).append( buildLink(snap) );
});
}
function buildLink(snap) {
return $('<a href="#"></a>')
.attr('data-id', snap.name())
.text(snap.val().name)
.on('click', function(e) {
e.preventDefault();
loadUser($(this).attr('data-id'));
});
}
function extend(base) {
var parts = Array.prototype.slice.call(arguments, 1);
parts.forEach(function (p) {
if (p && typeof (p) === 'object') {
for (var k in p) {
if (p.hasOwnProperty(k)) {
base[k] = p[k];
}
}
}
});
return base;
}