Last active
April 6, 2016 07:47
-
-
Save webcss/5d59d15fb07204c7d732 to your computer and use it in GitHub Desktop.
Firebase with mithril. Note that the gists provided here are deprecated and will soon be removed. You should use firebaseMixin (https://gist.github.com/webcss/e4aaa7d95342d107e1ce) instead.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Dinosaurs = { | |
model: function() { | |
// return a firebase reference to our database | |
return new Firebase('https://dinosaur-facts.firebaseio.com'); | |
}, | |
controller: function() { | |
var ref = Dinosaurs.model(); | |
this.facts = mithrilFire(ref.orderByChild('height')); | |
}, | |
view: function(ctrl) { | |
return [ | |
m('h1', 'Dinosaur facts'), | |
m('ul', | |
ctrl.facts.map(function(dino, id){ | |
return m('li', [ | |
m('h3', id + ' was ' + dino.height ' meters tall'), | |
m('input', { onchange: ctrl.facts.withValue('value', id, 'height'), value: dino.height }) | |
]); | |
}) | |
) | |
]; | |
} | |
}; | |
m.module(document.body, Dinosaurs); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*************************************************************** | |
* MithrilFire - m.firebase | |
* version 1.0.3 | |
* make firebase play nice with Mithril | |
* param @pathRef string/object - a firebase url/reference to listen to | |
* return object - firebase object accessor | |
================================================================ | |
This is a lightweight solution to handle firebase data with | |
mithril. It takes a firebase reference and returns an object which | |
provides access to the returned data in various ways. | |
Basic CRUD methods allow for add, update, remove and DataBinding | |
of snapshot values. | |
****************************************************************/ | |
m.firebase = function(pathRef, options) { | |
var ref = (typeof pathRef === 'string') ? new Firebase(m.firebase.rootPath + '/' + pathRef): pathRef; | |
function typeOf(o) { | |
return Object.prototype.toString.call(o).slice(8, -1).toLowerCase(); | |
} | |
function findIndex(arr, key) { | |
for(var i = 0, l = arr.length; i < l; i++) { | |
if(arr[i]._id === key) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
// using the Firebase API's prevChild behavior, we | |
// place each element in the list after it's prev | |
// sibling or, if prevChild is null, at the beginning | |
function positionAfter(arr, prevChild) { | |
var idx; | |
if (prevChild === null) { | |
return 0; | |
} else { | |
idx = findIndex(arr, prevChild); | |
return (idx === -1) ? arr.length: idx + 1; | |
} | |
} | |
function __onadded(arr, deferred) { | |
return function(snapshot, prevChild) { | |
var pos, data, | |
idx = findIndex(arr, snapshot.key()); | |
if (idx < 0) { | |
data = snapshot.val(); | |
if(typeOf(data) !== 'object' || !data) { | |
data = { '.value': data }; | |
} | |
data._id = snapshot.key(); | |
pos = positionAfter(arr, prevChild); | |
arr.splice(pos, 0, data); | |
deferred.resolve(arr); | |
m.redraw(); | |
} | |
}; | |
} | |
function __onchanged(arr, deferred) { | |
return function(snapshot) { | |
var data, | |
idx = findIndex(arr, snapshot.key()); | |
if (idx > -1) { | |
data = snapshot.val(); | |
if(typeOf(data) !== 'object' || !data) { | |
data = { '.value': data }; | |
} | |
data._id = snapshot.key(); | |
arr[idx] = data; | |
deferred.resolve(arr); | |
m.redraw(); | |
} | |
}; | |
} | |
function __onremoved(arr, deferred) { | |
return function(snapshot) { | |
var idx = findIndex(arr, snapshot.key()); | |
if (idx > -1) { | |
arr.splice(idx, 1); | |
deferred.resolve(arr); | |
m.redraw(); | |
} | |
}; | |
} | |
function __onmoved(arr, deferred) { | |
return function(snapshot, prevChild) { | |
var data, newpos, | |
idx = findIndex(arr, snapshot.key()); | |
if (idx > -1) { | |
data = arr.splice(idx, 1)[0]; | |
newpos = positionAfter(arr, prevChild); | |
arr.splice(newpos, 0, data); | |
deferred.resolve(arr); | |
m.redraw(); | |
} | |
}; | |
} | |
options = options || {}; | |
if (options.orderBy) { | |
switch(options.orderBy.toLowerCase()) { | |
case '.key': ref = ref.orderByKey(); break; | |
case '.value': ref = ref.orderByValue(); break; | |
case '.priority': ref = ref.orderByPriority(); break; | |
default: | |
ref = ref.orderByChild(options.orderBy); | |
} | |
if (options.startAt) { | |
ref = ref.startAt(options.startAt); | |
} | |
if (options.endAt) { | |
ref = ref.endAt(options.endAt); | |
} | |
if (options.equalTo) { | |
ref = ref.equalTo(options.equalTo); | |
} | |
} | |
return { | |
/** | |
* asArray | |
* param @options object - define optional params like ordering, range queries | |
* return mithril promise resolving to array for the given firebase location | |
* | |
* applies listeners for live data changes | |
*/ | |
asArray: function(options) { | |
var d = m.deferred(), | |
out = []; | |
ref.once('value', function(snapshot) { | |
m.startComputation(); | |
snapshot.forEach(function(record) { | |
var data = record.val(); | |
if(typeOf(data) !== 'object' || !data) { | |
data = { '.value': data }; | |
} | |
data._id = record.key(); | |
out.push(data); | |
}); | |
d.resolve(out); | |
m.endComputation(); | |
// m.redraw(); | |
// make sure we unbind any previously added listeners to avoid multiplication of lissteners | |
ref.off(); | |
// listen for changes | |
ref.on('child_added', __onadded(out, d)); | |
ref.on('child_changed', __onchanged(out, d)); | |
ref.on('child_removed', __onremoved(out, d)); | |
ref.on('child_moved', __onmoved(out, d)); | |
}); | |
return d.promise; | |
}, | |
/** | |
* asObject | |
* param @once bool - define wether or not to execute only once | |
* return mithril promise resolving to an object with the data at the given firebase location | |
* | |
* when once is false, updates live data changes | |
*/ | |
asObject: function(once) { | |
var d = m.deferred(); | |
// make sure we unbind any previously added listeners to avoid multiplication of lissteners | |
if(once) ref.off(); | |
ref[once?'once':'on']('value', function(snapshot) { | |
d.resolve(snapshot.val()); | |
m.redraw(); | |
}); | |
return d.promise; | |
}, | |
/** | |
* selectedKeys | |
* param @keys array - keys for which to retrieve data | |
* return mithril promise resolving to an array with the data at the given firebase locations | |
* | |
* resolve master-detail where master holds an array of detail keys | |
*/ | |
selectedKeys: function(keys) { | |
var d = m.deferred(), | |
out = []; | |
keys.forEach(function(key) { | |
m.startComputation(); | |
ref.child(key).once('value', function(snapshot) { | |
var data = snapshot.val(); | |
if (data) { | |
if(typeOf(data) !== 'object' || !data) { | |
data = { '.value': data }; | |
} | |
data._id = snapshot.key(); | |
out.push(data); | |
d.resolve(out); | |
// m.redraw(); | |
} else { | |
console.info('value not found at: ' + ref.path.toString() + '/' + key); | |
} | |
m.endComputation(); | |
}); | |
}); | |
// make sure we unbind any previously added listeners to avoid multiplication of lissteners | |
ref.off(); | |
// only listen for changed or removed children | |
// ref.on('child_added', __onadded(out, d)); | |
ref.on('child_changed', __onchanged(out, d)); | |
ref.on('child_removed', __onremoved(out, d)); | |
ref.on('child_moved', __onmoved(out, d)); | |
return d.promise; | |
}, | |
/** | |
* bindHelper | |
* param @key string - key index | |
* param @property string - key property to bind to | |
* param @attr string - HTML attribute to bind to | |
* return mithril withAttr function | |
* | |
*/ | |
bindHelper: function(key, childProp, attr) { | |
return m.withAttr(attr, function(value) { | |
ref.child(key).child(childProp).set(value); | |
}); | |
}, | |
/** | |
* unbind | |
* remove any listeners applied | |
* | |
*/ | |
unbind: function() { | |
ref.off(); | |
}, | |
/** | |
* add | |
* param @value any - value to add to this location | |
* param @priority any - optional priority for this value | |
* return key string - the firebasekey for the newly added value | |
* | |
*/ | |
add: function(value, priority) { | |
var newRef = ref.push(value); | |
if(priority) { | |
newRef.setPriority(priority); | |
} | |
return newRef.key(); | |
}, | |
/** | |
* update | |
* param @key string - the key for the location to update | |
* param @newData any - the update value | |
* param @priority any - optional priority for this value | |
* | |
*/ | |
update: function(key, newData, priority) { | |
// make sure we don't accidentally push our _id/key prop | |
if(newData.hasOwnProperty('_id')) { | |
delete newData._id; | |
} | |
if(newData.hasOwnProperty('.value')){ | |
newData = newData['.value']; | |
} | |
if (priority) { | |
ref.child(key).setWithPriority(newData, priority); | |
} else { | |
ref.child(key).set(newData); | |
} | |
}, | |
/** | |
* updatePriority | |
* param @key string - the key for the location | |
* param @priority any - optional priority for this location | |
* | |
*/ | |
updatePriority: function(key, priority) { | |
ref.child(key).setPriority(priority); | |
}, | |
/** | |
* remove | |
* param @key string - the key for the location to remove | |
* | |
*/ | |
remove: function(key) { | |
ref.child(key).remove(); | |
} | |
}; | |
}; | |
/** | |
* m.firebase.rootPath | |
* rootPath to your data | |
* | |
*/ | |
m.firebase.rootPath = ''; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*************************************************************** | |
* MithrilFire | |
* version 0.7 | |
* make firebase play nice with Mithril | |
* param @ref object - a firebase reference to listen to | |
* param @bool boolean - optionally set to true to listen once | |
* return object - firebase object accessor | |
================================================================ | |
This is a lightweight solution to handle firebase data with | |
mithril. It takes a firebase reference and returns an object which | |
provides access to the returned data. | |
since firebase stores data as objects only, extend it with some | |
useful array methods (forEach, filter, map, reduce) which work on | |
the returned snapshot. | |
Basic CRUD methods allow for add, update, remove and DataBinding | |
of snapshot values. | |
****************************************************************/ | |
var mithrilFire = function mithrilFire(ref, once) { | |
var data = []; | |
var fbo = { | |
asArray: function asArray() { | |
var out = []; | |
data.forEach(function(item) { | |
var value = item.val(); | |
if(typeof(value) !== 'object' || !value) { | |
value = { '.value': value }; | |
} | |
value.$id = item.key(); | |
out.push(value); | |
}); | |
return out; | |
}, | |
filter: function filter(fn) { | |
var out = []; | |
data.forEach(function(item) { | |
if (fn.call(item, item.val(), item.key(), data)) { | |
out.push(item); | |
} | |
}); | |
return out; | |
}, | |
forEach: function forEach(fn) { | |
data.forEach(fn); | |
}, | |
map: function map(fn) { | |
var out = []; | |
data.forEach(function(item) { | |
out.push(fn.call(item, item.val(), item.key(), data)); | |
}); | |
return out; | |
}, | |
reduce: function reduce(fn, initValue) { | |
data.forEach(function(item) { | |
fn.call(item, initValue, item.val(), item.key(), data); | |
}); | |
return initValue; | |
}, | |
snapshot: function snapshot() { | |
return data; | |
}, | |
add: function add(value, priority) { | |
var key = data.push(value); | |
if(priority) { | |
data.setPriority(key, priority); | |
} | |
return key; | |
}, | |
update: function update(key, newData, priority) { | |
var ref = data.child(key).ref(); | |
if (priority) { | |
ref.setWithPriority(newData, priority); | |
} else { | |
ref.set(newData); | |
} | |
}, | |
updatePriority: function updatePriority(key, priority) { | |
var ref = data.child(key).ref(); | |
ref.setPriority(priority); | |
}, | |
remove: function remove(key) { | |
var ref = data.child(key).ref(); | |
ref.remove(); | |
}, | |
withValue: function widthValue(attr, key, snapChild) { | |
return m.withAttr(attr, function(value) { | |
var ref = data.child(key).child(snapChild).ref(); | |
ref.set(value); | |
}); | |
} | |
}; | |
m.startComputation(); | |
ref[(once === true)? 'once': 'on']('value', function(snap) { | |
data = snap; | |
m.endComputation(); | |
}); | |
return fbo; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
note that the gists provided here are deprecated and will soon be removed.
You should use (firebaseMixin)[https://gist.github.com/webcss/e4aaa7d95342d107e1ce] instead.