Skip to content

Instantly share code, notes, and snippets.

@marshall007
Created September 19, 2011 02:18
Show Gist options
  • Save marshall007/1225872 to your computer and use it in GitHub Desktop.
Save marshall007/1225872 to your computer and use it in GitHub Desktop.

Modules

Code Structure

ProductPicker.Module = function(opts) {

    // private data
    var self = {};
    var defaults = {
        target: $('#ppModule'),
        tab: $('#ppTabModule'),
        path: 'html/module.htm',
        bindings: {
            '#ppModuleMain': {
                'click #someElement': 'doModuleTask'
            }
			'#ppModuleBreadcrumb': {
				'hover #anotherElement': 'doModuleTask2'
			}
        }
    };

    self.opts = $.extend(true, defaults, opts || {});

    // private methods
	self.ajax = {
		getModuleData: function(fn) {
			var params = {
				// set parameters required for Ajax call
			};
			ProductPicker.Util.sendAjaxRequest('getModuleData', '', params, fn);
		}
	};
    self.doModuleTask = function(e) {
        e.preventDefault();
		
		self.ajax.getModuleData(function(data) {
			// manipulate data (ex. append to DOM)
		});
    };
	self.doModuleTask2 = function(e) {
		e.preventDefault();
		
		// do some stuff
	}

    // public interface to be exposed
    return {
        init: function() {
            $(self.opts.target).load(self.opts.path, function() {
                ProductPicker.Util.bindEvents(self, self.opts.bindings);
            });
        },
        show: function() {
            $(self.opts.target).show();
            $(self.opts.tab).addClass('current');
        }
    };
};

Code Walk-through

ProductPicker.Module = function(opts) {

Module is the name of the module we intend to define. It must be unique, for example, you couldn't have two different definitions of a module both named Home. The only other thing to note about this line is opts, which allows options that either override or extend the default options. This is not currently in use, but provides extendability and ease of integrating the ProductPicker on other future templates.

var self = {};

Declares self locally, preventing it from overriding other modules' private data.

var defaults = {...};

Declares any default options you would like in addition to the four required ones:

  • target: The "target" node, or where in the DOM the module should be loaded.

    Example: $('#ppModule')

  • tab: The tab associated with the module.

    Example: $('#ppTabModule')

  • path: The path of the HTML file containing the module's framework.

  • bindings: This is where you bind events to callback functions. We'll go into more detail later.

self.opts = $.extend(true, defaults, opts || {});

We simply use the jQuery $.extend() function to combine our default options with any that were passed in when the module was initialized. Again, this functionality is not currently being used. Your variables are now accessible from within your module as self.opts.<variable name>.

self.ajax = {...};

This is where you can write any Ajax calls your module will use. Each of these functions should have at least one parameter, the callback function. Once you've initialized any parameters the server requires to perform the Ajax call (or if there are none, var params = {}), send the Ajax request using the sendAjaxRequest() utility function, like so:

ProductPicker.Util.sendAjaxRequest('functionName', '', params, fn);

self.doModuleTask = function(e) {...};

This is just an example of a callback function used in a binding. You can define as many functions like this as you'd like, or none at all. They will most likely be callback functions, but they do not have to be.

If you look back at the code, you will see an example of how to call an Ajax function described in the previous section. Now you can appreciate why we require a callback function as a parameter. It allows us to get the data back from the Ajax request and do whatever we want with it. Most likely, we'll be getting HTML back from the server (like a list of products), and appending it to the DOM.

return {...};

This contains the functions and data you'd like to make accessible to other modules and the system. There are two required functions:

  • init: Called when the module is initialized for the first time.

    If you need to do anything special, the code should be placed inside .load() and before ProductPicker.Util.bindEvents().

  • show: Called after the module is initialized and then again anytime the module's tab is clicked.

    You shouldn't need to change anything here unless you're doing something super fancy, but if you do, the code should be placed before .show().

Bindings

This is probably the only tricky thing about the new ProductPicker code design and it's very important. For now, I'm just going to explain how to use it. I'll explain how it works once I write the docs for the utility functions.

Old Way to Bind Events

Before, we were defining our callback functions inline, for example, something like this:

$('a.button').live('click', function() {
	// do stuff when links with class "button" are clicked
});

New Way of Binding Events

The method I've implemented now uses the jQuery .delegate() function. You declare all your bindings up in the defaults variable, like so:

bindings: {
    '#elementID': {
        'click a.button': 'buttonClick',
        'hover div.product': 'hoverProduct'
    }
    '#anotherID': {
        'click a.button': 'otherButtonClick',
        'click div.product>a': 'addRemoveProduct'
    }
}

In this case, we have four separate event bindings. '#elementID' and '#anotherID' define the listening scope for their respective events. Basically, if you click on #elementID a.button, self.buttonClick() will be called and if you click #anotherID a.button, self.otherButtonClick() will be called.

I'll go into detail about why we're doing this in the docs for the utility functions, but one benefit you'll find is that you will always get a function name and line number when you're debugging because the function isn't anonymous like in the old method. You'll find this much nicer to use after playing around with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment