JQuery for Everyone: Expand/Collapse All Groups
Erwin gave me another great idea from Stump the Panel.
We have a document library with a view using a grouped by.
We would like to make it possible to collapse all expanded records with one click.
As much as I try to avoid jQuery becomming a hammer and seeing everything as a nail, this is one of those prime examples of a simple but elegant solution to close a gap in the List View Web Part functionality.

(UPDATED!).
UPDATE: 1/15/2009 – Larry pointed out that nested groups still tried to trigger even if they were not visible which caused some looping. I added the :visible filter to the selectors for the code snippet which seems to work much better for nested groups.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> function collapseGroups() { $("img[src='/_layouts/images/minus.gif']:visible").parent().click(); } function expandGroups() { $("img[src='/_layouts/images/plus.gif']:visible").parent().click(); } $(function() { var expandAll = "<a href='#' onClick=" +'"'+"this.href='javascript:expandGroups()'" +'"><img title="expand all groups" style="border:none;" alt="expand all" src="/_layouts/images/collapseplus.gif"></a>'; var collapseAll = "<a href='#' onClick="+'"' +"this.href='javascript:collapseGroups()'" +'"><img title="collapse all groups" style="border:none;" alt="collapse all" src="/_layouts/images/collapseminus.gif"></a>'; $("td.ms-toolbar[width='99%']").append(expandAll).append(collapseAll); }); </script>
Update (7/28/2009):
This version tested with jQuery 1.3.2 and IE8:
<script type="text/javascript"> if(typeof jQuery=='undefined'){ var jQPath = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/'; document.write('<script src="',jQPath,'jquery.min.js" type="text/javascript"><\/script>'); } </script> <script type="text/javascript"> /* * Copyright (c) 2009 Paul Grenier (endusersharepoint.com) * Licensed under the MIT (MIT-LICENSE.txt) */ $(function(){ jQuery.groups = { collapse : function() { $("img[src*='minus.gif']:visible").parent().click(); }, expand : function() { $("img[src*='plus.gif']:visible").parent().click(); } }; var expandAll = "<a href='#' onClick=" +'"'+"this.href='javascript:$.groups.expand()'" +'"><img title="expand all groups" style="border:none;" alt="expand all" src="/_layouts/images/collapseplus.gif"></a>', collapseAll = "<a href='#' onClick="+'"' +"this.href='javascript:$.groups.collapse()'" +'"><img title="collapse all groups" style="border:none;" alt="collapse all" src="/_layouts/images/collapseminus.gif"></a>'; $("table.ms-menutoolbar td.ms-toolbar[width='99%']").append(expandAll).append(collapseAll); }); </script>
- JQuery for Everyone: Accordion Left Nav
- JQuery for Everyone: Print (Any) Web Part
- JQuery for Everyone: HTML Calculated Column
- JQuery for Everyone: Dressing-up Links Pt1
- JQuery for Everyone: Dressing-up Links Pt2
- JQuery for Everyone: Dressing-up Links Pt3
- JQuery for Everyone: Cleaning Windows Pt1
- JQuery for Everyone: Cleaning Windows Pt2
- JQuery for Everyone: Fixing the Gantt View
- JQuery for Everyone: Dynamically Sizing Excel Web Parts
- JQuery for Everyone: Manually Resizing Web Parts
- JQuery for Everyone: Total Calculated Columns
- JQuery for Everyone: Total of Time Differences
- JQuery for Everyone: Fixing Configured Web Part Height
- JQuery for Everyone: Expand/Collapse All Groups
- JQuery for Everyone: Preview Pane for Multiple Lists
- JQuery for Everyone: Preview Pane for Calendar View
- JQuery for Everyone: Degrading Dynamic Script Loader
- JQuery for Everyone: Force Checkout
- JQuery for Everyone: Replacing [Today]
- JQuery for Everyone: Whether They Want It Or Not
- JQuery for Everyone: Linking the Attachment Icon
- JQuery for Everyone: Aspect-Oriented Programming with jQuery
- JQuery for Everyone: AOP in Action - loadTip Gone Wild
- JQuery for Everyone: Wiki Outbound Links
- JQuery for Everyone: Collapse Text in List View
- JQuery for Everyone: AOP in Action - Clone List Header
- JQuery for Everyone: $.grep and calcHTML Revisited
- JQuery for Everyone: Evolution of the Preview
- JQuery for Everyone: Create a Client-Side Object Model
- JQuery for Everyone: Print (Any) Web Part(s) Plugin
- JQuery for Everyone: Minimal AOP and Elegant Modularity
- JQuery for Everyone: Cookies and Plugins
- JQuery for Everyone: Live Events vs. AOP
- JQuery for Everyone: Live Preview Pane
- JQuery for Everyone: Pre-populate Form Fields
- JQuery for Everyone: Get XML List Data with OWSSVR.DLL (RPC)
- Use Firebug in IE
- JQuery for Everyone: Extending OWS API for Calculated Columns
- JQuery for Everyone: Accordion Left-nav with Cookies Speed Test
- JQuery for Everyone: Email a List of People with OWS
- JQuery for Everyone: Faster than Document.Ready
- jQuery for Everyone: Collapse or Prepopulate Form Fields
- jQuery for Everyone: Hourly Summary Web Part
- jQuery for Everyone: "Read More..." On a Blog Site
- jQuery for Everyone: Slick Speed Test
- jQuery for Everyone: The SharePoint Game Changer
- JQuery For Everyone: Live LoadTip
Paul – Beautiful solution. How did you get it to sit on the list menubar? — Mark
I revisited the code from the Gantt chart fix. td.ms-toolbar[width='99%'] only appears in one place in a List View, the space between the last action button and the View selector. Then I used append() to insert the HTML.
This is actually a solution I’ve been looking for for a long time, thanks!
For some more nails for you to hammer, how about expanding on my POC here:
http://mo.notono.us/2009/01/moss-add-incoming-links-to-wiki-page.html
As the url and title state: this copies the Incoming Links for a wiki page onto the wiki page itself. But it needs perfecting, so that’s where you come in… ;-)
@Oskar,
That’s awesome! I don’t use the Wiki template on my site(s) but that’s a great idea.
If you’re fishing for ideas: this could get loaded into a hidden div that flies out when you hover on “Incoming Links”. That way if the load takes a second no one will see it.
This is really great and I do not want to take away from that. I implemented this on a list with about 150 items. They are grouped 2 levels, 12 top and 3 secondary. For some reason when I initially click the expand, it opens one item at a time. From start to finish is about 2 minutes before all items are open. If I click collapse before it is complete it will only close what was already opened, but then it seems to be disabled. Have I missed something with the installation?
Thanks
@Larry,
I appreciate your comments. You used a lot more data than my test case so I’ll need some time to check this out. I’m fairly certain the 2nd level groups will not expand with the first “expand all” can you confirm that?
When groups expand, the page makes a POST request to the list for additional data. Asking so many groups to expand at once could be a strain on the browser or the server. I’ll know more later.
Thanks again,
~Paul
The second level expanded. Works great, but it appears as if it is looping through each item, then it opens.
@Larry,
I have a hunch. Try adding the :visible filter to the end of the two selectors so they look like this:
$(”img[src='/_layouts/images/minus.gif']:visible”).parent().click();
BINGO! Much faster, the delay isn’t any more than what you get if you clicked to expand or collapse. You know sometimes you get the loading… until the content displays. This one on first click in about 5-7 seconds all 150 items are viewable. Collapse is instant. The second expand, instant.
Great job thanks!
Thanks again Larry, I updated the code snippet.
Thanks for the solution Paul, it works like a charm. Just one question … could it be that upgrading to jQuery 1.3 brakes the solution?
@Erwin,
I have an article coming out next week that references 1.3 and I will continue to publish new solutions with it but I can’t make promises about anything published before now until I test.
I read the changelog and nothing jumped out at me.
~Paul
@Erwin,
Actually, I did notice something strange with the attribute selectors in my new script. If you’re having this script break in 1.3, try this selector:
$(”img[src$='minus.gif']:visible”)
AND
$(”img[src$='plus.gif']:visible”)
@Paul
I completely understand you can’t guaranty every piece of code you write here will work with every new version of jQuery being released.
But … with the new selectors you gave everything works as before the upgrade of jQuery to 1.3.
Thank you very much.
Erwin
For those interested I changed the selector in the “append” line from :
$(”td.ms-toolbar[width='99%']“).append(expandAll).append(collapseAll);
into:
$(”table.ms-menutoolbar td.ms-toolbar[width='99%']“).append(expandAll).append(collapseAll);
The “Expand/Collapse All Groups” images where showing up in my view properties pages too …
Erwin
This is a great little trick you have hear. i would like to do some testing on some of my list. Can someone point me in the right direction for implementing this code into my list.
@Rich,
Check out the screencast I made for another post in this series:
http://www.endusersharepoint.com/?p=1223
The only difference will be which code you paste into the Content Editor Web Part.
~Paul
Had the same problem as somebody else until I changed the selector to:
$(”td.ms-gb img[src*='/_layouts/images/plus.gif']:visible”)
Also, I didn’t want the separate + and – images show up on the menu toolbar (which can be hidden on ListView Web Parts), hence I changed it to add a single image to the view header like this:
var imgTitle = “Expand/Collapse all”;
$(”tr.ms-viewheadertr td.ms-vh-group img”).parent().attr(”title”, imgTitle);
$(”tr.ms-viewheadertr td.ms-vh-group img”).attr(”alt”, imgTitle);
$(”tr.ms-viewheadertr td.ms-vh-group img”).attr(”src”,”/_layouts/images/plus.gif”);
$(”tr.ms-viewheadertr td.ms-vh-group img”).parent().click(
function()
{
var expanded = $(”td.ms-gb img[src*='/_layouts/images/plus.gif']:visible”);
var collapsed = $(”td.ms-gb img[src*='/_layouts/images/minus.gif']:visible”);
if (expanded.length > 0)
{
$(”td.ms-gb img[src*='/_layouts/images/plus.gif']:visible”).parent().click();
}
if (collapsed.length > 0)
{
$(”td.ms-gb img[src*='/_layouts/images/minus.gif']:visible”).parent().click();
}
});
Plus adding some style to my custom CSS file (which certainly could be added via JQuery too):
.ms-viewheadertr td.ms-vh-group img
{
height: 16px;
margin-left: 1px;
margin-top: 2px;
width: 16px;
}
Now I do have a nice (I’m using a custom icon, tho) image in the left column of each grouped view header, no matter if a Web Part or list view which expands/collapses all groups on a single click.
HTH
I love this, but. I have the toobar hidden on my document library. Could you please provide code that would do the same idea without needing the toolbar to be available? I can make use of this right away. Thanks so much.
under firfox, the display is weired.
Nick – Define “weird”. — Mark
Hi,
There is no wards to prise you. Simply Superb.
Thanks,
Rao.
Awesome solution! Easy to apply, serves its purpose. Simply brilliant!
I’m not a developer … just a lowly end-user doing my company’s SharePoint site development and maintenance via the browser.
Can this expand/collapse features be implem,ented through the browser? Or do I need to use something like SharePoint Designer?
This code works great with JQuery-1.2.6-min but when I tried to use it with JQuery-1.3.2-min, it didn’t work. It was just not doing anything when clicking on the plus/minus icon to expand or collapse all groups. Any suggestions?
Peter, this article will show you what to do.
http://weblogs.asp.net/jan/archive/2008/11/20/sharepoint-2007-and-jquery-1.aspx
@Jenny,
The problem is the :visible filter, it is broken for IE in the newest version of jQuery. I rewrote this to avoid using :visible, but it’s not published yet. I’ll try to get to that soon.
@Peter,
As Jenny stated, this is something you can do in your environment (even in your default.master) without any special tools or server access.
Jan’s site as well as my series on using JavaScript in SharePoint have some good resources.
Echoing Kermt’s comment- can this be made to work on web parts with the toolbar hidden?
@Nancy,
Where do you want to put the +/- icons?
Very interesting, looking forward to the update with JQuery-1.3.2-min.
@Ad,
see above.
I am following up on @Nancy.
It would be cool if we could add these buttons to the Summary Toolbar rather than Full Toolbar. AutoSponge, would this be possible?
Hi, I tried with JQuery-1.3.2-min and IE 6 and it isn’t working. Let me know if anything is wrong!!!
its working well….i typed in something wrong..its awesome…thanks alot!!!
I am following up with Greg…Is it possible to use the summary toolbar. It will be really very good if there is some solution for that…Thanks,,,
And I have one more question- I have a page with 10 data view web parts which appear grouped by default. These web aprts must have the title bar hidden.
I want a button to place at the top of the page in a CEWP that will allow “expand all’-”collapse all” for all ten web parts at once. Can this be leveraged for something like that?
@Nancy,
The original code should do that. I wrote another version that only functions for the web part the “buttons” appear on.
If the toolbar is hidden, try changing $(”table.ms-menutoolbar td.ms-toolbar[width='99%']“) to $(”.ms-titlearea”).
This will put the icons above the content area and below the top-nav.
Just to clarify- I am talking a about a web part page that has a bunch of DVWPs on it, not a list view or library view.
And what is requested is “one control to rule them all,” ideally a button (or two buttons?) to sit at the top of the page and force expand/collapse of all grouped items in all ten DVWPs- “Collapse all Groups,” “Expand all Groups.”
This code will do that?
@Nancy,
It should, but I think the DVWP expand/collapse fails in FireFox which is why I had to rewrite it for my site. So I can’t test that situation. But all this script does is find the .gif on the page and click its parent. DVWP uses the same .gif.
This did work- I was expecting them to appear lower down. They are appearing above the .gif image I have on the page header. Thanks!
This is great and just what I need. I am relatively new to all this SP stuff so this may be easy to do. I am trying to get the ms-seperator lines before th ‘+’ and after the ‘-’. so the bar looks like | + – |. As soon as I add the seperator it gets all whacked out. Any suggestions?
The code works absolutely great when I place it in a CEWP or save it to a .js file and reference it. When I move the .js file to a different site collection and then use the Content Link to reference it, the whole thing breaks with a message of
“Cannot retrieve the URL specified in the Content Link property. For more assistance, contact your site administrator.”
I am trying to use Mark’s methodology of creating one main center for all code and script and reference everything back to it. Any ideas why this is breaking the code?
@Tom,
I’m fairly certain that this would be a problem with the file having a permissions issue when accessed with the id used to consume the script. Whatever id is used on the viewing page, needs to also have access to the secondary collection (or the collection has anon access turned on).
I have been told that this is due to the CEWP not able to use the content link across site collections unless you have the proper port specified in the url link. Unfortunately, I cannot seem to get the correct information from the admins to make this work. I am going to have to find another way.
Love this script. It works great when I place it on a view that I have grouped. I’m actually using a copy of what SevenOfNine has in his posting above.
My question is that I would also like to implement something like this in a dataview that I have. Not sure how to do this. I took the code that was working great on the allitems.aspx page that I have it on and copied it to my default.aspx page where the dataview is but it does not work anymore now?
Any ideas? Thanks
It can easily converted in expandable menu ! good script carry on.
I want to use this functionality on a web part web page with a DVWP (no toolbar turned on). Is this possible? My DVWP has two levels of groupings and pulls from a SP list. (Using a DVWP to remove the grouping field name.)
We are using this piece of code with a big document library and it works fine. However it’s very fast with Google Chrome but very slow with IE7. Any idea? Tips?
Thanks.