\$\begingroup\$\$\endgroup\$
In response tomy 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 usehere
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>");};// #endregion1 Answer1
\$\begingroup\$\$\endgroup\$
Update here:http://jsfiddle.net/5ej8G/3/ (code is also pasted below)
Main suggestions:
- your exportSymbol function can be refactored to handle an array of publicPaths and Objects.
- The subscribe conditions can be consolidated since they throw the same message.
- check your parameters before using. typeOf checks don't work well with all objects, but there are techniques to have them work with all objects. One from Angus Croll(http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/) is included in the link above.
- Explicitly state which elements you want your code to act on, maybe by passing in a parameter object. doing a $("*"), on medium to large pages (with lots of dom elements) can be a performance hit.
(function (window, $, undefined) { "use strict"; var ab = window.ab = window.autoBinder = {}, elements, toType = function(obj) { return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() }; //can handle an array of publicPaths and objects ab.exportSymbols = function (paramArray) { var tokens, target = window, i, index, len, limit, exportSymbol; if(toType(paramArray) !== 'array') { throw "You must pass an array into this function."; } //Export Symbol now becomes a inner helper function exportSymbol = function(pubPath, obj) { tokens = pubPath.split("."); lastIndex = tokens.Length; for (i = 0; i < lastIndex ; i++) { target = target[tokens[i]]; } target[tokens[lastIndex]] = obj; }; //validate and run helper function on each object in array for(index= 0, len=paramArray.length; i < len; i++) { if(toType(paramArray.publicPath) !== 'string' || toType(paramArray.publicPath) !== 'object') { continue; } exportSymbol(paramArray[index].publicPath, paramArray[index].obj); } }; 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"); //Conditions can be consolidate since they trow the same message if ((trigger === undefined) || !ab.extensions[trigger]) { throw "Found Subscribe without Trigger."; } $(document).bind(value, function (event, htmlElement) { ab.extensions[trigger](event, htmlElement, $element); }); } }; })(); //can pass in a an array of object instead of mutiple calls ab.exportSymbols([ {pubPath : "ab.extensions.datePicker", obj : ab.extensions.datePicker}, {pubPath : "ab.hookups.make" , obj : ab.hookups.make}, {pubPath : "ab.hookups.publish" , obj : ab.hookups.publish}, {pubPath : "ab.hookups.subscribe" , obj : 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));// Example 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>");};You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
