-
-
Save josephrexme/7f0a6124d9b4d2794551 to your computer and use it in GitHub Desktop.
Simple two-way data binding
This file contains hidden or 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
do ($ = jQuery, exports = window) -> | |
class ActiveDataBinder | |
constructor: (uid) -> | |
# Use a jQuery object as simple PubSub | |
pubSub = $ {} | |
# We expect a 'data' attribute specifying the binding | |
# in the form 'data-bind-<uid>="<attribute>" and name | |
# the corresponding message in the form '<uid>:change'. | |
dataAttr = "bind-" + uid | |
message = uid + ":change" | |
# Listen to change events on elements with the data-binding attribute and proxy | |
# them to the PubSub, so that the change is "broadcasted" to all listeners. | |
$(document).on "change", "[data-" + dataAttr + "]", (event) -> | |
$input = $(this) | |
attr = $input.data(dataAttr) | |
value = $input.data("bind-value") | |
value ||= if $input.is(":checkbox") then $input.is(":checked") else $input.val() | |
pubSub.trigger message, [ attr, value ] | |
# PubSub propagates changes to all bound elements, setting value of | |
# input tags or HTML content of other tags. | |
pubSub.on message, (event, property, value) -> | |
for elem in $("[data-" + dataAttr + "='" + property + "']") | |
$elem = $(elem) | |
if $elem.data("bind-value") | |
# Nothing to do. No visual representation of the value. | |
else if $elem.is("input:not(:checkbox), textarea, select") | |
$elem.val(value) | |
else if $elem.is(":checkbox") | |
$elem.prop("checked", value) | |
else | |
$elem.html(value) | |
return pubSub | |
# ActiveData wraps a 'data' object identified by 'uid', listens for change | |
# events and provides a minimal interface of 'set' and 'get' methods for | |
# easy two-way data binding. | |
class ActiveData | |
constructor: (data, uid) -> | |
# Setup the data binding, listen for message in the form "<uid>:change" | |
# and update the data unless the change was initiated by us. | |
binder = new ActiveDataBinder(uid) | |
message = uid + ":change" | |
wrapper = | |
set: (attr, val) -> | |
data[attr] = val | |
binder.trigger message, [ attr, val, this ] | |
get: (attr) -> data[attr] | |
binder.on message, (event, attr, value, initiator) -> | |
wrapper.set(attr, value) unless initiator == wrapper | |
return wrapper | |
# Export both classes into the global namespace (usually 'window'). | |
exports.ActiveDataBinder = ActiveDataBinder | |
exports.ActiveData = ActiveData |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment