1,789 articles and 14,172 comments as of Sunday, December 5th, 2010

Wednesday, July 21, 2010

Use jQuery to Create a Tag Cloud

Guest Author: Jason MacKenzie
Intelligence Among Us

I was searching for a way to implement tag cloud functionality for a very specific use case that my client requires.  We are in the middle of a large migration of forms from Lotus Notes to InfoPath and part of the job is going to be increasing the “findability” of the new forms. 

My objective is to make the searching of forms so simple that a new employee should be able to find what they are looking for the first time, every time.  I’m a big fan of tagging and tag clouds as one mechanism for categorizing content and wanted to see what would be involved with accomplishing this using jQuery.




The solution works as follows: 

  1. Query a SharePoint list, building a list of tags  
  2. Use jQuery to create a tag cloud from the list
  3. When the user clicks a tag query the list finds all items that contain that tag
  4. Pop a jQuery dialog box with all the forms matching the tag (this gets around having to navigate to another page to see the tag search results).

One caveat: this solution will only work on one list.  It will not roll up tags from multiple lists across sites or site collections.

I have the following tools to help me accomplish this:

  1. SPServices : http://spservices.codeplex.com/ 
  2. DynaCloud jQuery plugin  http://johannburkard.de/blog/programming/javascript/dynacloud-a-dynamic-javascript-tag-keyword-cloud-with-jquery.html
  3. U2U CAML Builder: http://www.u2u.be/res/tools/camlquerybuilder.aspx

We have packaged up our InfoPath forms and deployed them as features.  In order to help the users locate the forms we have created a content type called eForm Locator.  The purpose of this content type is to store information about the forms including the owner, department, the URL of the form and any associated tags.  This will allow us to display the information in a variety of ways and allow the users to navigate directly to a new form instance.


The first thing we need to do is create a new page to host our magnificent creation.  Place a Content Editor Web Part on the screen and put in your jQuery references.  You have built your Scripting Resource Center – right??  http://www.endusersharepoint.com/2010/01/05/build-a-sharepoint-scripting-resource-center/

<script type="text/javascript" src="http://URL/sprc/Resources%20%20jQuery/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="http://URL/sprc/Resources%20%20jQuery/jquery-ui-1.7.1.min.js"></script>
<script src="http://URL/sprc/Resources%20%20jQuery/jQuery%20SP%20Services/jquery.SPServices-0.5.4.min.js" type="text/javascript"></script>
<script src="http://URL/sprc/Resources%20%20jQuery/jQuery%20DynaCloud/jquery.dynacloud-5.js"></script>
<link rel="stylesheet" href="http://URL/sprc/Resources%20%20jQuery/jquery-ui-themes-1.7.1/excite-bike/jquery-ui.css" type="text/css">

The next step is to add another CEWP to the page and prepare to get our hands dirty!

All the code will be listed at the bottom of the article so for now we’ll just break it into manageable chunks.

Firstly – we need to query the eForm Locator list in order to build our list of tags.  This is where we use Marc’s SPServices library.  Just for the record Marc – when we finally meet I will be kissing you.  Be forewarned.  For those of you that have not used this you are missing out.

$().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "eFormLocator",
    CAMLViewFields: "<ViewFields><FieldRef Name='Tags' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName=z:row]").each(function() {

         $('#CloudContent').append($(this).attr("ows_Tags").replace(/;/g, " "));

         $('#CloudContent').append(" ");

      });

    }
  });

As we loop through the results we are appending the results of the tags field (replacing the “;” separators with spaces) to a DIV element with an ID of CloudContent.

We then simply call the DynaCloud plugin and let it do its magic.   Check the link above for more complete documentation on this plugin.

$.dynaCloud.sort = true;
   $("div.dynacloud").dynaCloud();
   $('#CloudContent').hide();

At this point our cloud is lazily floating on our page looking lovely.  But it doesn’t actually do anything yet.  The original intention of the DynaCloud plug in was to create a tag cloud out of a section of text on a web page and then highlight it when the tag is clicked.  Since that does us no good we’ll need to make a change to the plugin.




As seen above, instead of highlighting the text, we want to pop open a dialog with the search results.  So we’re going to call a function called queryTagList that is on our page.  This function is not as complicated as it looks so we’ll run through it step by step.

  1. Clear our DIV that will be used to populate the jQuery dialog
  2. Query the eForm locator list using SPServices.  We want to filter the results by the tag that was clicked and order them by the title of the Form.  Thank you U2U CAML Query Builder!
  3. We then use the results to build some HTML that will populate the contents of the dialog box and call the jQuery to pop it open.  When one of the links is clicked it will open the eForm in a new page and then close the dialog.
function queryTagList(textToQuery)
{

  $('#dialog').html("");

  $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "eFormLocator",
    CAMLQuery: "<Query> \
   <Where> \
      <Contains> \
         <FieldRef Name=\"Tags\" /> \
         <Value Type=\"Text\">" + textToQuery + "</Value> \
      </Contains> \
   </Where> \
   <OrderBy> \
      <FieldRef Name=\"Title\" Ascending=\"True\" /> \
   </OrderBy> \
</Query>",
    CAMLViewFields: "<ViewFields><FieldRef Name='Tags' /><FieldRef Name='eForm_x0020_URL' /><FieldRef Name='Title' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName=z:row]").each(function()    {

      if ($(this).attr("ows_Tags").indexOf(textToQuery) > -1)
      {
         //We want the dialog to close when someone opens a form
         var mouseup = "$('#dialog').dialog('close');";

         var url = "<div><a onmouseup=" + mouseup  + "  target='_blank' href='" + $(this).attr("ows_eForm_x0020_URL").substring(0, $(this).attr("ows_eForm_x0020_URL").indexOf(",")) + "'>" + $(this).attr("ows_Title") + "</a></div>"

         $('#dialog').append(url)
         $('#dialog').dialog('option','show', 'blind');
         $('#dialog').dialog('option', 'width', 900);
         $('#dialog').dialog('option', 'height', 400);
         $('#dialog').dialog('open');

      }

In this article we have used a variety of tools and jQuery plugins to build a single-list tag cloud populated with SharePoint data completely on the client.  Thanks to all the developers that created these plugins that made this task so much easier.

Full Code

<script language="javascript" type="text/javascript">

var strTags = "";

$(document).ready(function() {

jQuery("#dialog").dialog({
      bgiframe: true, autoOpen: false,  modal: true, show: 'slide'
    });

  $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "eFormLocator",
    CAMLViewFields: "<ViewFields><FieldRef Name='Tags' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName=z:row]").each(function() {

         $('#CloudContent').append($(this).attr("ows_Tags").replace(/;/g, " "));

         $('#CloudContent').append(" ");

      });

    }
  });

   $.dynaCloud.sort = true;
   $("div.dynacloud").dynaCloud();

   $('#CloudContent').hide();
});

function queryTagList(textToQuery)
{

  $('#dialog').html("");

  $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "eFormLocator",
    CAMLQuery: "<Query> \
   <Where> \
      <Contains> \
         <FieldRef Name=\"Tags\" /> \
         <Value Type=\"Text\">" + textToQuery + "</Value> \
      </Contains> \
   </Where> \
   <OrderBy> \
      <FieldRef Name=\"Title\" Ascending=\"True\" /> \
   </OrderBy> \
</Query>",
    CAMLViewFields: "<ViewFields><FieldRef Name='Tags' /><FieldRef Name='eForm_x0020_URL' /><FieldRef Name='Title' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName=z:row]").each(function()    {

      if ($(this).attr("ows_Tags").indexOf(textToQuery) > -1)
      {
         //We want the dialog to close when someone opens a form
         var mouseup = "$('#dialog').dialog('close');";

         var url = "<div><a onmouseup=" + mouseup  + "  target='_blank' href='" + $(this).attr("ows_eForm_x0020_URL").substring(0, $(this).attr("ows_eForm_x0020_URL").indexOf(",")) + "'>" + $(this).attr("ows_Title") + "</a></div>"

         $('#dialog').append(url)
         $('#dialog').dialog('option','show', 'blind');
         $('#dialog').dialog('option', 'width', 900);
         $('#dialog').dialog('option', 'height', 400);
         $('#dialog').dialog('open');

      }

      });

    }
  });

}
</script>

<div id="CloudContent" class="dynacloud"></div>
<div id=dynacloud></div>
<div id=dialog Title="eForm Tag Search Results"></div>

Guest Author: Jason MacKenzie
Intelligence Among Us

Jason has been an IT professional for 12 years and has worked in a variety of roles from software development to managing business solutions for a large international automotive supplier. He has developed mission critical software solutions for the manufacturing industry and has experience in the government and educational fields as well.

Jason is a social networking enthusiast and is currently working as an independent SharePoint architect. Jason helps organizations with strategy and implementation guidance related to  architecture, governance, processes as well as hand-holding and facilitating a good group cry every now and again. Jason’s goal is to actively participate in the community and share what he has learned in order to help people and business leverage their investment in this critical platform.

View all entries in this series: Use jQuery to»
 

Please Join the Discussion

14 Responses to “Use jQuery to Create a Tag Cloud”
  1. Henning says:

    Hi,

    cool way to get a tagcloud – but what did you do to trigger the “queryTagList” function? Unfortunatly your screenshots are not helpful, since they have a to high resolution.

    • Hi there,

      My apologies for the image quality. You need to modify the code in the DynaCloud plugin. If you look at the last lines of code in the plugins .js file you want to make the modifications as follows:

      //var text = jQuery(this).text().toUpperCase();
      var text = jQuery(this).text();
      jQuery(target).each(function() {
      // jQuery(this).highlight(text);
      queryTagList(text);

  2. Bil Simser says:

    Pretty cool solution. I’m actually really interested in the eForms locator content type now and want more details about how that works?

  3. Hi Bill,

    We are doing a fairly large forms migration for a regional government. There are many sites and forms libraries all with different security requirements. The intention is to allow people, from one web page to be able to find whatever form they are looking for.

    So we created the eForm Locator (horrible name I know) which is nothing more than a lot of different metadata about the forms including the URL to a new instance of the form. This way we can tag them, organize them by department, service area etc. which will allow people to find them more easily. We’re also using some workflows to keep a tally of the number of forms so we can show people the most popular forms that are being used.

    Jason

  4. Walter says:

    I’m trying to apply this to my blog and would assume that I would change…

    eFormLocator > Posts
    Tags > Category
    ows_Tags > PostCategory
    eForm_x0020_URL > Title

    Am I missing something?

    • If you are talking about an out of the box blog you pretty much have it. The Posts list has a column called category which would be accessed using jQuery as ows_Category.

      Title is not going to do it for you as you want to link directly to the post which adds the ID to the querystring. So grab the ID field and build your URL accordingly.

      Does that answer your question?

  5. Brett says:

    Hi Jason,

    Love this idea as many of us don’t have server-side access or the authority to install 3rd Party Web-Parts.

    Are you able to provide the details to use this in a generic List?
    I’m trying to get this working for a Discussion List, Wiki Page, basically any list within SharePoint.

    So with Fields: ID, Title, Text, Type
    Could you fill in the blanks below please?

    eFormLocator =
    Tags =
    ows_Tags =
    eForm_x0020_URL =

    Thanks,

    Brett

    • Brett says:

      Jason,

      I’ve almost got it. The Tag Cloud displays at the top of the list, I click on the Tag and a pop-up window displays showing the Title’s that have the Tag names for that item.
      I click on an item in the pop-up window and it goes to a blank window with about:blank in the address bar.

      So basically, I just require the code or format for the eForm_x0020_URL field.
      Hovering over the Title in the Pop-up window displays a link to the List where the CEWP resides.
      http://teamweb/sites/Golf/Lists/TagsList

      I’ve replaced, eFormLocator = Listname
      Tags = Keywords (column with categories and keywords)
      ows_tags = ows_keywords
      Title = Title
      eForm_x0020_URL = ???

      I’m very new to Jquery, so you may have to dumb it down for me.

      Thanks.

      Brett

  6. In my case the eForm URL column was a link directly to a new instance of an InfoPath form so the form could be opened directly in a new window.

    In your case it seems like you will need to get the link directly to the list item. You could do this by pulling back the ID column in your CAML Query to SPServices and append that onto the URL of of the list item dispform.aspx like

    url = ‘urlToYourList/DispForm.aspx?ID=’ + $(this).attr(”ows_ID”).

Trackbacks

Check out what others are saying about this post...
  1. [...] is a follow up to my previous post related to building a Tag Cloud using jQuery.   My client is moving a large amount of forms from Lotus Notes to MOSS and InfoPath 2007 [...]




Notify me of comments to this article:


Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!