By Cory House
So you’re building a modern web app? That means you’re likely running a variety of client-side libraries and custom business logic in JavaScript. One of the first hurdles you run into is, “Hey, I need some data from the server injected in my JavaScript.” Some developers, when posed this problem, have an unproductive response: They start dynamically generating strings of JavaScript on the server so they can inject custom logic onto the page.
No surprise. This is arguably the path of least resistance. But as we’ll see below, it’s toxic because it’s hard to maintain. And it’s not performant. And…okay, let’s hold off on the justification for a second and review a concrete example.
Imagine you’ve built a content management system that is run by multiple clients. Each client configures their Google Analytics Key within an admin console, which you then save to the database. Ultimately, this data needs to be injected into JavaScript. One approach is to build the entire Google Analytics script in a string on the server and inject it onto the page. It looks like this in C#:
string googleAnalyticsScript = @"var _gaq = _gaq || [];
_gaq.push(['_setAccount', '" + googleAnalyticsKey + @"']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();";
Note how hard this is to read. Since the entire script is now stored in a string on the server, it’s a wall of text with no code coloring except for the googleAnalyticsKey variable that’s being injected into the script. There’s a variety of other issues with this approach that we’ll get to shortly.
Thankfully, a much cleaner option exists using what I call the JavaScript configuration object pattern. Begin by placing the static JavaScript in a .js file. Use variables as placeholders for any dynamic data:
Note the reference to websiteSetup.GoogleAnalyticsKey
above on line two. Where’s that data defined? We define it separately by creating a data structure on the server and serializing it to JSON using a library. As we’re about to see, this is trivial since virtually all popular programming languages have libraries for serializing objects to JSON. Let’s take a look at how we pull this off in C#.
First, define a class called WebSiteSetup
with the necessary properties. In this example we only need a single property to store the Google Analytics Key, but the idea scales well if you have a complex dataset to inject.
public class WebsiteSetup
{
public string GoogleAnalyticsKey;
}
Alternatively, in C# you could simply serialize an anonymous type, and, with a single value like this, that arguably makes the most sense.
Once you’ve defined your type, use a JSON serialization library on the server to convert an instance of this type into JSON. In C#, there are many JSON serialization libraries but in this example I’ll use JavaScriptSerializer since it’s shipped with the .NET framework.
var websiteSetup = new WebsiteSetup()
{
GoogleAnalyticsKey = "GoogleAnalyticsKeyFromDatabaseSetHere"
};
var json = new JavaScriptSerializer().Serialize(websiteSetup);
The snippet above will generate the following JSON string:
"{\"GoogleAnalyticsKey\":\"GoogleAnalyticsIdFromDatabaseSetHere\"}"
Now it’s just a matter of injecting this string into the head of your page. This piece will vary depending on your server-side technology, but in ASP.NET WebForms you’d do something like this:
var websiteSetup = "var websiteSetup = " + json + ";";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "WebSiteSetupScript", websiteSetup, true);
The idea here is simple: inject the data that your static .js script will need into the head of your page. Just make sure this JSON is injected before your static .js script. The beauty of this approach is we’ve separated our concerns. Configuration data is separate from the definition of the static third party script. And we’ve gained many other benefits, as we’ll see below.
So yes, there are a few more moving parts here, and going through these extra steps to inject a single piece of data into a small script that Google provides may seem like overkill to you. But imagine you’re building client-side charts that require dozens of datapoints from the server for configuration and rendering. Then this approach really shines.
Regardless, chances are you’ll need a variety of data from the server on page load for various JavaScript files. Defining a single setup object that contains all this data allows you to keep all static JavaScript within .js files. The big rule here is to stay native. By native, I mean JavaScript belongs in .js files, not some string written in a server-side language. There’s a variety of benefits to staying native by using the configuration object pattern above.
Programming is the art of telling another human what one wants the computer to do.
Donald Knuth
StackOverflow uses the configuration object pattern as well. Visit StackOverflow.com and view source. Search for StackExchange.init(
. They simply serialize an object to JSON so that their .JS files have the dynamic data necessary to perform the desired client-side behavior. So hey, we’re in good company here.
This conversation is a sampling of the topics I cover in my new Pluralsight course “Clean Code: Writing Code for Humans”. If you’re interested in becoming a better developer and building a vocabulary for evaluating code quality, give it a look!
This article was originally published at http://www.bitnative.com/2013/10/06/javascript-configuration-object-pattern/