Chris Spittles Chris Spittles - 5 months ago 42
Javascript Question

How to use Chaining with Nested, Revealing Module Patterns in JavaScript?

I'm struggling to get my head around a couple of JS patterns joined together: the revealing module pattern, and the chaining pattern.

What I would ideally like to be able to do is invoke multiple methods from a single initialising function like this:

components
.loader()
.menu()
.toolbar();


And this works perfectly as long as any methods I define publicly
return this;
.

Things start to go wrong however when I need to nest revealing module patterns in order to expose deeper methods that are invoked outside of the initialisation like this:

components
.menu
.close();


The problem doing this is that
menu
no longer returns
components
, but instead returns it's child methods which means it breaks the chain at this point. Here is a "complete" example to illustrate what I am try to achieve:



var components = function () {

var loader = function () {
console.log("components.loader initialisation");

return this;
}

var menu = function () {
console.log("components.menu initialisation");

var open = function () {
console.log("components.menu.open");

return this;
}
var close = function () {
console.log("components.menu.close");

return this;
}

return {
open: open,
close: close
}
}();

var toolbar = function () {
console.log("components.toolbar initialisation");

return this;
}

return {
loader: loader,
menu: menu(),
toolbar: toolbar
}
}();

$(function () {

components
.loader()
.menu()
.toolbar();

components
.menu
.open();

});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>





So I guess my question is, how can I use; nested, revealing modules and chaining together (if at all possible)?


Answer

var components = (function () {

var loader = function () {
    console.log("components.loader initialisation");

    return this;
};

var menu = function () {

    var menu = function () {
        console.log("components.menu initialisation");
		
        return this;
    };
	

    menu.open = function () {
        console.log("components.menu.open");

        return this;
    };

    menu.close = function () {
        console.log("components.menu.close");

        return this;
    };

    return menu;
};

var toolbar = function () {
    console.log("components.toolbar initialisation");
	
    return this;
};

return {
    loader: loader,
    menu: menu(),
    toolbar: toolbar
};
})();

$(function () {
components
	.loader()
	.menu()
	.toolbar();

components
	.menu
		.open();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>