I need help with JavaScript/jQuery design patterns. Below is some HTML and JS code illustrating what I do, and further below are questions extrapolated from these examples.
Some HTML with nested divs to create a traversing scenario:
<div class="box">
BOX 1
<div class="nested-boxes">
<div class="box">
BOX 1-1
<div class="nested-boxes">
<div class="box">
BOX 1-1-1
</div>
</div>
</div>
<div class="box">
BOX 1-2
</div>
</div>
</div>
And here is the Javacript code:
// First I declare functions that I want to have available globally
// under a common namespace. Those functions reproduce that namespace as
// a prefix in their name to avoid conflict.
$.extend(true, window, {
MyFunctions: {
Boxes: {
getBox: myfunctions_boxes_getBox
},
Circles: {
// getCircle: myfunctions_circle_getCircle
}
// Squares....
}
});
// I write functions which I want to use on jQuery objects as so:
function myfunctions_boxes_getNestedBoxes() {
return this.find('.nested-boxes').first().children('.box');
}
function myfunctions_boxes_showLabel() {
return this.find('span').first().text();
}
// I then add those functions as new methods to my jQuery objects:
function myfunctions_boxes_getBox($element) {
var $box = $element.closest('.box');
$box.getParentBox = myfunctions_boxes_getParentBox;
$box.getNestedBoxes = myfunctions_boxes_getNestedBoxes;
$box.showLabel = myfunctions_boxes_showLabel;
console.log('getBox',$box);
return $box;
}
// Traversing functions call each other to make sure I retrieve a jQuery object with all
// my custom methods:
function myfunctions_boxes_getParentBox() {
var $parent_box = myfunctions_boxes_getBox(this.closest('.box').parents('.box').first());
console.log('getParentBox',$parent_box);
return $parent_box;
}
Now this is what my code looks like:
// I first need to call a global function:
$box = MyFunctions.Boxes.getBox($('#box-1-1'));
// Then I can start chaining my methods
$box.getParentBox().getNestedBoxes().each(function(){
// however as soon as I use a native jQuery method, I end up with
// a jQuery object which doesn't have my custom methods ans I need
// to use a global function again.
console.log($(this), MyFunctions.Boxes.getBox($(this)).showLabel());
});
A jsFiddle showing this code in action (should it help you understand what I do) is available.
Q1: How can I write my functions without having to repeat the namespace as a prefix in their name (e.g. myfunctions_boxes_) while avoiding conflicts with third party code?
Every time I create a new function that I want to use as a custom method on a jQuery object (e.g. getParentBox, getNestedBoxes...) I have to manually map it inside one of my functions (i.e. myfunctions_boxes_getBox):
Q2: Is there a way to automatically map my custom methods?
The below question may be related to the above one but I prefer asking it separately as I feel they're not exactly the same
As soon as I use a native jQuery method (e.g. each in above example), I end up with jQuery objects which don't have my custom methods and I need to call one of my global functions again to retrieve the same object but with my custom methods attached to it.
Q3: Would it make sense to create a jQuery plugin for my global functions to keep the OO nature of me code (see below example)?
// plugin declaration (the getBox function should be modified to make use of this)
jQuery.fn.getBox = MyFunctions.Boxes.getBox
// then my code becomes cleaner:
$('#box-1-1').getBox().getParentBox().getNestedBoxes().each(function(){
console.log($(this).getBox().showLabel());
});