JavaScript Best Practices

JavaScript usage in portlets requires care by the portlet developers to avoid library, version and namespace conflicts with both the portal framework and other portlets on the same page. Below are uPortal's recommendations for using JavaScript frameworks in your portlets to help mitigate these issues.

Recommended Frameworks

Fluid

uPortal 3.1 will adopt the use of the Fluid framework for some of the dynamic user interface components. Fluid provides accessible JavaScript components that work across all A Grade Browsers. The uPortal project will be continuing to move to Fluid provided components and CSS classes for the framework and bundled portlets.

jQuery

A very full featured JavaScript framework that has some key features for working in a portal environment including global namespace and conflict resolution. Fluid uses jQuery as its base JavaScript framework.

JavaScript Loading & Name Spaces

Unfortunately the JSR-168 specification doesn't provide a way for a portlet to contribute to the <head> of a document for things like loading JavaScript files. That leaves the best option for a developer to load the JavaScript frameworks that the portlet needs inline in the HTML markup of the page. Below is an example of loading jQuery 1.4.2, jQuery TreeView 1.4.0 and assigning them to the $tv namespace under the communities var. The communities var is used as a namespace for this portlet, allowing the portlet to declare its own functions without placing them in the global namespace.

<script type="text/javascript" src="${pageContext.request.contextPath}/javascript/jquery/1.4.2/jquery-1.4.2.pack.js" ></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/javascript/jquery-treeview/1.4.0/jquery.treeview.js" ></script>
<script type="text/javascript">
    var communities = {};
    jQuery.noConflict(true);
    jQuery(function($) {
        // treeview init
        $('ul.listing').treeview({
            animated: {duration:300, easing:"swing"},
            collapsed: true,
            unique: false
        });
        $('ul.treeview ul').siblings('a').click(function(e) {
            e.preventDefault();
            $(this).siblings('div.hitarea').trigger('click');
            $(this).blur();
        });
    });
</script>

Using this approach the portlet is ensured it will not be affected by other versions of jQuery loaded on the same page or other JavaScript frameworks that affect $. The approach is described on jQuery's Using jQuery with Other Libraries page.

JavaScript Caching

The other important approach the above example takes is to fully qualify the paths to the JavaScript. The full library name, version number and packaging should be included on the URL that the script is loaded from. This allows the portlet developer to set aggressive browser caching headers for the JavaScript to reduce subsequent page load times. If a JavaScript framework is upgraded the change in the version number in the URL will ensure the new version is loaded.

Targeting of elements

If you need to target an element in your markup, you must also make sure that those elements are named appropriately. If using JSP, you can use the portlet taglib and the <portlet:namespace/> tag to prefix your elements with a unique portlet ID, like so:

$j('#<portlet:namespace/>_content').fadeIn(500);

and

<div id="<portlet:namespace/>_content"></div>

This approach will allow you to have multiple instances of a portlet on one page and each will target the correct element within the portlet.