In response to my own question on Stack Overflow, I'm attempting a solution to decouple JavaScript and html. I'd appreciate any comments, proposed refactoring, or criticism.
I have a fiddle of it in use here
Here's the code:
(function (window, $, undefined) {
"use strict";
var ab = window.ab = window.autoBinder = {},
elements;
ab.exportSymbol = function (publicPath, object) {
var tokens = publicPath.split("."),
target = window,
i;
for (i = 0; i < tokens.length - 1; i++) {
target = target[tokens[i]];
}
target[tokens[tokens.length - 1]] = object;
};
ab.exportProperty = function (owner, publicName, object) {
owner[publicName] = object;
};
ab.extensions = (function () {
return {
datePicker: function (element) {
var params = {
minDate: 0,
showButtonPanel: false
},
e = $(element);
if (e.data("mindate") !== undefined) {
params.minDate = e.data("mindate");
}
if (e.data("showpanel") !== undefined) {
params.showButtonPanel = e.data("showpanel");
}
e.datepicker(params);
}
};
})();
ab.hookups = (function () {
return {
make: function (value, element) {
if (ab.extensions[value]) {
ab.extensions[value](element);
}
},
publish: function (value, $element) {
if (!value) {
return;
}
$element.change(function () {
$element.trigger(value, $element);
});
},
subscribe: function (value, $element) {
var trigger = $element.data("trigger");
if (trigger === undefined) {
throw "Found Subscribe without Trigger.";
}
if (!ab.extensions[trigger]) {
throw "Found Subscribe without Trigger.";
}
$(document).bind(value, function (event, htmlElement) {
ab.extensions[trigger](event, htmlElement, $element);
});
}
};
})();
ab.exportSymbol("ab.extensions.datePicker", ab.extensions.datePicker);
ab.exportSymbol("ab.hookups.make", ab.hookups.make);
ab.exportSymbol("ab.hookups.publish", ab.hookups.publish);
ab.exportSymbol("ab.hookups.subscribe", ab.hookups.subscribe);
$(window).load(function () {
elements = $("*").filter(function () {
var data = $(this).data(),
p;
if (data === undefined) {
return false;
}
for (p in data) {
if (data.hasOwnProperty(p)) {
return true;
}
}
return false;
});
elements.each(function () {
var obj = $(this),
data = obj.data(),
p;
for (p in data) {
if (data.hasOwnProperty(p)) {
if (ab.hookups[p]) {
ab.hookups[p](data[p], obj);
}
}
}
});
});
} (window, jQuery));
// #region Example of Extending extensions
window.ab.extensions.effectiveDateChanged = function (event, triggerElement, subscribedElement) {
var $element = jQuery(triggerElement);
subscribedElement.val("Value set to: " + $element.val());
};
window.ab.extensions.dropDownChanged = function(event, triggerElement, subscribedElement) {
var $element = jQuery(triggerElement),
value = $element.val();
if (value === "") {
subscribedElement.attr("disabled", "disabled");
subscribedElement.html("");
return;
}
subscribedElement.removeAttr("disabled");
subscribedElement.html("<option>" + value + "</option>");
};
// #endregion