Skip to content

SharePoint Blog Tag Cloud

March 10, 2011

SharePoint 2010 comes with a new Tag Cloud web part. The Tag Cloud Web Part works with social tags only.

In my SharePoint blog site “tagging” the blog posts with categories does not a Tag Cloud entry makes…  and I really wanted that to work right out of the box.  Well, you get what you get and you make the rest.

The Challenge

We want to show a Tag Cloud for the categories assigned to blog posts.  The tag cloud should include the list of categories in the blog posts such that the font size is directly related to the frequency of the category use in posts.

There are two tasks that we want to accomplish to answer this challenge:

  1. Get a list of categories and a count of how many times each category is used across all posts in the blog
  2. convert the list of categories and frequencies to a tag cloud.

There are a couple of pretty good jQuery tag cloud plugins and bits of codes out there.   A pretty cool 3D scrolling Tag Cloud can be found in this link.   A list-based or spherical tag cloud plug-in is found in this link.  In this post I will make use of the latter, but feel free to use your favorite plugin for that purpose.

I am going to impose some basic restrictions in order to make this solution usable in as-broad-as-possible context:

  • No server deployment – many people don’t have access to deploy server-side code
  • No Changes to lists – it is possible to create columns with count (but that require server deployment)

No SharePoint Designer changes. Repeat after me “Customized pages are evil!”.

We also want to present a create a complete solution, not a pattern.  That said, our solution can also be used as sort of a pattern to work with similar cases.

Getting Categories and Frequency

SharePoint 2010 maintains the list of distinct categories in a list called Categories. The categories associated with each post are stored in a field titled Categories.  This field is a lookup field with multiple selections.

The secret to grabbing the category list is understanding how SharePoint stores Lookup column values with multiple selections.

Unlike a relational database, SharePoint stores the entries as a delimited string with the following format:

<id>;#<Title>;#<id>;#<title>

so a typical entry in a blog about frog legs may look like this

23;#French Cooking;#45;#Frogs;#51;#Exotic Foods

The beauty of this arrangement is that we don’t need to go the original list to find the names of the categories. (there are lots of ugly sides to this as well, but we are going to let it go for now.)

Blog posts are stored in a list called Posts.  Our algorithm is therefore as follows:

  1. Get Categories field for all blog posts in the Posts list
  2. Concatenate all category names from all blog posts (without the id’s)
  3. sort the list alphabetically
  4. cycle through the array.  Compare to previous entry and increase a counter until a new entry is found.
  5. Store entries and count in a list

Solution Implementation

The first part of our solution is to call SharePoint Lists web service to get all list items for the Posts list.  (I like to separate the SOAP envelope for the call, which really obstruct the actual code.   I provide the that piece of plumbing in the complete solution attached at the end of the blog.)

The call to get the items using the sharepoint.js helper file looks like this:

$(function(){
    var options = {"listName" : "Posts",
    "query" : "",
    "viewFields" : "<ViewFields><FieldRef Name='PostCategory' /></ViewFields>"};

    $.ajax({
        type: "POST",
        url: SharePoint.Services.Lists,
        data: SharePoint.getEnvelope(SharePoint.Operations.getListItems, options),
        datatype: "xml",
        contentType: "text/xml; charset=\"utf-8\"",
        success: processResult,
    });
})

Note that the actual name of the field is PostCategory, and that is the only field of interest for us for this application.

When we get the results we collect the list of categories:

var categoryArr = Array();
$("[nodeName=rs:data]", xData).find("[nodeName=z:row]").each(function () {
    var c = $(this).attr("ows_PostCategory");
    categoryArr.push(c.replace(/(\d+);#([^;]+)/g, "$2|$1")) ;
});

we start by converting the delimited string in the form of <id>;#<name>;#<id>;#<name> to a delimited string in the form <name>|<id>;#<name>|<id>.  That will allow us to keep the ID, but sort by name in the following steps.

Next, we combine all array entries and parse it out to a new array.  Each entry in the new array will have the format <name>|<id>.  We proceed to sort the array to line it up for the count:

 var categories = categoryArr.join(";#");
   categoryArr = categories.split(";#");
   categoryArr.sort();

Counting the entries is pretty low-tech javascript affair:

 var oldCat = categoryArr[0];
   var cnt = 0;
   for (var i=0;i<categoryArr.length;i++) {
       cat = categoryArr[i];
       if (cat == oldCat) { cnt++; }
       else { // found new entry var entry = oldCat.split('|');
           $("#cloud").append(listItem(entry[1], entry[0], cnt));
           oldCat = cat;
           cnt = 1;
       }
       // end it now for last entries if (i == categoryArr.length - 1) {
             var entry = oldCat.split('|');
           $("#cloud").append(listItem(entry[1], entry[0], cnt));
       }
   }

The HTML should contain a UL with a cloud class name.

The cloud plug-in is the last step of the processing:

$("#cloud").tagcloud({height: "120", type: "cloud", sizemin: 10 });

We add a new list item (LI) for each unique category along with the weight of the entry and a link to the Category.aspx, that is a built-in page that takes the ID and name of the category to display all related posts:

function listItem(id, name, val) {
    var link = "<a style='text-decoration : none;' href='/Lists/Categories/Category.aspx?CategoryId=" + id + "&Name=" + name + "'>" + name + "</a>";
    return "<li value='" + val + "' id='" + id + "'>" + link + "</li>";
}

Putting It All together

Deployment of the code to your SharePoint site consists of copying the files to a document library and referencing them from a Web Content web part.

There are 3 files in the package: 2 script files and 1 html file.  All files can go in the same library, but a better practice it to put the scripts in a separate “scripts” library – just because…  (if you do put them in the same library, change the references for the JS files.)

Put a content editor web part on a page and type the name of the html file in the link box.  You probably want to also turn off the “chrome” under the Appearance tab.

tagcloud

Another option is to copy the content of the HTML file into the control itself.

Finally

Here is a link to the code files referenced in the article.

Advertisements
3 Comments
  1. very cool

    Thanks!!

  2. Rahim Khowaja permalink

    I have implement it but not working

  3. Rahim Khowaja permalink

    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.3)
    Timestamp: Tue, 6 May 2014 12:32:05 UTC

    Message: Expected identifier, string or number
    Line: 22
    Char: 5
    Code: 0
    URI: http://mosspa2/Style%20Library/SPTagCloud/Pages/cloud.htm

    This error came when clink link in content editor webpart

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

%d bloggers like this: