JS Link: Avoid Polluting the Global Namespace

Over the past few months I have been doing a lot of research around JavaScript frameworks and techniques as I am learning how to create SharePoint 2013/O365 Apps for clients. A recent project had a need to override the default view of a few columns. JS Link proved to be the easiest way to accomplish the changes, but every example that I found had all of the JavaScript functions placed squarely in the global namespace. One of the things that I find seems to be common among all of the books and articles I have read over the past three months clearly states that we should do our due diligence to keep the global namespace in JavaScript as clean as possible.

Here’s a pretty good explanation over at StackOverflow. The answer discusses garbage collection as well as the dangers of placing everything in the global namespace. The common practice that I see is to wrap up your code into an immediately invoked function expression – if you study the basic code for a JS Link file, you’ll see that it makes use of an IIFE to get things rolling.

(function () {
	var override = {};
	
	override.Template = {};
	
	override.Template.Fields = {
		"Field": { 
			"View": function (ctx) {
					return ctx.CurrentItem.title + ": Overridden";
			}
		}; 
		
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(override);
)();

The IIFE creates a JavaScript line that is immediately executed when the script is loaded. In the example above, a new variable named override is created which will be a JavaScript object. A template property is attached along with a fields object containing the override behavior for the JS Link file. The JS Link, when executed will return the title of the list item with :Overridden appended. This template is registered with the TemplateManager in SharePoint.

The typical approach to creating JS Link files is to add a bunch of individual functions that are called by the JS Link IIFE.

(function() {
	var overrideCtx = {};
	overrideCtx.Templates = {};
	
	overrideCtx.Templates.Fields = {
		'Budget_x0020_ID': {'View': budgetIDField },
		'Actuals':{'View': actualsField },
		'Budget':{'View': budgetField }
	};
	
	SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

function budgetIDField(ctx){
	var html = "<div><strong>" + ctx.CurrentItem.Budget_x0020_ID + "</strong></div>";
	return html;
}

function toUSD(number) {
	/* implementation of conversion to USD */
    return '$' + dollars + '.' + cents.slice(0, 2);
}

function actualsField(ctx) {
	var amount = ctx.CurrentItem.Actuals;
	return toUSD(amount);	
}

function budgetField(ctx) {
	var amount = ctx.CurrentItem.Budget;
	return toUSD(amount);
}

Technically, this is not incorrect, but it definitely adds additional functions to the global namespace that may not need to be there. To move this out of the global namespace means that an IIFE needs to be created. Additionally, a typical practice that I’m getting into is to create a namespace object for storing specific JavaScript functions for a client or solution.

First, I check to see if I already have an object to store my functions that are specific to this solution.

This line will check the global namespace for an object named AwesomeJSLinkSolution. If a variable with the same name is found, it is used. Otherwise a new object is created. (This is good and responsible use of the global namespace.)

Next, the IIFE declaration is created:

With the IIFE, anything that I want to be scoped publically, must be returned. This includes functions and variables that may need to be used later by the solution.

There is also a helper function called toUSD that is used by the solution. Since this function is not necessary to be called from outside the scope of the IIFE, it can be declared directly inside the IIFE. The final code for the IIFE now looks like the following:

var AwesomeJSLinkSolution = AwesomeJSLinkSolution || {};

AwesomeJSLinkSolution.BudgetFields = (function () {
	
	function toUSD(amount) {
		/* convert amount */
		return amount;
	};

	return {
		budgetIDField: function (ctx) {
			var html = "<div><strong>" + ctx.CurrentItem.Budget_x0020_ID + "</strong></div>";
			return html;
		},
		actualsField: function (ctx) {
			var amount = ctx.CurrentItem.Actuals;
			return toUSD(amount);	
		},
		budgetField: function (ctx) {
			var amount = ctx.CurrentItem.Budget;
			return toUSD(amount);
		}
	}
})();

Now the functions that apply to this specific solution are no longer located in the global namespace. Additionally, a function that is specific to this JS Link file is not even accessible outside of the IIFE.

The only outstanding task it to modify the JS Link file. This is a matter of simply updating the function calls to use the new object created by the IIFE.

(function() {
	var overrideCtx = {};
	overrideCtx.Templates = {};
	
	overrideCtx.Templates.Fields = {
		'Budget_x0020_ID': {'View': AwesomeJSLinkSolution.BudgetFields.budgetIDField },
		'Actuals':{'View': AwesomeJSLinkSolution.BudgetFields.actualsField },
		'Budget':{'View': AwesomeJSLinkSolution.BudgetFields.budgetField }
	};
	
	SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

The final file source is:

var AwesomeJSLinkSolution = AwesomeJSLinkSolution || {};

AwesomeJSLinkSolution.BudgetFields = (function () {
	
	function toUSD(amount) {
		/* convert amount */
		return amount;
	};

	return {
		budgetIDField: function (ctx) {
			var html = "<div><strong>" + ctx.CurrentItem.Budget_x0020_ID + "</strong></div>";
			return html;
		},
		actualsField: function (ctx) {
			var amount = ctx.CurrentItem.Actuals;
			return toUSD(amount);	
		},
		budgetField: function (ctx) {
			var amount = ctx.CurrentItem.Budget;
			return toUSD(amount);
		}
	}
})();

(function() {
	var overrideCtx = {};
	overrideCtx.Templates = {};
	
	overrideCtx.Templates.Fields = {
		'Budget_x0020_ID': {'View': AwesomeJSLinkSolution.BudgetFields.budgetIDField },
		'Actuals':{'View': AwesomeJSLinkSolution.BudgetFields.actualsField },
		'Budget':{'View': AwesomeJSLinkSolution.BudgetFields.budgetField }
	};
	
	SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

JS Link Resouces

Advertisements

5 thoughts on “JS Link: Avoid Polluting the Global Namespace

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s