Advanced Javascript Namespaces for Portlets +
As mentioned earlier, we are doing some heavily ajaxified portlets over here at agimatec. When we switched to this Javascript-Centric Portlets, we had to solve a problem more people tend to have: The fundamental flaw of Javascript to depend on global variables for linking and the resulting clash of function names we wrote for our portlets. There is a wildly-published way to handle this, which is not suitable when writing more than a few Javascript functions, and the way we handle this problem. But let’s start with a description of the commonly advised way of handling this problem and how that way falls short when doing serious Javascript in portlets.
The easy way
When consulting the portlet books on the market or Sun’s own tips, you’ gonna find one easy solution to the problem: using the portlet namespace for your Javascript. The portlet namespace is a portlet-instance specific string that is suitable to identify assets of a portlet instance. So the easy way out is to use it as prefix or post fix for the functions you write:
<!-- Example: JSP page --> <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
Wow, that was easy. But there are some drawback when doing this:
- you have to stick to define your Javascript inside the portlets – no external Javascript files!
- being unable to define external Javascript files, there is no easy way of sharing Javascript code between portlets, which is not DRY
- Debugging gets even more painful with function names like “show_<insert some lengthy string here>()”
So, if your are up to make heavy use of Javascript and Ajax-based rich user interfaces, this is a no-go.
Using external Javascript files
So, loading Javascript form external file is the way to go. So here is our approach to the problem:
Use Javascript namespaces
We are putting all our stuff into one global variable, called “agimatec” (at the time we chose the name, we were not aware of Douglas Crockford‘s advice on making globals uppercase – otherwise we would haven named it “AGIMATEC”). This ensures that we’re leaving all third party scripts on the page untouched. Each portlet has its own (sub-)namespace inside this global.
Use a convention to locate the script files
We’re putting our javascript files into a java-like folder structure that reflects our namespace structure, so the portlet “Clientis Edit User” is put into the namespace “agimatec.portlet” and the corresponding file can be found under “agimatec/portlet/clientisEditUser.js”
Use a common initialization method for all portlets
All our portlet scripts must define the function “getPortlet()”, which returns a “raw” version of the portlet script.
Let a library create portlet script objects
Last but definitely not least we have written our own library to create portlet instances. The library contains a function that takes the portlet namespace string, along with the name of the portlet Javascript object, creates a new instance by calling “getPortlet()” on the Portlet object and puts the instance into its own namespace which is created using the portlet namespace:
/**
* Create a portlet namespace instance.
* @param {object} portletObject A raw portlet namespace
* @param {string} portletNamespace The Portlet ID as given by the portlet container
*/
agimatec.createPortletInstance(portletObject, portletNamespaceId){
var rawNamespace = portletObject.getPortlet();
portletObject[portletNamespaceId] = rawNamespace;
}
Using this technique, we are able to write clean, fully namespace-wrapped portlet scripts that have no problems with colliding function names and can co-exist even in multiple instances on one page without problems. As bonus, two instances of the same portlet on one page only load the external Javascript file once.
One major thing is not mentioned of this post: how to load the portlet scripts. We are using the YUI Loader for loading the portlet scripts, amoung other things. I’ll cover this in another post in the next weeks, so stay tuned.
[...] promised earlier, i’ll discuss in this post how we load the Javascript modules we have written over the last [...]
[...] Portlet namespaces and javascript [...]
[...] Portlet namespaces and javascript [...]