Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

HTML

Tables and relations

So I am in the process of revamping a project for work which deals with tables or tabular data. The current implementation uses so many external libraries to make this thing work.

Basically I have a table with many rows and some of those rows are parents and others are children in the sense of relation that is this data is related to that data.

How it should look in respect to how it is related

<table>
<!—code omitted for brevity -->
<tbody>
    <tr>
        <td>parent info</td><td>parent info</td><td>parent info</td>
        <tr>
            <td>child info</td><td>child info</td><td>child info</td>
        </tr>
</tr>
</tbody>
</table>

However while it is technically related like this for validity sake it is laid out like so

<table>
<!—code omitted for brevity -->
<tbody>
    <tr>
        <td>parent info</td><td>parent info</td><td>parent info</td>
</tr>
<tr>
        <td>child info</td><td>child info</td><td>child info</td>
    </tr>
</tbody>
</table>

I brought this up to Nick Pettit on twitter and his response was “If you're nesting tables within tables, then either the parent table or child tables are not tabular data anymore.” So I figured I did not understand what tabular data is so upon Googling it nearest I can tell is that tabular data is any data that can be displayed or conveyed with a table…. So if you put it in a table it is tabular. So I don't grasp what make data tabular OR this isn't data that is meant to be tabular in either case this is a tough layout.

In my data that I have to display there are up to 5000 parent (rows) with anywhere from 1-500 child rows related to it.

Essentially what this table is – is a GUI view of all of our servers currently reporting any anomaly or error status, the entity (process) having the error and the particular error.

I need to figure out how to best layout this information. The current implementation uses datatables, treetables, jquery ui and a hand full of other libraries and it’s very cumbersome. It also leaves a problem that when you search or sort a table and it reorganizes stuff rows get rewritten where it breaks the parent/child relationship.

2 Answers

Kevin Korte
Kevin Korte
28,148 Points

Yeah don't nest tables in tables. Why can't each table be it's own parent table, and the children are just rows of their related table.....meaning you'd have multiple tables on the page, but never a table nested in a table. Since you already have some relationship that child data knows which parent it belongs to, it shouldn't be hard to refactor it so each parent is it's own table, and the child data just becomes it's rows.

If you need global search/sort among all the tables, you could than just use javascript or jquery to search/sort the DOM since everything you need is there in valid HTML.

and the parent data is represented in the TH of the table?

Kevin Korte
Kevin Korte
28,148 Points

Yes, would that work for you?

Possibly. I'll have to do a few mock-ups to see but I had the same idea but then thought if I didn't have a master TH to sort by it would break..... but those T's are just toggles for sorting. they could be anything form buttons to divs because it would just be click listeners and sort queries.

Kevin Korte
Kevin Korte
28,148 Points

I might look at using Flexbox as mention already too. Flexbox layout might get you what you want. I think what Nick was saying that once you nest a table in a table, the parent table is now being used as a structural component, not a data presenter. The child table becomes the data presenter, and we want to avoid using tables for structure.

I have done so now. The problem with getting the columns to line up to the div I have showing what columns are what. sort of a master header.

Kevin Korte
Kevin Korte
28,148 Points

Do you have a link to look at this somewhere?

Sure http://codepen.io/johnweland/pen/XbEMoW

I am using Font awesome so you'll see some text that says "icon" on the left hand side, that is for a toolbar.

click the "x" in the select column to toggle (caret icon doesn't show as I couldn't include my fonts in the pen.)

Tom Sager
Tom Sager
18,987 Points

John --

It look like you might have a couple of solutions in process here. I got your codepen to work, and could successfully collapse and un-collapse rows. (You can load the awesome font in-line: link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" ). It looked very functional, and your jQuery worked well. The challenge will be to style the disparate tables so they look cohesive, e.g. with the same column widths.

I then noticed the flexbox code in your CSS file. I am not sure that adding a flexbox layout to an HTML table is the way to go. A more traditional approach is to turn the table into nested divs, e.g.

  <div class="container"> 
   <h1>Enforcer RealTime Status</h1> 
   <a href="#" class="toggle-all">Show All</a> 
   <div class="table"> 
     <div class="row header collapsed"> 
      <div class="item">Select</div> 
      <div class="item">Hostname</div> 
      <div class="item">IP/Process</div>
      <div class="item">Version</div> 
      <div class="item">Type</div>
      <div class="item">Uptime</div> 
      <div class="item">Program Last Seen</div> 
      <div class="item">Message</div> 
      <div class="item">Event Last Seen</div> 
      <div class="item">Pin</div> 
     </div>    <!-- row --> 
     <div class="row"> 
      <div class="item">
       <i class="toggle fa fa-caret-right"></i>
      </div> 
      <div class="item">gplab</div> 
      <div class="item">172.26.16.24</div> 
      <div class="item"></div> 
      <div class="item">1 WARN</div> 
      <div class="item"></div> 
      <div class="item">
       <i class="toggle fa fa-itemumb-tack"></i>
      </div> 
     </div> <!-- row --> 
    <div class="row"> 
     <div class="item">
      <input type="checkbox" value="checkbox1">
     </div> 
     <div class="item"></div> 
     <div class="item">callm_1</div> 
     <div class="item">ivr-951</div> 
     <div class="item">WARN</div> 
     <div class="item">1d 22:06</div> 
     <div class="item">55s ago</div> 
     <div class="item">ccv spkid_rivals_reply timeout</div> 
     <div class="item">1d 21:59 ago</div> 
     <div class="item">
      <i class="toggle fa fa-itemumb-tack"></i>
     </div> 
    </div>   <!-- row -->
  </div>   <!-- table -->
  </div> <!-- / .container --> 

and then style the divs (this styling does not a working layout, but might be a starting point).

.table {
  display: flex;
  flex-flow: column nowrap;
  justify-content: space-between;
}
.row {
  display: flex;
  flex-flow: row nowrap;
}
.item {
  display: flex;
  flex-flow: row nowrap;
}

Finally, a third architecture occurred to me. You might be able to use a single (non-nested) table to hold everything, and use specific selectors to control the appearance. Something like this (I am assuming that the 'top-level ' data is a list of servers, and the child data is a list of apps running on that server. Modify the selector names as needed to better match reality).

  <table>
    <tbody>
        <tr class="header">
          <td>Select</td>
          <td>Hostname</td>
          <td>IP/Process</td>
          <td>Version</td>
          <td>Type</td>
          <td>Uptime</td>
          <td>Program Last Seen</td>
          <td>Message</td>gplab
          <td>Event Last Seen</td>
          <td>Pin</td>
      </tr>
      <tr class="host collapsed" id="gplab">
        <td><i class="toggle fa fa-caret-right"></i></td>
        <td>gplab</td>
        <td>172.26.16.24</td>
        <td coli="4"></td>
        <td>1 WARN</td>
        <td></td>
        <td><i class="toggle fa fa-tdumb-tack"></i></td>
      </tr><!-- / tr -->
        <tr class="app collapsed" id="gplab_row_1">
        <td><input type="checkbox" name[]="gplab_app" value="1"></td>
        <td></td>
        <td>callm_1</td>
        <td>ivr-951</td>
        <td>WARN</td>
        <td>1d 22:06</td>
        <td>55s ago</td>
        <td>ccv spkid_rivals_reply timeout</td>
        <td>1d 21:59 ago</td>
        <td><i class="toggle fa fa-tdumb-tack"></i></td>
      </tr><!-- / tr -->
    </tbody><!-- / tbody -->
  </table><!-- / table -->

Now your jQuery can add and remove styling classes based on the hostname, etc. This mi.ght have the advantage of not having to rebuild the entire table

Let me know if this all makes sense.

Tom Sager The last example is pretty much how it works now using two libraries, Treetables.js and DataTables.js

The problem is that Datatables added a search function which would be great except that it breaks relationships.

If I have a host with 3 app call ivr-(something) and I search "ivr" it redraws the tables with any row that contains "ivr" but in most cases it redraws the rows without their host row so essentially it breaks the layout. I thought if I could build in multiple tables where the relationships is solid (items that appear to be contained in another actually are contained then maybe when searching it would maintain said relationship.

pen updated to allow for font-awesome

Tom Sager
Tom Sager
18,987 Points

John - See what you think of this http://codepen.io/regas99/pen/QbmBRM

Each table row has a 'data-host=hostname' attribute to provide server-level grouping. Within each server group, the first row has a 'host' class while the other rows have an 'app' class. You can control visibility using class selectors, and you should be able to search and sort on these as well.

Would this work for you?

Tom Sager, Looks great man. Thank you. If it will maintain the relationship when searching and sorting it will be perfect.

I am trying to make every other row with the class 'host' to be stripped.

tr.host:nth-child(even) {
  background-color: #e4e4e4;
}

Making something odd happening though the first 2 host rows are not stripped and everyone after than is. I added 13 hosts for testing.

Tom Sager
Tom Sager
18,987 Points

First, in cutting and pasting my pen, many of the data-host properties had the wrong host name. (Programs are way better at generating consistent structures than I am.) I think this is a cleaner implementation of the HTML structure http://codepen.io/regas99/pen/oXqKjK

Second, note that I have only been looking at the presentation layer. I do not know how the relationships between your database table and your HTML table are mapped. My solution was to create a single (non-nested) table where rows are differentiated by classes and id's. When you start sorting the table inside the DOM, the relationships will probably have to maintained separately.

Third, the nth-child selector appears to be counting every row in the table before it is selecting for the host class. So if a host happens to be on an even row it will be selected; if on an odd row it will not be selected. This means that then number of hosts and apps (visible and hidden) above the host will determine its styling. Probably not what you had in mind!

Try this styling, then add or subtract a single app in say host3 and see how it changes the host styling for host4 and below. This pretty clearly demonstrates the issue.

tr:nth-child(even) {
  background-color: lightgrey;
}
tr.host:nth-child(even) {
  background-color: skyblue;
}

A quick fix is to override the host style after the nth-child selector:

tr:nth-child(even) {
  background-color: #e4e4e4;
}
tr.host {
  background-color: skyblue;
}

This looks more visually appealing to me. You can probably add more logic to alternate coloring on the host rows, but I don't know what that is off the top of my head.

Tom Sager
Tom Sager
18,987 Points

I do not see any nested tables in your code? They look identical except for line 6, which is "tr" in the first and "/tr" in the second. A nested table would have a second "table" definition inside a <td> in the parent table.

I have not used treetable, but it requires the use of multiple data attributes on the elements. Flexbox might be a better methodology, but it might require an extensive rewrite.

Right... The first is how it should look in respect to how the data is actually related, but that is not a kosher way to code. In fact nesting rows with in rows the DOM just sorts it out and makes them all siblings. The way around this is to nest whole new tables with in a <tr> from another table the DOM then doesn't goes and reorganize them but its a huge taboo to do apparently.

Tom Sager
Tom Sager
18,987 Points

I just reread the question and realized that I had misinterpreted it. I saw "nested tables" and got hung up on that, when the question seems more about displaying nested data in a table. And I originally read your examples as source code instead of as a layout template.

I don't have anything to add to Kevin's excellent suggestions.

No worries and thanks for the help.