Collapse groups in a Grid

Me again!
I have quite a few tables where I have used grouping, but sometimes there are still a LOT of entries within a group. Is there a way please to collapse / expand the groups so that only the headings show until you click o them?

If there is, is it also possible to show any totals rows under the group heading?

Many thanks once again :slight_smile:

There’s not a native option for this is Knack, hopefully one of the genius code gurus will jump in and help :man_technologist::woman_technologist:

1 Like

Thanks @CarlHolmes, I will leave this question open for now then and keep my fingers crossed!
For any others who might have ideas, here’s a screenshot of what I want to collapse / expand at will:

I have some code that is working for me that took some time to work out as this is a bit confusing to try and code but my code is setup for 2 groups so not sure how it will affect your scenario. I would have to work with it to switch it to one group when I have time. One of the complexities that I noticed is that every time you view or edit a record and it returns it closed the grouping and had to be reopened, so I added code to store the group state so it persists during a refresh. Will try and post something later today.

@DeanBozzan62116 good work. I like it a lot.

Many thanks @DeanBozzan62116 - looks pretty much like I want to achieve (although I’d love to also be able to include the overall total for each currency if that were doable) … did I miss something though, am I meant to see some code to do this?

I had to revise the code to work with one Grouping. Persistence of State is not working with this code - in other words when you leave the page and come back or refresh the page all the groupings will start in a collapsed state which is what you may want. Much depends on your usage and if you are working in a group of records, inline editing and refreshing the modal view… that may change behaviors you want but it gets more complex. But try this and see if it gets you what you need. Just change the view_xxx in the first line.

$(document).on('knack-view-render.view_71', function (event, view, data) {
    // Function to generate a unique identifier for each group
    function getGroupId(groupRow) {
        return 'group-state-' + view.key + '-' + groupRow.index();
    }

    // Function to toggle group visibility and icon
    function toggleGroup(groupRow, forceCollapse = false) {
        var groupId = getGroupId(groupRow);
        var rowsToToggle = groupRow.nextUntil('.kn-table-group');
        var isExpanded = rowsToToggle.first().is(':visible');

        if (isExpanded || forceCollapse) {
            rowsToToggle.hide();
            groupRow.find('.expand-collapse').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
            localStorage.setItem(groupId, 'collapsed');
        } else {
            rowsToToggle.show();
            groupRow.find('.expand-collapse').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
            localStorage.setItem(groupId, 'expanded');
        }
    }

    // Initialize groups and add expand-collapse icon
    $('#' + view.key + ' .kn-table-group').each(function () {
        var groupRow = $(this);

        // Add icon if not already present
        if (!groupRow.find('.expand-collapse').length) {
            groupRow.find('td:first').prepend('<i class="fa fa-plus-square-o expand-collapse" style="cursor: pointer; margin-right: 5px;"></i>');
        }

        // Attach click event to toggle group
        groupRow.off('click').on('click', function () {
            toggleGroup(groupRow);
        });

        // Collapse all groups on initial load
        toggleGroup(groupRow, true);
    });

    // Restore group states from Local Storage
    $('#' + view.key + ' .kn-table-group').each(function() {
        var groupRow = $(this);
        var groupId = getGroupId(groupRow);
        var state = localStorage.getItem(groupId);

        if (state === 'expanded') {
            toggleGroup(groupRow);
        }
    });
});
1 Like

Thank you @DeanBozzan62116

This is fantastic, thank you

Amazing @DeanBozzan62116
That worked for me too.
If I make any further improvements as I use it, I’ll post them back here.

Hope you are going well @Callum.Boase

I am about to attempt apply this code to app. Scream if you recommend i do not! :rofl:

I didn’t end up developing any changes to it. Hope the existing code does what you need

Thank you for this. It makes our new pages so much better!

If anyone gets back to this, my wishlist would be;
Include multiple views? Or maybe just apply to the whole app whenever we use grid groupings if that is simpler?

page retains collapse/expand state

and as someone already said, summary row to still appear

Hi Guy,

I can answer one/two of your items easily, so here we go.

Here’s how you can re-use the logic and apply it to multiple views without repeating the code over and over.

//Applying the code to one grid view
//Replace view_14 with whatever view_id you want to apply the code to
$(document).on("knack-records-render.view_14", function (event, view, data) {
    setupExpandableGridViewGroups(view);
});

//Apply it to another grid view 
$(document).on("knack-records-render.view_15", function (event, view, data) {
    setupExpandableGridViewGroups(view);
});

//And a third one
$(document).on("knack-records-render.view_16", function (event, view, data) {
    setupExpandableGridViewGroups(view);
});

//Generic helper function to make the expandable groups work with any view
function setupExpandableGridViewGroups(view) {
  // Function to generate a unique identifier for each group
  function getGroupId(groupRow) {
    return "group-state-" + view.key + "-" + groupRow.index();
  }

  // Function to toggle group visibility and icon
  function toggleGroup(groupRow, forceCollapse = false) {
    var groupId = getGroupId(groupRow);
    var rowsToToggle = groupRow.nextUntil(".kn-table-group");
    var isExpanded = rowsToToggle.first().is(":visible");

    if (isExpanded || forceCollapse) {
      rowsToToggle.hide();
      groupRow
        .find(".expand-collapse")
        .removeClass("fa-minus-square-o")
        .addClass("fa-plus-square-o");
      localStorage.setItem(groupId, "collapsed");
    } else {
      rowsToToggle.show();
      groupRow
        .find(".expand-collapse")
        .removeClass("fa-plus-square-o")
        .addClass("fa-minus-square-o");
      localStorage.setItem(groupId, "expanded");
    }
  }

  // Initialize groups and add expand-collapse icon
  $("#" + view.key + " .kn-table-group").each(function () {
    var groupRow = $(this);

    // Add icon if not already present
    if (!groupRow.find(".expand-collapse").length) {
      groupRow
        .find("td:first")
        .prepend(
          '<i class="fa fa-plus-square-o expand-collapse" style="cursor: pointer; margin-right: 5px;"></i>'
        );
    }

    // Attach click event to toggle group
    groupRow.off("click").on("click", function () {
      toggleGroup(groupRow);
    });

    // Collapse all groups on initial load
    toggleGroup(groupRow, true);
  });

  // Restore group states from Local Storage
  $("#" + view.key + " .kn-table-group").each(function () {
    var groupRow = $(this);
    var groupId = getGroupId(groupRow);
    var state = localStorage.getItem(groupId);

    if (state === "expanded") {
      toggleGroup(groupRow);
    }
  });
}

To apply it to every grid in the app instead of selected ones, it should work to do this (sub view_XX with ‘table’ so the code runs any time records render in a grid (table) view

$(document).on("knack-records-render.table", function (event, view, data) {
    setupExpandableGridViewGroups(view);
});

Re retaining collapse/expand & summary rows. I’ll leave that up to someone else for now.

1 Like

Amazing. Thank you!