I'm writing an app that is using a revealing-ish module pattern. I'm using Gulp for compilation, so I can set the order of compilation. Aside from some jQuery, there aren't any other frameworks or libraries at play.
I'm trying to break the files up:
I'm trying to namespace as follows:
myApp
myApp.dashboard
myApp.dashboard.ui
myApp.dashboard.data
The problem is the namespace nesting because (for example) my dashboard.ui.js
file is referenced in dashboard.js
I receive
Uncaught TypeError: Cannot set property 'ui' of undefined
when it tries to access the myApp.dashboard.ui
.
I've tried every order of compilation I can think of. I'm guessing there's something wrong with my pattern but I'm not sure what. Here's an example of the code.
// app.js
let myApp = (function(){
const $els = {
menu: $('#menu')
// etc.
};
const eventHandlers = () => {
//site-wide click event handlers (for example)
};
const utils = {
// utility functions
};
const init = () => {
// set some site variables, etc.
eventHandlers();
};
return {
init,
utils
};
})(myApp || {});
//dashboard.js
myApp.dashboard = (function (parent){
// ! need access to the UI
let ui = parent.dashboard.ui;
const eventHandlers = () => {
...
};
const init = () => {
eventHandlers();
};
return {
init
};
})(myApp || {});
//dashboard.ui.js
myApp.dashboard.ui = (function (parent){
// ! need access to the DATA
let ui = parent.dashboard.data;
const htmlTemplate = (content) => {
return `<h1>${content}</h1>`;
};
const setValidationFlags = () => {
...
};
return {
setValidationFlags
};
})(myApp || {});
//dashboard.data.js
myApp.dashboard.data = (function (parent){
const getData = (dataObject) => {
// do XHR look up
// call setter, etc.
};
const parseForm = () => {
// collect form data.
};
return {
parseForm
};
})(myApp || {});
Can someone please provide some guidance on how to correct my code so that I can nest the UI and Data portions under the myApp.dashboard
namespace and have the three accessible to one another?
If this pattern is way off base, pointers on how to improve it are also welcome.
dashboard
requires ui
requires data
, so you need to load them in the reverse order. And have each module set up the whole namespace tree it needs when it is not yet available:
// data.js
var myApp;
if (!myApp) myApp = {};
if (!myApp.dashboard) myApp.dashboard = {};
myApp.dashboard.data = (function(){
…
return { parseForm };
})();
// ui.js
var myApp;
if (!myApp) myApp = {};
if (!myApp.dashboard) myApp.dashboard = {};
myApp.dashboard.ui = (function(){
// need access to the DATA
const data = myApp.dashboard.data;
…
return {setValidationFlags};
})();
// dashboard.js
var myApp;
if (!myApp) myApp = {};
if (!myApp.dashboard) myApp.dashboard = {};
myApp.dashboard.init = (function(){
// need access to the UI
const ui = parent.dashboard.ui;
…
return () => {
eventHandlers();
};
})();
The alternative would be not to use references to the other modules inside the IIFE that is executed immediately, but to defer them until the init
call which is when all modules should have been loaded.