Building Components in Adobe CQ 5 – Part 1: A tutorial on clientlibs using jQuery UI

This is the first part of a multi-part set of posts I want to write about some things I learned while building a component in CQ 5.4. Since I struggled in a couple of areas, I am sure some of you have or will too.

In this first post, I want to cover the use of the clientlibs functionality in CQ. As you will gather from visiting the link, there is not much detail on this very useful capability. As you may or may not know, CQ renders web pages using Apache Sling. The tag line says “Bringing back the fun” … More on my take on that in a later post. Ultimately, pages are displayed by first locating content in the repository and based on the content’s resource type and selector. These resolve to scripts that actually render the content. The bottom line is that the final page that you see in your browser is made up of the output of multiple scripts that generate the HTML and associated assets.

This is where clientlibs comes in handy. Let’s say you would like to use a jQuery plugin from jQuery UI or some other plugin like Flexigrid in a custom CQ component, the key requirement is to include a combination of CSS and JS files in your page. Of course, in CQ you can edit the page templates of your site to include those libraries required for your component. But this is not best practice for a couple of reasons:

  1. Including client-side files in templates increases you page overhead because these files will be included in all pages wether they are needed or not;
  2. Your component will not be portable. If your rely on includes in the templates, then if you wanted to re-use your component on some other instance of CQ, you would have to manually touch the site templates to ensure that your component has the necessary libararies.

Clientlibs is a convenience wrapper for the com.day.cq.widget.HtmlLibraryManager service interface. This service manages the client side includes like JS and CSS to manage which files should be included in the page as well as ensuring duplicate files are not sent. Using clientlibs in CQ is really easy, once you know what to do that is :).

Here is a short tutorial to walk through what you need to do to. The example we will use, is include the jQuery UI files to leverage the dialog plugin to display a jQuery modal dialog.

I am using CRXDE to create the project.

  1. Create a basic component project in CQ. I am assuming you know how to do this. If not, have a look at this tutorial. I called my component myjquerysample. The project should look like this:
  2. Create a new cq:ClientLibraryFolder node under myjquerysample called clientlibs.
  3. Set the following properties on the new node:
    Name Type Value
    dependencies String[] cq.jquery
    categories String[] jquerysamples

    The dependencies property tell the CQ rendering engine to make sure that the jquery libraries are included in the page. CQ uses comes with jQuery libraries as they are used for built-in product features. CQ 5.4 comes with jQuery version 1.4.4. The categories property is absolutely key. We’ll see in another step that the category name will be used to tell CQ which clientlibs must be included with the html that will be generated. In fact, the cq.jquery we specified for the dependencies is a category. CQ uses categories to identify client libraries to be included.

  4. Select and download the jQuery UI components from jqueryui.com. Again, I assume you know how to do this. Here is a screenshot of the options that I chose. Extract the zip file you downloaded. In the extracted folder, you will find a folder named js and another css.
  5. Open the css folder on your file system. Since I selected Cupertino as the theme for the jQuery UI components there is a sub folder called cupertino. Open that folder to drag and drop its contents (css file and images folder) into the clientlibs node in CRXDE.
  6.  On your file system, navigate to the js folder to drag and drop the jquery-ui-1.8.16.custom.min.js to the clientlibs node in CRXDE.
  7. Your clientlibs folder should now look like this
  8. Now we need to tell CQ which files we would like to have picked up when our component gets rendered. To do this, create two additional text files in the clientlibs folder: js.txt and css.txt.
    The contents of the js.txt file (I am sure you have guessed already) is the filename(s) of javascript files you would like to include with your component. In our case, we need to reference the jquery-ui-1.8.16.custom.min.js.
    We need to do something similar to the css.txt file. The difference, is we are pointing to the jquery-ui-1.8.16.custom.css file.
  9. OK, now we have everything in place in our clientlibs node. Let’s create a simple component that displays a modal dialog with a message defined by the content author. To accomplish this, we’ll first need to create a dialog node that will enable the content author to provide a string which will be the message to be displayed in the dialog.
    Again, I assume you know how to do this. Here is a screenshot of my dialog tree as a reference.
  10. Now comes the final part, writing the script that will render the component’s content. This is where is all comes together.
    <%--
    My jQuery Sample Component component.
    Author: Marcel Boucher]
    --%>
    
    <%@include file="/libs/foundation/global.jsp"%>
    <%@page session="false" %>
    
    <%
    // Retrieve the configuration property if set by author.
    final String message = properties.get("message", "Default message for dialog.");
    %>
    
    <cq:includeClientLib categories="jquerysamples" />
    
    <script type="text/javascript">
    // This function is called on page ready. It bootstraps the div tag with the jQuery UI dialog class.
    jQuery(function ($) {
    $( "#dialog-message" ).dialog({
    modal: true,
    autoOpen: false,
    buttons: {
    Ok: function() {
    $( this ).dialog( "close" );
    }
    }
    });
    });
    
    // This function actually displays the dialog sets the title and body.
    function showDialog() {
    jQuery( "#dialog-message" ).dialog( "option", "title", 'My Sample jQuery UI Dialog' );
    jQuery("#dialog-message p").html("<%= message %>");
    jQuery("#dialog-message").dialog("open");
    }
    
    </script>
    
    <button id="btnShowMessage" onclick="showDialog()">Show jQuery dialog</button>
    
    <!-- Placeholder for the jQuery UI Dialog plugin -->
    <div id="dialog-message" title="My Sample Dialog">
    <p>Default message content.</p>
    </div>
    

There is a lot going on here. The key line in this code is the <cq:includeClientLib> JSP tag. We tell CQ to include all clientlibs folders that have been tagged as being part of the jquerysamples category. This also means that you could create shared clientlibs across multiple components.

,,,

Comments Closed

8 Responses to Building Components in Adobe CQ 5 – Part 1: A tutorial on clientlibs using jQuery UI

  1. Mike Thaxton says:

    Marcel, this is a great write-up of a powerful and tremendously real-world useful feature. A couple of questions I have come across recently, though:

    1. In your example above, the js file included client-side would be “/apps/samples/components/myjquerysample.js”. Since we’d be doing this to a number of components, how can we avoid exposing the entire /apps tree via the dispatcher? Is this a security risk? Client-side files with “apps / components” in the URL feel odd to me, or at least a non-standard configuration.

    2. In practice, this component would have a use beyond just displaying the jQuery effect – say, it’s a title component. The same effect might need to be used in a footer component – in the above, the footer component would need to include the clientlibs of the title component. A developer/author might not know that and we’d end up with two or more copies of the jQuery files. What are your thoughts on centralizing certain clientlibs that are used in multiple components/pages? In /etc, perhaps?

  2. Ryan Lunka says:

    @Mike and @Marcel…

    We’ve been working quite a bit with ClientLib folders on our current project. They can be extremely powerful, but challenging to figure out. We’ve had a little bit of advice from Adobe Consulting, but are working on our best practices for use.

    In order to keep our clientlibs out of the “app” tree, we posted put them beneath etc/clientlibs/myapp. Another recommendation had been made to put them beneath the design node (etc/designs/myapp), but we have not decided if we feel that it’s best to mix “functionality-based” JS and CSS with “style-based” CSS designs.

    Another trick is working through how to dynamically include a clientlib: only include a clientlib once if it is needed. Simply writing the “IncludeClientLibrary” tag WITHIN a component that depends on the clientlib will only pull the library in when necessary (saving page size), but that also means pulling it in once for EVERY instance of that component on the page.

    We are going to assess a recommendation from AC: add a “categories” property to each of your components, specifying the dependencies on clientlibs for that component. Then in the HEAD of our base page component, tally up what clientlibs need to be pulled in based on what components are on the current page, using that property. This way you can only pull in the necessary clientlibs, and you will only pull them in once a piece.

    I’m curious to hear other’s thoughts on our ideas and the advice we were given as well as any other thoughts on this topic.

  3. Praveen says:

    Good post by the way.This tutorial is for a individual component. I am eager to know the proedure to create the clientlibs structure for the whole website. I have multile folders with CSS and jquery files in them.. How can i include all of them using a clientlib approach???

  4. Gabriel Walt says:

    Just some quick notes for the sake of completeness:

    – I consider it as best practice to put the clientlibs under the /apps folder as long as there is a clientlib outside of the /apps folder (typically in the /etc/designs) folder that concatenates them all into one file. That way you can have the CSS and JS where they belong to, right next to the JSP that contains the associated markup and still merge them together into one file that is located in /etc/designs.

    – There are two very convenient tools that you need to know when you are working with clientlibs:
    1. if you access your page with the ?debugClientLibs=true argument in the path, it will include individual JS / CSS files again on the fly, which helps during debugging in Firebug etc.
    2. you can see a list of the different clientlibs of your instance through the following url, which again helps debugging:
    http://localhost:4502/libs/cq/ui/content/dumplibs.html

    • Danny says:

      Gabriel, in response to your response about where to place CSS/JS. How are you concatenating the CSS/JS from the apps/component folder into etc/designs in a single file? Are you simply copying and pasting them? Or is there some way to automatically move them into etc?

      • Matthew Sullivan says:

        You would use another clientlib under /etc which may not even have any files, which would include your /apps category clientlib and any others using the “embed” string[] property. Then rather than include the one from /apps with “IncludeClientLibrary” you would include the one from /etc.

        Look at /etc/clientlibs/foundation/main which embeds all of the clientlibs with category cq.foundation from under libs, into one called cq.foundation-main under /etc

    • Ryan Lunka says:

      Doesn’t this create a scenario where your app pulls in ALL of the possible JavaScript in your site for every single page load? Isn’t that unnecessary document weight?

      Also, do you have any information about the “themes” I see in the Geometrixx clientlib? That is one of a few things about Geometrixx that seems to work differently and I cannot quite figure it out.