Second Life of a Hungarian SharePoint Geek

January 21, 2010

Displaying results in multiple columns using the Content Query Web Part

Filed under: CQWP, SharePoint — Tags: , — Peter Holpar @ 10:14

It’s a rather common request to display CQWP results in multiple columns. In this post I will show you how to do that by altering the ItemStyle.xsl and the ContentQueryMain.xsl files. Check out and open both of these files in Style Library / XSL Style Sheets folder using SharePoint Designer 2007.

If you don’t have experience in customizing XSL style sheet files, I recommend you to read the following articles first:

How to: Customize XSL for the Content Query Web Part

Customizing the Content Query Web Part and Custom Item Styles

The solution described here is only one of the possible solutions, you can achieve the same result applying different techniques.

First we edit the ContentQueryMain.xsl and add a new parameter LastRow in the call-template of the OuterTemplate.CallItemTemplate to pass the number of the last row at line 120 (assuming it is the original ContentQueryMain.xsl without customization).

Before modification:

  1. <xsl:call-template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:with-param name="CurPosition" select="$CurPosition" />
  3. </xsl:call-template>

After modification:

  1. <xsl:call-template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:with-param name="CurPosition" select="$CurPosition" />
  3.   <xsl:with-param name="LastRow" select="$LastRow" />
  4. </xsl:call-template>

We should also modify the OuterTemplate.CallItemTemplate template to be able to receive the new parameter value. We add the new  LastRow parameter at line 135.

Before modification:

  1. <xsl:template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:param name="CurPosition" />

After modification:

  1. <xsl:template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:param name="CurPosition" />
  3.   <xsl:param name="LastRow" />

We have to pass the value of the LastRow parameter as well as the CurPosition parameter that is the number of the actual row to our item template. We will call our template News, and add the following block to the OuterTemplate.CallItemTemplate template just before the otherwise block at line position 152. Note that the value of the CurPosition parameter will be passed further in the CurPos parameter to fit to the existing naming conventions of the style XSL files.

  1. <xsl:when test="@Style='News'">
  2.   <xsl:apply-templates select="." mode="itemstyle">
  3.     <xsl:with-param name="CurPos" select="$CurPosition" />
  4.     <xsl:with-param name="LastRow" select="$LastRow" />
  5.   </xsl:apply-templates>
  6. </xsl:when>

After the preparation of the ContentQueryMain.xsl file, we should create the News item style itself in the ItemStyle.xsl. The following XML fragment illustrates a possible formatting. Of course, you are free to modify that, keeping the main points in your mind.

In the first example we create two columns. We use the values of CurPos parameter and the LastRow parameter to decide what special table formatting should be applied.

We create the table header for the first row, table footer for the last row, table row opening for odd rows and table row closing for even rows. We use the mod operator to check if an item represents an even or an odd row.

  1. <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
  2.   <xsl:param name="CurPos" />
  3.   <xsl:param name="LastRow" />
  4.   <xsl:variable name="SafeLinkUrl">
  5.     <xsl:call-template name="OuterTemplate.GetSafeLink">
  6.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  7.     </xsl:call-template>
  8.   </xsl:variable>
  9.   <xsl:variable name="SafeImageUrl">
  10.     <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
  11.       <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  12.     </xsl:call-template>
  13.   </xsl:variable>
  14.   <xsl:variable name="DisplayTitle">
  15.     <xsl:call-template name="OuterTemplate.GetTitle">
  16.       <xsl:with-param name="Title" select="@Title"/>
  17.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  18.     </xsl:call-template>
  19.   </xsl:variable>
  20.   <xsl:variable name="LinkTarget">
  21.     <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
  22.   </xsl:variable>
  23.  
  24.   <xsl:if test="$CurPos = 1 ">
  25.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;</xsl:text>
  26.   </xsl:if>
  27.   <xsl:if test="$CurPos mod 2 = 1">
  28.     <xsl:text disable-output-escaping="yes">&lt;tr&gt;</xsl:text>
  29.   </xsl:if>
  30.  
  31.  
  32.   <td width="50%" valign="top">
  33.     <table width="90%">
  34.       <tr height="27px" valign="top">
  35.         <td>
  36.           <span>
  37.             <a href="{$SafeLinkUrl}">
  38.               <xsl:value-of select="@Title"/>
  39.             </a>
  40.           </span>
  41.           <span>
  42.              <xsl:value-of select="ddwrt:FormatDateTime(@ArticleStartDate, 1033, 'MM-dd-yyyy')"/>
  43.           </span>
  44.         </td>
  45.       </tr>
  46.       <tr height="35px" min-height="35px" valign="top">
  47.         <td>
  48.           <span>
  49.             <xsl:if test="string-length($SafeImageUrl) != 0">
  50.               <div class="image-area-left">
  51.                 <a href="{$SafeLinkUrl}" target="{$LinkTarget}">
  52.                   <img class="image" width="100px" height="100px" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
  53.                 </a>
  54.               </div>
  55.             </xsl:if>
  56.             <xsl:value-of select="substring(@Comments,0,200)"/>
  57.             <xsl:if test="string-length(@Comments) &gt; 200"></xsl:if>
  58.           </span>
  59.           <a href="{$SafeLinkUrl}"> Details…</a>
  60.         </td>
  61.       </tr>
  62.  
  63.     </table>
  64.   </td>
  65.  
  66.   <xsl:if test="$CurPos mod 2 = 0">
  67.     <xsl:text disable-output-escaping="yes">&lt;/tr&gt;</xsl:text>
  68.   </xsl:if>
  69.   <xsl:if test="$CurPos = $LastRow ">
  70.     <xsl:text disable-output-escaping="yes">&lt;/table&gt;&lt;/div&gt;</xsl:text>
  71.   </xsl:if>
  72. </xsl:template>

Note the text elements having disable-output-escaping="yes". We should use these elements since the XSL must be a well formed XML, so we cannot add unclosed or unopened HTML tags.

Don’t forget to add the ddwrt XML namespace to the stylesheet to enable date formatting and save both of the files.

xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime

If you don’t have content on your publishing site, create a few articles, and add a CQWP to one of your pages to aggregate the pages. You should also add the ArticleStartDate field to the CQWP CommonViewFields, to be sure it is included in the result:

<property name="CommonViewFields" type="string">ArticleStartDate,DateTime;</property>

If you don’t know how to do that, refer to this article:

How to: Customize the Content Query Web Part by using Custom Properties

Also, set the Item style of the CQWP to News.

image

After these modifications, you should see something like that:

image

If the result is matching your expectations, do not forget to check in the ItemStyle.xsl and the ContentQueryMain.xsl files and publish the page with the CQWP to make the changes visible to visitors.

Let’s improve our style a bit. If you need more columns, you can apply the same mod operator to get the information if a table row starting or row closing HTML tag must be added, just use the number of the columns instead of the constant 2 used in the sample above, and decrease the column with of 50% used to divide the full with into two, for example, you can use 33% for three columns.

But it would be better if you would not have to bother with the internals of the template, but use a constant variable in the XML.

For the sake of simplicity and to avoid mismatches I include the entire item style, although it does not differ significantly from the previous version.

  1. <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
  2.   <xsl:param name="CurPos" />
  3.   <xsl:param name="LastRow" />
  4.   <xsl:variable name="SafeLinkUrl">
  5.     <xsl:call-template name="OuterTemplate.GetSafeLink">
  6.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  7.     </xsl:call-template>
  8.   </xsl:variable>
  9.   <xsl:variable name="SafeImageUrl">
  10.     <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
  11.       <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  12.     </xsl:call-template>
  13.   </xsl:variable>
  14.   <xsl:variable name="DisplayTitle">
  15.     <xsl:call-template name="OuterTemplate.GetTitle">
  16.       <xsl:with-param name="Title" select="@Title"/>
  17.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  18.     </xsl:call-template>
  19.   </xsl:variable>
  20.   <xsl:variable name="LinkTarget">
  21.     <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
  22.   </xsl:variable>
  23.  
  24.   <xsl:variable name="ColNum">3</xsl:variable>
  25.  
  26.   <xsl:if test="$CurPos = 1 ">
  27.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;</xsl:text>
  28.   </xsl:if>
  29.   <xsl:if test="$CurPos mod $ColNum = 1">
  30.     <xsl:text disable-output-escaping="yes">&lt;tr&gt;</xsl:text>
  31.   </xsl:if>
  32.  
  33.  
  34.   <td valign="top">
  35.     <xsl:attribute name="width">
  36.       <xsl:value-of select="round(100 div $ColNum) + '%'" />
  37.     </xsl:attribute>
  38.     <table width="90%">
  39.       <tr height="27px" valign="top">
  40.         <td>
  41.           <span>
  42.             <a href="{$SafeLinkUrl}">
  43.               <xsl:value-of select="@Title"/>
  44.             </a>
  45.           </span>
  46.           <span>
  47.              <xsl:value-of select="ddwrt:FormatDateTime(@ArticleStartDate, 1033, 'MM-dd-yyyy')"/>
  48.           </span>
  49.         </td>
  50.       </tr>
  51.       <tr height="35px" min-height="35px" valign="top">
  52.         <td>
  53.           <span>
  54.             <xsl:if test="string-length($SafeImageUrl) != 0">
  55.               <div class="image-area-left">
  56.                 <a href="{$SafeLinkUrl}" target="{$LinkTarget}">
  57.                   <img class="image" width="100px" height="100px" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
  58.                 </a>
  59.               </div>
  60.             </xsl:if>
  61.             <xsl:value-of select="substring(@Comments,0,200)"/>
  62.             <xsl:if test="string-length(@Comments) &gt; 200"></xsl:if>
  63.           </span>
  64.           <a href="{$SafeLinkUrl}"> Details…</a>
  65.         </td>
  66.       </tr>
  67.  
  68.     </table>
  69.   </td>
  70.  
  71.   <xsl:if test="$CurPos mod $ColNum = 0">
  72.     <xsl:text disable-output-escaping="yes">&lt;/tr&gt;</xsl:text>
  73.   </xsl:if>
  74.   <xsl:if test="$CurPos = $LastRow ">
  75.     <xsl:text disable-output-escaping="yes">&lt;/table&gt;&lt;/div&gt;</xsl:text>
  76.   </xsl:if>
  77. </xsl:template>

The main change is that we introduced a new variable called ColNum, and set its value to 3, just to alter the original two-column behavior. We use the value of this parameter when applying the mod operator, and instead of having a fixed with of the table cell we compute that using the formula round(100 div $ColNum) + ‘%’.

Let’s save the new version and see the result!

image

If we change the value of the ColNum parameter to 4, after saving the file we get the following result:

image

Well, of course, we could make it even better and have the value of the ColNum variable from a template parameter, but I let you to do that improvement alone if you really need that kind of flexibility.

About these ads

27 Comments »

  1. I done my web part using the steps given in the site but i am facing error this error is

    “Unable to display the web part.To Troubleshoot the Problem,Open this web page in HTML editor or SPD.If the Problem Persists,Contact your web server administrator”

    Can you please solve this issue ???? Siva …..

    Comment by Sambasivarao — February 22, 2010 @ 10:57

  2. Hi Sambasivarao,

    There might be several kind of error that cause this message.

    Be sure, you have included the xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime namespace in ItemStyle.xsl.

    Save the ItemStyle.xsl and the ContentQueryMain.xsl files, and export the web part as an XML file, and check all of these files for possible XML format errors, for example, by opening the files in Internet Explorer.

    If it does not solve the issue, revert to the original files, and do the changes step by step again, checking the result in the browser after each step.

    Peter

    Comment by pholpar — February 22, 2010 @ 23:52

  3. Hello Pholpar,
    Thanks for reply, i tried as you mentioned in the mail but still facing problem with the same error i placed xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime in the ItemStyle.xsl but still facing error can you please help me to resolve this issue

    Comment by sambasivarao — March 8, 2010 @ 18:33

  4. Hello Peter,
    Thanks for your reply i done it now its working fine in my portal and thanks for helping me to resolve my issue anyway nice discussion

    sambasivarao

    Comment by sambasivarao — March 9, 2010 @ 13:41

    • Hi Sambasivarao,

      Nice to hear that it is working now. Sorry I was not able to help you more effectively than sending a few links.

      Peter

      Comment by pholpar — March 10, 2010 @ 13:41

  5. hmm.. but multi column output is out of box option in CQWP.. check it out

    Comment by Sandeep — March 24, 2010 @ 21:35

    • Hi Sandeep,

      Thanks for your comment!

      Do you mean the “Number of columns” option? AFAIK that is available only when you have groupped the results. Without groupping it is not possible OOB. Let me know if I’m wrong.

      Peter

      Comment by pholpar — March 25, 2010 @ 09:31

  6. Thanks!

    This was exactly what I was looking for. You saved my day.

    Comment by karthik — August 16, 2010 @ 07:47

  7. Hi,
    i use your example but i run in Internet Explorer 7 and at the begining appear more spaces.In IE8 works ok.Do you know how to fix this in IE7?
    Thanks!

    Comment by Catalin — December 24, 2010 @ 09:16

  8. It look’s fine in IE, but in firefox appears unformatted.

    Comment by Bruno — January 21, 2011 @ 12:02

  9. Hello Peter,
    What would be the solution in case if we wanted to display the articles in vertical (row column fasion) i.e. The result shld appear like:

    1 5
    2 6
    3 7
    4 8

    Instead of the way youhave in your example:

    1 2
    3 4
    5 6

    Comment by Ketan — February 7, 2011 @ 18:02

  10. Dear Peter,

    I want to display the data in 2 columns format as per your example given, but I have some addtional requirement.
    I want that each cell of the table contains its group header and subitems of that soecific group under the same cell.

    Do u get me ??

    Comment by Ali — May 3, 2011 @ 05:56

    • Hi Ali,

      If you have additional requirements, feel free to use the existing example and alter it to much your needs.

      Peter

      Comment by Peter Holpar — May 7, 2011 @ 21:53

  11. Dear Peter,
    Jus as an extension to this example, Can v do paging using these 2 xsl.

    Comment by Sheena datta — May 19, 2011 @ 05:58

    • Hi Sheena,

      If you need paging you probably have to work with an extended version of the content query web part, like this one from Waldek.

      Peter

      Comment by Peter Holpar — May 19, 2011 @ 07:09

      • I saw this post even. but I need to work OUT-OF-BOX. Can u suggest?

        Comment by Sheena datta — May 19, 2011 @ 09:59

      • AFAIK, one cannot do that OOB. If one could, there would have been no need for Waldek to create a custom solution.

        Comment by Peter Holpar — May 19, 2011 @ 10:08

  12. Hello Peter,

    Great post! No problems implementing at all! I do, however, have one question.

    Is it possible for you to point me in the right direction for alternating row styles? I’m beating myself up on this!

    Thanks,

    Scott

    Comment by Scott — June 7, 2011 @ 19:33

  13. your are real genious. thank you very much

    Comment by leo — August 8, 2011 @ 02:41

  14. Hi, this is a lovely article. makes life very easy. thanks.
    i have replicated this on my local sharepoint server 2010 and it works perfectly.
    i have a migrated site (from MOSS2007 to sharepoint 2010). when i replicate the same thing on the migrated site it does not work. the places where we are supposed to enter Link, Image, Title, ArticleDate and Comments, these options don’t come instead Link, Image, Title, and some other fields instead of the ones which we should have got for this code. please help.

    Comment by badhon — December 14, 2011 @ 11:21

  15. For SharePoint application developers who want to:

    > Add any (sub)Site(s) all over the SiteCollection
    > Query any Content Type(s)
    > Add any Column(s) in no time
    > Change style to any Layout without deploying anything

    Here is a project on CodePlex: http://enhancedcqwp.codeplex.com/

    Comment by Hans — April 6, 2012 @ 15:26

  16. Hi,
    Great Article!

    I just implemented the above solution (the last one, that allow to dynamically choose how many columns you want) on SP 2010 but, looking at the generated HTML code I saw that the calculated width attribute was wrong. So I replaced the statement with

    Regards
    Roberto

    Comment by sharepoint360 — April 9, 2012 @ 08:39

  17. …the statement did not get displayed…

    replaced round(100 div $ColNum) + ‘%’
    with
    concat(round(100 div $ColNum), ‘%’)

    Comment by sharepoint360 — April 9, 2012 @ 08:40

  18. Hi,
    We have implemented this work around for one of my requirements. It is displaying fine in IE8 and new ones but it is having extra spaces in IE7. Also the formatted html is having some extra in valid elements.
    I have removed the additional html markup by following this article:

    http://blog.mastykarz.nl/optimizing-output-content-query-web-part/

    but there are still some additional elements which are getting added and are messing up the applied styling.
    Here is an example of such invalid elements:

    Any suggestions?

    Comment by svs — August 30, 2012 @ 13:38


RSS feed for comments on this post. TrackBack URI

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

The Shocking Blue Green Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 53 other followers

%d bloggers like this: