Most languages provide plenty of array utility functions from slicing(), merging, flattening(), filtering() and mapping(), but one thing that you typically have to do yourself is transform arrays to display them in a tabular format. Why would you want to do this? Presenting information in a table is a great way to separate categories, sort elements, as well as maximize screen real estate. I recently arranged an array of objects into a 4 x 3 table of checkboxes in order to avoid having a list of up to 15 items, which would necessitate a lot of scrolling on the user’s part. In today’s article, I’ll show you how to dynamically transform the contents of a one-dimension array into an HTML table on both the server and client, using PHP and JavaScript respectively.
The Array Structure
For the purposes of today’s examples, the display function expects an array of objects where each has two properties: a slug (unique key) and name (label):
- Element 1: {slug: ‘menu_allergen_milk’, name: ‘Milk’}
- Element 2: {slug: ‘menu_allergen_peanut’, name: ‘Peanuts’}
- Element 3: {slug: ‘menu_allergen_sulphites’, name: ‘Sulphur dioxide’}
- Element 4: {slug: ‘menu_allergen_celery’, name: ‘Celery’}
- Element 5: {slug: ‘menu_allergen_seafood’, name: ‘Seafood’}
- Element 6: {slug: ‘menu_allergen_mustard’, name: ‘Mustard’}
- etc…
Producing an HTML Table using PHP
Whatever language you employ to implement the functionality, the idea is always the same:
- Print out the start of the table, up to, but not including the first <TR> row tag.
- Iterate over each array element.
For each element: - If it’s the first cell, print the <TR> row tag.
- Print the table cell and element contents.
- If we’ve printed the number of columns that we want, print the closing <TR> row tag and reset the cell counter.
- Print out the end of the table.
Here is the above operation in PHP code:
//for displaying columns of checkboxes function transform_allergens_array_to_table($column_count) { $cell_index = 1; $html .= '<table name="tblMenuAllergens" width="" cellpadding="1"><thead></thead><tbody>'; for ($i=0; $i < $menu_tags_len; $i++ ) { if ($cell_index == 1) { $html .= '<tr>'; } $id = $menu_tags[$i]['slug']; $name = $menu_tags[$i]['name']; $html .= '<td width="110"><input type="checkbox" name="menu[' . $type . '][]" value="' . $id . '" id="' . $id . '" '; if (array_search($id, $saved_menu_tags) !== false) { $html .= 'checked="checked"'; } $html .= '><label for="' . $id . '">' . $name . '</label></td>' . "n"; if ( ++$cell_index > $column_count ) { //close the row $html .= '</tr>' . "n"; $cell_index = 1; } } $html .= '</tbody></table>' . "n"; return $html; }
Here is an example of the HTML markup produced:
<table name="tblMenuAllergens" width="" cellpadding="1"> <tbody> <tr> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_gluten" id= "menu_allergen_gluten"><label for= "menu_allergen_gluten">Gluten</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_milk" id= "menu_allergen_milk" checked="checked"><label for= "menu_allergen_milk">Milk/lactose</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_eggs" id= "menu_allergen_eggs"><label for= "menu_allergen_eggs">Eggs</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_fish" id= "menu_allergen_fish"><label for= "menu_allergen_fish">Fish</label> </td> </tr> <tr> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_peanut" id= "menu_allergen_peanut" checked="checked"><label for= "menu_allergen_peanut">Peanuts</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_nut" id= "menu_allergen_nut" checked="checked"><label for= "menu_allergen_nut">Nuts</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_soya_beans" id= "menu_allergen_soya_beans"><label for= "menu_allergen_soya_beans">Soyabeans</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_celery" id= "menu_allergen_celery"><label for= "menu_allergen_celery">Celery/celeriac</label> </td> </tr> <tr> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_mustard" id= "menu_allergen_mustard"><label for= "menu_allergen_mustard">Mustard</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_sesame" id= "menu_allergen_sesame"><label for= "menu_allergen_sesame">Sesame seeds</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_lupin_flour" id= "menu_allergen_lupin_flour"><label for= "menu_allergen_lupin_flour">Lupin</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_crustacean" id= "menu_allergen_crustacean"><label for= "menu_allergen_crustacean">Crustaceans</label> </td> </tr> <tr> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_molluscs" id= "menu_allergen_molluscs"><label for= "menu_allergen_molluscs">Molluscs</label> </td> <td width="140"> <input type="checkbox" name="menu[breakfasts][]" value="menu_allergen_sulphites" id= "menu_allergen_sulphites"><label for= "menu_allergen_sulphites">Sulphur dioxide</label> </td> </tr> </tbody> </table>
And here’s what the generated table looks like:
One More Time in JavaScript
Accomplishing the same thing in JavaScript requires surprisingly few syntax changes. In the following client-side code, the selected allergens are displayed within a table in a read-only format – i.e., without the checkboxes. Another change is that empty cells are added to complete the last row if necessary. It just looks better with borders.
I prefer to place the script at the bottom of the page and invoke printArrayInTabularFormat() as an inline function. You can even pass arguments to it by including them in the closing parentheses!
var $menu_tags = [ {slug: 'menu_allergen_milk', name: 'Milk'}, {slug: 'menu_allergen_peanut', name: 'Peanuts'}, {slug: 'menu_allergen_sulphites', name: 'Sulphur dioxide'}, {slug: 'menu_allergen_celery', name: 'Celery'}, {slug: 'menu_allergen_seafood', name: 'Seafood'}, {slug: 'menu_allergen_mustard', name: 'Mustard'} ]; var MENU_TAGS_COLUMN_COUNT = 4; (function printArrayInTabularFormat(menuTags, colCount) { var html = '<table name="tblMenuAllergens" cellpadding="1" border="1"><thead></thead><tbody>' + "n"; var cellIndex=1; for (var $i=0; $i<menuTags.length; $i++) { if (cellIndex == 1) { html += '<tr>'; } var $id = menuTags[$i]['slug']; var $name = menuTags[$i]['name']; html += '<td width="120">' + $name + '</td>' + "n"; if (++cellIndex > colCount) { //close the row html += '</tr>'; cellIndex = 1; } } //finish empty cells var remainingCellsCount = menuTags.length % colCount; if (remainingCellsCount) { for (var $i=0; $i<remainingCellsCount; $i++) { html += '<td width="120"> </td>' + "n"; } html += '</tr>'; } html += '</tbody></table>' + "n"; html += '</td></tr></tbody></table>' + "n"; document.getElementById('allergensTable').innerHTML = html; })($menu_tags, MENU_TAGS_COLUMN_COUNT);
Here is the generated code this time:
<table name="tblMenuAllergens" cellpadding="1" border="1"> <tbody> <tr> <td width="120"> Milk </td> <td width="120"> Peanuts </td> <td width="120"> Sulphur dioxide </td> <td width="120"> Celery </td> </tr> <tr> <td width="120"> Seafood </td> <td width="120"> Mustard </td> <td width="120"> </td> <td width="120"> </td> </tr> </tbody> </table>
…which looks like this in the browser:
Milk | Peanuts | Sulphur dioxide | Celery |
Seafood | Mustard |
Conclusion
For best results I would remove all of the table, row, and cell attributes and move them to a CSS file. That would help make the function as generic as possible.