Optional Config Objects in JavaScript OOP
Well, one of the challenges in writing our custom JavaScript library for this next release of our CMS at work has been to come up with a modularized approach to our objects that can be followed precisely while still allowing a measure of flexibility to the end developer (Imagine that! Actually trying to support some framework style design principles in JavaScript!). Anyway, what has been one of the most challenging pieces to the puzzle has been to appropriately handle configuration objects passed to constructors that override specific, default behavior of the object.
No, the challenge was not so much handling a config object proper — that is relatively easy. Where the challenge began to really take shape was in allowing a user to provide specific pieces of optional data and only use the valid pieces of the config object to override existing default values while ignoring the rest so as not to cause any JavaScript errors to be thrown elsewhere in the script. For a quick example, let’s say we have the following data object that loads itself up using an Ajax call (NOTE: all examples in this post are using the ExtJS lib).
var DataObject = function()
{
// Load method
this.load = function(id)
{
var o = this;
if (this.beforeload) this.beforeload();
Ext.Ajax.request({
url : o.ajaxFiles.load,
headers : { 'Content-type' : 'text/xml' },
params : { id : o.data.id },
callback : function(opts, success, response)
{
var obj = parseXMLResponse(response.responseXML.documentElement); // Custom parse function
var data = Ext.util.JSON.decode(obj.data);
// Load up our data object from the response
for (var k in data)
{
o.data[k] = data[k];
}
if (o.afterload) o.afterload(o);
}
});
};
this.loadConfig = function(config)
{
// Here is what we need to build appropriately
};
// Now, we run our constructor logic and set up our default values
this.data = {};
this.ajaxFiles = {
load : 'path/to/my/load.php' // MUST have this, since it's used in this.load()
};
// Load the config object if it has been provided
if (config) this.loadConfig(config);
}
The this.loadConfig() method is what we are discussing in this post. We want a way of handling the configuration values provided by the user, assigning only those values provide without overriding defaults that will cause our object to break. My first attempt was very straight forward but had holes in it:
this.loadConfig = function(config)
{
for (var k in config)
{
this[k] = config[k];
}
}
Pretty simple approach, but I realized that as soon as I passed a config object with any reference to an ajaxFile object, all default values of the ajaxFiles member variable were nullified if they were not explicitly defined within the config object. For our example, assume we pass in an empty ajaxFiles object within our config properties:
var obj = new DataObject({
ajaxFiles : {},
afterload : function(o)
{
alert('Our load has completed');
}
});
You’ll notice that, for good measure, I went ahead and assigned an afterload handler to alert us when the actual load process is done. However, based on our preliminary loadConfig() method, we now have a completely empty ajaxFiles object. To remedy this, we need to have a specific design pattern to follow to assign all sub-values of any config options that may have default values.
While quite likely not the most optimized way to handle this, we can at least see the principle implied in this example. You can easily see how we can (and should) manually handle specific attributes of our config object while still allowing the user full control over other, more general overrides as well:
this.loadConfig = function(config)
{
for (var k in config)
{
if (k != 'ajaxFiles') // Filter out custom handled options
{
this[k] = config[k];
}
}
// Now, handle them explicitly
if (config.ajaxFiles)
{
for (var k in config.ajaxFiles)
{
this.ajaxFiles[k] = config.ajaxFiles[k];
}
}
}
If we handle each of our custom object values this way, we can allow for very precise assignment of overrides while preserving the integrity of our overall object.
This isn’t rocket science by any means, but it’s the sort of thing where the light just sort of “comes on”, so I thought I’d share in the slim chance anyone else was struggling with the same type of flexibility challenge.
Enjoy!
Garth Henson has been working professionally as a web developer for nearly 10 years. When not coding in PHP, JavaScript or Actionscript, he can usually be found trying to refine his photography skills.





