Is it possible to create nested tables? As well as tables with expanding rows?

I’m not sure what the proper terminology is, but what I’d like to do is show a list of records with an icon on each row that would expand that row and show detail records for that row.

For instance, if you’re familiar with the Northwind database, let’s use the Orders and Order Details tables as an example. Using the Table Generator, define a table connected to a paged query that returns the Orders and related Order Details for each record. The table needs to display each order as a row, and then when the user clicks the expand icon, show the order details for that given order. I need it to be a paged query because I want to have a paging component below the table. Hope that makes sense.

Here is the Orders table:

With the paging component under it:

Now, I’d like to put a button on each row with an icon that would expand the row and show some fields from the Order Details for that row’s Order.

Yes that is possible, but you will need to custom code this.
You need to use nested repeats on the server side and either nest a table within in an existing table row > td or use collapses with nested tables inside. No point-and-click solution out of the box.

OK, I’m not afraid of custom coding it, so I’d be interested in more detail.

Can I use a paged query on the server side, or do I have to use a multi query and build the paging properties somehow? I know how to use a repeat and loop over the data returned by the query, but can’t figure out how to get the data into the right structure.

With this server side code:
image

This is the data and it’s the correct, but OrderDetails is not part of the data property like it probably should be:

I think each entry in OrderDetails needs to be an array in it’s parent record in Orders.data property. Is there a way to get it there?

For the paged query, you will need to use the “repeat” as a source for the dynamic table on the front end and then use the paged query itself for the paging.

OK, I think I followed that and got it working. So basically, we’re ignoring the data property of the paged query and using the output of the repeat. Redundant data, but so far so good.

I now have an OrderDetails array for each row in the Orders array and it’s available on the front end but I can’t figure out how to display it. I used the table generator to create another table but its showing the data from the first row only. And it just wants to show it above or below the Orders table.

How do I get it to show in the correct row?

That’s only because of the way the paged query works. When working with regular queries you only use the repeat and disable the output of the query itself.

What do you mean? What’s the code for both repeats on your page?

Is this what you mean?

For the Orders table:
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="sc_orders.data.repeat" id="tableRepeat1" dmx-state="qm_orders" dmx-sort="sort" dmx-order="dir">

And for the OrderDetails table:
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="sc_orders.data.repeat[0].OrderDetails" id="tableRepeat2">

I know repeat[0] is not correct, but I’m not sure what it should be.

If the second repeat is nested into the repeating element of the first one the it needs to be:

dmx-bind:repeat="OrderDetails"

Great! We’re getting closer!

As you can see, the details are correct by the OrderID

But the layout is not quite what I’m looking for yet. I just added another Cell (td) and inserted the OrderDetails table into that cell. But its showing its showing it as another column on the right and I’d like ti to be an expanded area of some sort under each row.

What markup or component could I use to do that?

You can add another tr in the main repeating tbody element after the existing tr.

<tr>
  <td colspan="9">
  ...your nested table code goes here...
  </td>
</tr>

just make sure the colspan value is equal to your main table columns count.

Perfect! Yes, I found that on getbootstrap.com: https://getbootstrap.com/docs/5.0/content/tables/#nesting

So, I’m getting this now:

Now to figure out how to show the details collapsed and then the user can expand and collapse at will. What markup would work for that?

Something like this?

I got this working using the collapse class on the nested tr and a button on the main row.

<tr class="collapse" dmx-bind:id="'collapseOrderDetails'+$index">
Then the button:
<button id="btn1" class="btn" data-bs-toggle="collapse" dmx-bind:data-bs-target="'#collapseOrderDetails'+$index"><i class="fas fa-plus"></i></button>

However, it’s messing up the row stripping. I think its because the collapsed row is every other row and that is the expected offset color.

As you can see, all the rows are the shadow color. Any idea how to correct this?

1 Like

You can add a custom css class and style it. Example, add the following class to your table table-collapse and remove the table-striped class from the table. Then in your css style it like:

.table-collapse tbody tr:nth-of-type(4n+1) {
    background-color: rgba(0,0,0,.05);
}
2 Likes

That’s awesome! Seems to work very nicely.

I think that pretty much does it, except for the icon in the expand/collapse button. I’d like the icon to change from a plus to a minus on each row when it’s expanded and back to plus when collapsed. Is there a way to reference the collapsed state of the tr and show/hide icons? Maybe reference the class? Or what would work for that?

I have a similar setup, but use arrows, so the icons will need changing, but something like this should work:

<td class="text-center"><i class="fas fa-fw" dmx-class:fa-caret-down="!bs4collapse.collapsed" dmx-class:fa-caret-right="bs4collapse.collapsed"></i>{{id_ord}}</td>

1 Like

What does bs4collapse.collapsed refer to?

I converted it to plus/minus for my case:
<i class="fas" dmx-class:fa-plus="!bs4collapse.collapsed" dmx-class:fa-minus="bs4collapse.collapsed"></i>

But, I’m still only getting the plus regardless of the state.

The row which displays the details when clicked:
<tr dmx-on:click="bs4collapse.toggle()"

Hmm, I’m not using the onClick event. I’m using the bs toggle and target method:

<button dmx-bind:id="'btnCollapseOrderDetails'+$index" class="btn" data-bs-toggle="collapse" dmx-bind:data-bs-target="'#trCollapseOrderDetails'+$index">

I could use a combination I guess, but was hoping for a way to reference the collapsed state of the tr.

I don’t think my example was very helpful - I just copied some code from something I had done before. In principal, could you use dynamic classes like this:

<button id="btn1" class="btn btn-primary" data-toggle="collapse" data-target="#collapse1"> <i class="fal" dmx-class:fa-angle-down="!collapse1.collapsed" dmx-class:fa-angle-right="collapse1.collapsed"></i>
</button>
<div class="collapse" id="collapse1" is="dmx-bs4-collapse">
<p>Collapse body text goes here.</p>

?