I want to have a button that deletes all rows from the table. So basically, fire the click function on all instances of the class .table-remove
.
You could do it that way but it's far simpler to organise your table into :
- a
<thead>
containing the header row
- a
<tbody>
containing the visible row(s)
- a
<tbody>
containing the row template
Thus, the code behind the "Delete All" button can very simply select all rows in the first <tbody>
and .remove()
them.
HTML
<div class="container">
<h1>HTML5 Editable Table</h1>
<p>Through the powers of <strong>contenteditable</strong> and some simple jQuery you can easily create a custom editable table. No need for a robust JavaScript library anymore these days.</p>
<ul>
<li>An editable table that exports a hash array. Dynamically compiles rows from headers</li>
<li>Simple / powerful features such as add row, remove row, move row up/down.</li>
</ul>
<div id="table" class="table-editable">
<span class="table-add glyphicon glyphicon-plus"></span>
<table class="table">
<thead> <!-- <<<< wrap the header row in <thead>...</thead> -->
<tr>
<th>Name</th>
<th>Value</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody class="main"> <!-- <<<< wrap the visible row(s) in <tbody>...</tbody> -->
<tr>
<td contenteditable="true">Stir Fry</td>
<td contenteditable="true">stir-fry</td>
<td>
<span class="table-remove glyphicon glyphicon-remove"></span>
</td>
<td>
<span class="table-up glyphicon glyphicon-arrow-up"></span>
<span class="table-down glyphicon glyphicon-arrow-down"></span>
</td>
</tr>
</tbody>
<tbody class="hide"> <!-- <<<< wrap the template row in its own hidden <tbody>...</tbody> -->
<tr>
<td contenteditable="true">Untitled</td>
<td contenteditable="true">undefined</td>
<td>
<span class="table-remove glyphicon glyphicon-remove"></span>
</td>
<td>
<span class="table-up glyphicon glyphicon-arrow-up"></span>
<span class="table-down glyphicon glyphicon-arrow-down"></span>
</td>
</tr>
</tbody>
</table>
</div>
<button id="export-btn" class="btn btn-primary">Export Data</button>
<button id="deleteAll-btn" class="btn btn-primary">Delete All</button>
<p id="export"></p>
</div>
Another aspect is how best to attach click handlers to the three row actions - delete, move-up and move-down.
As the rows are created/appended dynamically, the way to go is to delegate click handling to a container (eg the table) using jQuery's $(static-container).on(event, descendent-selector, handler)
. This will attach the desired actions to all current rows, and future rows just by appending them.
Javascript
jQuery(function($) {
var $TABLE = $('#table table');
var $BTN = $('#export-btn');
var $BTN2 = $('#deleteAll-btn');
var $EXPORT = $('#export');
$('.table-add').on('click', function() {
$('tbody.hide tr', $TABLE).clone(true).appendTo($('tbody.main', $TABLE));
});
$TABLE.on('click', '.table-remove', function() { // delegate row removal to the table
$(this).closest('tr').remove();
});
$TABLE.on('click', '.table-up', function() { // delegate row-up movement to the table
var $row = $(this).closest('tr');
$row.insertBefore($row.prev());
});
$TABLE.on('click', '.table-down', function() { // delegate row-down movement to the table
var $row = $(this).closest('tr');
$row.insertAfter($row.next());
});
$BTN.on('click', function() {
var $headers = $('thead th', $TABLE).not(':empty').map(function() {
return $(this).text().toLowerCase();
});
var $data = $('tbody.main tr', $TABLE).map(function() {
var $td = $(this).find('td'),
h = {};
$headers.each(function(i, header) {
h[header] = $td.eq(i).text();
});
return h;
});
$EXPORT.text(JSON.stringify($headers.get().concat($data.get())));
});
$BTN2.on('click', function deleteAll() {
$("tbody.main tr", $TABLE).remove();
});
});
DEMO.