Click to expand & Collapse table groups

1. Create your table with groups as per http://helpdesk.knackhq.com/support/solutions/articles/5000443486-tables#columns

2. Add Javascript and change XXX to your view:

//Call the function when your table renders
$(document).on('knack-view-render.view_XXX', function (event, view , data) {
  addGroupExpandCollapse(view);
})

// function that adds expand & collapse to tables with grouping
var addGroupExpandCollapse = function(view) {
var cols = $(’#’ + view.key + ’ > table’).find(“tr:first th”).length - 1;

$(’#’ + view.key + ’ .kn-table-group’).css(“cursor”,“pointer”);
$(’#’ + view.key + " .kn-group-level-1 td").attr(‘colspan’, cols);

$(’#’ + view.key + ’ .kn-table-group’).click(function () {
var StartRow = this.rowIndex;
var TableRows = $(this).parent().children();

TableRows.each(function( index ) {
  if(this.rowIndex > StartRow) {
    var RowClass = $(this).attr('class');
    
    if(typeof RowClass === 'undefined' || RowClass == 'even') {
      if($(this).is(':hidden')) {$(this).show()} else {$(this).hide()}
    } else {
      return false;
    }
  }
});

});

}

3. Make sure it works:




Thanks everyone for contributing to this piece of code. I have found it very handy and thought I would share some of the changes I have made.

Without any code, you are looking at a table like this:

I have two columns in the table called school. The first is used to Group and the second is used to create a link to "edit" the school.

I wanted to not have the second column displayed and to have the link as part of the Group header line.

 

I added this javascript and CSS 

 

//////////////////////////////////////////////////////////////////////////////////////////////////
//Call the function when your table renders to collapse the table
// 
$(document).on('knack-view-render.view_xxx', function (event, view, data) {
allGroupExpandCollapse(view);


// pass the view and the cell class that has the href link 
addGroupExpandCollapse(view, "field_111");

});

//////////////////////////////////////////////////////////////////////////
var addGroupExpandCollapse = function (view, classInUse) {

var viewEl = document.getElementById(view.key);
var trEls = viewEl.getElementsByTagName("tr");

var trElsCount = trEls.length;

for (i = 0; i < trElsCount; i++) {
	if (trEls[i].classList.contains("kn-table-group")) {

		// find the first 'td' element from the Group Header 
		var firstTd = trEls[i].getElementsByTagName("td")[0];
		var rowText = $(firstTd).html();
		var iconHtml = '<i class="fa fa-plus-square-o expand-collapse"></i> ';

		// find the first 'a' element in the first td from the next detail line
		var cellTd = trEls[i + 1].getElementsByClassName(classInUse)[0];
		var hrefA = cellTd.getElementsByTagName("a")[0];

		if (hrefA != null) {
			// replace existing html with a plus icon on all Group Header td
			$(firstTd).html(iconHtml);
			// copy the first 'a' element from the next detail line and append it to the Group Header td
			$($(hrefA)).clone().appendTo($(firstTd));

		} else {
			// Display only the original text (no link) with the icon
			$(firstTd).html(iconHtml + rowText);
		}
	}
}

$('#' + view.key + ' tbody .' + classInUse + ' span').css("visibility", "hidden");

// This line causes groups to be collapsed by default.
$('#' + view.key + ' .kn-table-group').nextUntil('.kn-table-group').toggle();

$('#' + view.key + ' .expand-collapse').css("cursor", "pointer");
$('#' + view.key).on("click", ".expand-collapse", function () {

	var rowEl = $(this).closest("tr");
  	var rowElHtml = $(rowEl).html();

	if (rowElHtml) {
		if (rowElHtml.indexOf('fa-minus') !== - 1) {
			$(rowEl).html(rowElHtml.replace('minus', 'plus'));
		} else {
			$(rowEl).html(rowElHtml.replace('plus', 'minus'));
		}
	}

	$(rowEl).nextUntil('.kn-table-group').toggle();

});

}

//////////////////////////////////////////////////////
var allGroupExpandCollapse = function (view) {

var viewEl = document.getElementById(view.key);
var thEl = viewEl.getElementsByTagName("th")[0];
var thElText = $(thEl).html();

$(thEl).html('<i class="fa fa-plus-square-o"></i> <i class="fa fa-minus-square-o"></i> ' + thElText);

$('#' + view.key + ' th i').css("cursor", "pointer");
$('#' + view.key + ' th a').css("display", "inline");

var plusIcon = viewEl.getElementsByClassName("fa-plus-square-o")[0];
var minusIcon = viewEl.getElementsByClassName("fa-minus-square-o")[0];

$(minusIcon).click(function () {
	$('#' + view.key + ' .kn-table-group').nextUntil('.kn-table-group').toggle(false);

	$('#' + view.key + " .kn-group-level-1 td").each(function () {
		if ($(this).html().indexOf('fa-minus') !== - 1) {
			$(this).html($(this).html().replace('minus', 'plus'));
		}
	});
});

$(plusIcon).click(function () {
	$('#' + view.key + ' .kn-table-group').nextUntil('.kn-table-group').toggle(true);

	$('#' + view.key + " .kn-group-level-1 td").each(function () {
		if ($(this).html().indexOf('fa-plus') !== - 1) {
			$(this).html($(this).html().replace('plus', 'minus'));
		}
	});
});

}

 

CSS

#view_xxx .kn-table-group.kn-group-level-1 {
  background-color: rgba(0,0,0,.03)!important;
}

.fa.fa-plus-square-o, .fa.fa-minus-square-o{
font-size: 15px !important;
}

 

   With the end result looking like this:

I have hidden the contents of the second column, moved the link to the Group Header line and added Collapse/Expand All icons.

 

In the CSS I have lightened the Group Header colour and resized the icons.

 

Thanks,

Another thumbs up from me!

Hi Everyone,

Thank you very much for posting this code.  I made a small modification that shows the correct icons when the groups are collapsed by default.  

The code below has the groups collapsed and shows a "plus" icon for the group which then changes to the "minus" sign when the group is expanded.  Below is the full code (make sure to change XXX to the name of your view):

//Call the function when your table renders
$(document).on('knack-view-render.view_XXX', function (event, view , data) {
addGroupExpandCollapse(view);
})

var addGroupExpandCollapse = function(view) {

$('#' + view.key + ' .kn-table-group').css("cursor","pointer");

$('#' + view.key + " .kn-group-level-1 td").each(function () {
if($(this).text().length > 1) {
var RowText = $(this).html();
$(this).html('<i class="fa fa-plus-square-o"></i>&nbsp;' + RowText);
}
});

// This line causes groups to be collapsed by default.
$('#' + view.key + ' .kn-table-group').nextUntil('.kn-table-group').toggle();

$('#' + view.key + ' .kn-table-group').click(function() {

$(this).nextUntil('.kn-table-group').toggle();

if($(this).html().indexOf('fa-minus') !== -1) {
$(this).html($(this).html().replace('minus', 'plus'));
} else {
$(this).html($(this).html().replace('plus', 'minus'));
}
});

}

Hey Manuel, 

I added that code as you mentioned, yet it doesn't start collapsed. Can you take a look at the loom video and see if i did it right? 

I appreciate the help. 

Benjamin

https://www.loom.com/share/4e160c03e03e47f9a72076d9bd3b5ae4

Hi,

Thanks for the Code. I noticed someone else needed to have the table groups collapsed by default...

I just added this line:

$('#' + view.key + ' .kn-table-group').nextUntil('.kn-table-group').toggle();

... right before this one:

  $('#' + view.key + ' .kn-table-group').click(function() {

--- by doing that, your table groups will be collapsed by default right  after the rendering process finishes.

Happy coding

Manuel

This worked beautifully. I really appreciate everything you guys do. I have one, hopefully small request. 

Does anyone know a way for the table, that this is applied to, to show all records. This works, but because my table has 150 records it will split it into two pages. Please help. 

Hi 

How to make the table collapsed on page load and then users will click on the table group to expand?  Right now table is in expanded by default. 

Thanks

Thanks for Sharing. For some reason this code works on all of my table groups other than the very first entry which displays the "+" and "-" but they are non-functional. The buttons on all of the subsequent groups function.  Any Tips?

Update: Never mind. I figured it out. In case anyone else has this problem. The code will not work on the first record if you have more than one field grouping assigned. Remove all but one of the field groupings and adjust the sort order on data to achieve the same results.

Then the code runs beautifully. Thanks again for sharing!

Mai - I've been trying some things without success so far.

I'll post an update when i get it working...

Hi all, thanks for posting all of your code! Just wondering - would anyone know how to customize the JS so that the table loads with all rows collapsed on default? 

Lacking the JS experience but hoping to get our site up and running where it needs to be... would appreciate any advice offered.

Thank you!!

Finally got it! I copied your second code but forgot to include this at the beginning... derp :-P

//Call the function when your table renders
$(document).on('knack-view-render.view_XXX', function (event, view , data) {
  addGroupExpandCollapse(view);
})

 

It might matter,

The second code I listed includes Stevan's modification - notice this line:

$(this).nextUntil('.kn-table-group').toggle();

So just use that and let us know if that works.

Ha nice! I use VBA in Excel and have a little experience in Java but still very much a newbie. This is fun though isn't it!

I am using icons for my page menus / buttons so I don't think that's it. Does it matter that I used Steven's jquery code in combination with yours? Or should they still work together?

Newbie too Emay - old self-taught Access VBA dev here, and enjoying the challenge Knack is providing in making a switch.

I was thinking that if you don't use icons anywhere in your app then Knack might not call the library for icons to work, so maybe try adding an icon to something (a menu button or link) and see if that works.

I have not tested though as all my apps have icons somewhere and this code has always worked to date.

Very cool! I had been wishing this feature existed and this works like a charm!

Although I cannot get the 2nd piece of code to work to display the "+" and "-". Is there something I need to replace to customize it for my app?

I'm very new to javascript so pardon my ignorance :-)

Had trouble re-posting with page errors so here's another try.

Got icons working while I'm sure the code could be more elegant - include adding a pointer cursor on hover too:

 

var addGroupExpandCollapse = function(view) {

$(’#’ + view.key + ’ .kn-table-group’).css(“cursor”,“pointer”);

$(’#’ + view.key + " .kn-group-level-1 td").each(function () {
if($(this).text().length > 1) {
var RowText = $(this).html();
$(this).html(’<i class=“fa fa-minus-square-o”></i>&nbsp;’ + RowText);
}
});

$(’#’ + view.key + ’ .kn-table-group’).click(function() {

$(this).nextUntil('.kn-table-group').toggle();

if($(this).html().indexOf('fa-minus') !== -1) {
  $(this).html($(this).html().replace('minus', 'plus'));
} else {
  $(this).html($(this).html().replace('plus', 'minus'));
}

});

}

I like the idea of Knack contributors Stevan especially after benefitting from the likes of MS Access MVPs in my dark past, and more recently the sharing that’s happening here.

Welcome Brad!

We are all here to learn from each other!

I went through the icon story already. Unless you are all set with it I can post if it helps.

it can be done with a very few lines of code.

PS : We should consider forming a club of knack contributors, shouldn't we?

Much better Steven!  Shortens by code 'slightly' - a lot.

I'll look at adding expand/collapse type icons to the table-group cells and post here.

Thanks again Stevens.

Hi Brad.

Nice! 

a slightly shorter version with the .nextUntil() Jquery - quite useful for this.

 

/*Expand collapse table row*/

$(document).on(‘knack-view-render.view_xxx’, function(event, view) {
$(’.kn-table-group’).click(function() {$(this).nextUntil(’.kn-table-group’).toggle();
});
});