An expanded version of this article, along with many other customization examples and how-tos can be found in my book, SharePoint 2007 and 2010 Customization for the Site Owner.
12/19/09 Updated! More pictures and some more detail in the steps.
12/19/09 Expand Collapse bug found and fixed! (not my bug, SharePoint’s bug!) See here…
1/30/11 SharePoint 2010 version of this article. See here…
Group By on more than 2 columns in a view
In my SharePoint classes I have often been of asked how to group on more than two levels in a view. I have always given the quick answer of "use SharePoint Designer"!
But, some of you have asked "How?". You may be sorry you asked… but here goes…
Goals:
- Create a view with nested groups deeper than just 2 levels
- Put the counts and totals at the bottom of each section.
- Do the above with no custom web parts, custom XSLT or anything that has to be deployed to the server.
Sample:
Secrets and Tricks needed:
- It can't be done "out of the box" in the browser
- SharePoint Designer is needed to make the edits
- You need to convert the view web part to a XSLT Data View (SharePoint Designer's Data View web part)
- You need a Sort and Group secret
- You need to fix the footer rows
- You need to manually add your totals, averages, counts etc.
My Example:
- I have a simple list (actually imported from Excel) with these columns: ID1, Bike, BikeType, BikeSize, BikeColor and Retail (price).
- I want to group this on BikeType, BikeSize, BikeColor and count the items and sum or average the price in each group.
Steps: (and yes, a lot of them!)
- Tip: There are many, many options available in the Data View Web Part used here. For the first time through this process don't change any options not listed below. You can always come back and experiment with the rest of the options later!
- Create a new Standard View from the list's view menu.
Generally don't bother with any options other than selecting the desired columns.- Don't set any grouping options, they will mess up the expand / collapse functionality
- Don't set up any Totals options, they will be ignored
- Do select the columns needed in your view, both display and grouping
- Optionally set the filter options (this can also be done in SharePoint Designer)
The “before” – just a standard view with selected columns:
- Don't set any grouping options, they will mess up the expand / collapse functionality
- Open your site with SharePoint Designer and expand the Lists node in the Folder List pane.
- Expand your list's node and double-click on your new view.
- If your view page is not being displayed in the Design view, click the Design tab at the bottom of the page.
- Note: the view is now being displayed using a ListViewWebPart and can only be customized from the browser ("Modify View")
- Right-click in the middle of the view and select Convert to XSLT Data View.
- Note: the view is now being displayed using a DataFormWebPart and
- is no longer a “View” and can not longer be modified from the “Customize this view”
- can be customized from SharePoint Designer,
- from the browser you can only rename the view,
- from the browser you can also use Site Actions, Edit Page, Modify Shared Web Part to hand edit the XSLT,
- going forward, columns added to the list will not be added to the DataFormWebPart.
- is no longer a “View” and can not longer be modified from the “Customize this view”
- Your data should now be displayed.
- You could also fix up the display of the data (right align some columns, rename column headings, select color, bold, etc)
- You could also fix up the display of the data (right align some columns, rename column headings, select color, bold, etc)
- Save! At this point you may want to click Save and review the results so far in a browser. Review the formatting and note the things you need to change. This will then be an unghosted, or customized, page.
-
- Now add the Sorting and Grouping options…
- For my example I am first grouping on BikeType, then by BikeSize and BikeColor
- For my example I am first grouping on BikeType, then by BikeSize and BikeColor
- Right-click the web part and select Show Common Control Tasks (or click the pop-out arrow at the top right corner of the control The pop-out is named “Common Data View Tasks”).
- Click “Sort and Group”
- Remove any sort fields listed (usually one)
- Add your top most group:
- Click the field (BikeType) and
- Click Add
- Click “Show group header”
- Click Collapse group (optional)
- Click “Show group footer” (if you want counts and totals)
- Click the field (BikeType) and
- Add your second group by clicking the field (Example: Size) and clicking Add.
- If you stop here you will have groups, but all of your counts and totals will be wrong! We need to create both the text to display for the group and a hierarchy for the grouping. At the second level of our grouping we need to group on the combination of both columns, “Bike Type” plus “Size”
- Click “Edit Sort Expression”
- At a minimum you will need to concatenate the current grouping column with the previous grouping columns, and while you are at it you can add some formatting:
- Enter: concat(@Bike_x0020_Type, " - ", @Size) (Watch the capitalization! Use the exact name the Intelisense offers – spaces are “coded” so “Bike Type” is “Bike_x0020_Type”.)
- Note the preview at the bottom of the dialog box…
- Click OK
- Click Show group header
- Click Collapse group (optional)
- Click Show group footer (if you want counts and totals)
- At a minimum you will need to concatenate the current grouping column with the previous grouping columns, and while you are at it you can add some formatting:
- If you stop here you will have groups, but all of your counts and totals will be wrong! We need to create both the text to display for the group and a hierarchy for the grouping. At the second level of our grouping we need to group on the combination of both columns, “Bike Type” plus “Size”
- For the third and following groups repeat the step above with Sort Expressions similar to:
- concat(@Bike_x0020_Type, " - ", @Size, " - ", @Bike_x0020_Color)
- In each new group include all of the fields from the previous groups along with any separators you like:
concat(@group1field, @group2field, @group3field, @group4field, @group5field, etc)
or concat(@group1field, " - ", @group2field, " - ", @group3field, " - ", @group4field, " - ", @group5field, etc)
- concat(@Bike_x0020_Type, " - ", @Size, " - ", @Bike_x0020_Color)
- Before clicking OK to leave this dialog box, check the order of the groups. They have probably gotten changed. (bug?)
- Make sure they are in order something like:
@BikeType
concat(@Bike_x0020_Type, " - ", @Size)
concat(@Bike_x0020_Type, " - ", @Size, " - ", @Bike_x0020_Color) - Recheck each of the sort levels to see if these are still checked:
- Click Show group header
- Click Collapse group (optional)
- Click Show group footer (if you want counts and totals)
- Make sure they are in order something like:
- Optionally add one more column just to sort the data within the last group. Do not turn on the group header or group footer options for this sort-only field.
- Click OK to close the Sort and Group dialog box.
- You will probably want to change the Paging options as they default to 100 items.
- Tip: If you have a lot of data in the list SharePoint Designer can get really slow. There are two things you could do here, set paging to a small number (not so good for testing multi-level grouping) or from the Common Control Tasks select Show With Sample Data.
- If you want grand totals you will also need to click Data View Properties and check Show View Footer.
- Save! At this point you may want to click Save and review the results so far in a browser. You should now have all of your groups.
Click the + to expand a section.
- Now is a good time to clean up the formatting such as the gray background and odd row height in the group header and footer rows. (Right-click in the row in Design view and select Cell Properties.
(click for bigger view)
- Your grouping work is now done. The following steps are only needed if you want to add totals, counts, averages, etc.
- Now for totals!
- These steps describe adding totals to the footer rows, but also apply to modifying header (top of each group) rows.
- The Data View sets up the header and footer rows as a single cell with a column span of 99! To display totals in the same columns and the data you will need to fix these rows.
- You will need to fix each of the group footer rows plus the view footer row.
- These steps describe adding totals to the footer rows, but also apply to modifying header (top of each group) rows.
- In the Code View do a search for "colspan="99"". In my example there will be seven of these, one for each grouping footer, one for each grouping header and one for the view footer.
- Now you need to do a little planning. In my example I'd like to put the "Count=" in a two column spanned cell under the ID and Bike columns. Then I would like to have one cell under each additional column. So something like: <td colspan='2'>count stuff</td><td></td><td></td><td></td><td>total goes here</td>
Steps:- Find "colspan="99"" for the first group footer row. (Tip: Did you find a header or footer row? Look up two lines and you should see "<xsl:if test="$showheader"" or "<xsl:if test="$showfooter""!)
- Change the 99 to 2
- Find the end tag for the cell (</td>) (down about 16 lines of html)
- After the end tag add the other cells (TD tag pairs), one for each additional column (I need four more)
<td></td> <td></td><td></td><td></td>
- Find "colspan="99"" for the first group footer row. (Tip: Did you find a header or footer row? Look up two lines and you should see "<xsl:if test="$showheader"" or "<xsl:if test="$showfooter""!)
- Now to add the total…
- Switch to Design view and you should see the new cells in one of the footer rows.
- Click in the cell where you want the total
- Right-click and select Insert Formula
- Build your formula. For a total double click "sum" in the function list then select your field from the dropdown list. My example needed: sum(@Retail)
- The formula editor does not know one extra piece of information needed here. The @Retail field needs to come from the current group only. To get this, update the formula like this: sum($nodeset/@Retail) ("nodeset" is all lower case)
Tip: How would you have discovered this? Go look at how they calculated the Count: count($nodeset). - Notice that the formatting is wrong. The total is left aligned and the wrong size. To match the font and size find the style used for the data in the row above. In my example it looked like this: <TD Class="{$IDADW3HE}">
- Copy the class info (Class="{$IDADW3HE}") into your total cell (the TD tag). The result will look something like this:
<td Class="{$IDADW3HE}"><xsl:value-of select="sum(@Retail)" /></td> - The last step is to right align the cell (you can use the toolbar button) and to format the total. To format the number, click in the cell with the total, right-click and select Format Item As… and pick your formatting options.
- Note: SharePoint Designer may get creative and merge your formatting in new styles with great names like style1, style2, style3 etc.. If you are curious, do a search for .style1 (dot style1) and you will find they have placed the style class definition in the PlaceHolderBodyAreaClass master page placeholder.
- Switch to Design view and you should see the new cells in one of the footer rows.
- Fix up each footer row, including the View Footer, the same way. Add the extra TDs, add the totals, counts, etc, and format the results.
- Now about the View Footer… and some things to make your head hurt…
- The View Footer is built in its own HTML table, so the column widths are not going to line up with the rest of the list. (I'll have to come back with another article to make these line up correctly).
- The grand totals need a special calculation to sum all of the rows. The @Retail field (or @yourfield) needs to come from the entire set of rows. To get this, update the formula like this: sum(/dsQueryResponse/Rows/Row/@yourfield) (make sure the capitalization is correct!)
Tip: How would you have discovered this? Go look at how they calculated the Count for the View Footer: count(/dsQueryResponse/Rows/Row) .
- The View Footer is built in its own HTML table, so the column widths are not going to line up with the rest of the list. (I'll have to come back with another article to make these line up correctly).
Finally all done!
A lot of steps, but it's a fairly routine and mechanical process. Do it a few times and you to will be able to amaze your fellow site owners!
Hopefully the next version of SharePoint will support more than two levels of grouping. Then we can all brag: "Back in the old days I had to … " (But sad to say… 2010 Beta 2 does not!)