So I've got this HTML snippet to generate the table above:
<div
class="container">
<table
id="actionTabDataTable"
class="table table-striped table-bordered"
cellspacing="0"
width="100%"></table>
</div>
<!-- Modal -->
<div
class="modal fade"
id="myModal"
tabindex="-1"
role="dialog"
aria-labelledby="myModalLabel">
<div
class="modal-dialog"
role="document">
<div
class="modal-content">
<div
class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close">
<span
aria-hidden="true">
×
</span>
</button>
<h4
class="modal-title"
id="myModalLabel">
Please tell us about the job
<span
id="name"></span>
has:
</h4>
</div>
<div
class="modal-body">
<form>
<div
class="form-group">
<label
for="job">
Job title
</label>
<input
type="text"
class="form-control"
id="job"
name="job" />
</div>
</form>
</div>
<div
class="modal-footer">
<button
type="button"
class="btn btn-default"
data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary">
Add
</button>
</div>
</div>
</div>
</div>
And I want to be able to interact with the underlying data which is an array of objects generated from a form further back in the mists of time... or at least earlier in the process anyway. So I use the following snippet of JavaScript:
var data = [{
"name": "John Smith",
"jobs": [
"Bottle Washer",
"Bus Boy"
]
}, {
"name": "Jane Smith",
"jobs": [
"Head Chef",
"Barmaid"
]
}, {
"name": "Barry Smith"
}];
$(function(){
var table = $("#actionTabDataTable").DataTable({
"data": data,
"columns": [{
"title": "Name",
"data": "name"
}, {
"title": "Jobs",
"orderable": false,
"data": "jobs",
"render": function(d) {
if (d) {
return $("<ul></ul>", {
"class": "list-group"
}).append(function() {
var lis = [];
for (var i = 0; i < d.length; i++) {
lis.push($("<li></li>", {
"text": d[i],
"class": "list-group-item"
}).append($("<i></i>", {
"class": "glyphicon glyphicon-remove"
})).append($("<i></i>", {
"class": "glyphicon glyphicon-edit",
"data-toggle": "modal",
"data-target": "#myModal"
})));
}
return lis;
}).prop("outerHTML");
} else {
return "No jobs";
}
}
}, {
"title": "Action",
"orderable": false,
"render": function() {
return $("<button></button>", {
"class": "btn btn-primary",
"text": "Add",
"data-toggle": "modal",
"data-target": "#myModal"
}).append($("<i></i>", {
"class": "glyphicon glyphicon-plus"
})).prop("outerHTML");
}
}]
});
$("#actionTabDataTable tbody").on("click", ".glyphicon-remove", function() {
var d = table.row($(this).parents("tr")).data();
var job = $(this).parents("li").text();
$.each(data, function(k, v) {
if (v.name === d.name) {
console.log(v.jobs.length);
for (var i = 0; i < v.jobs.length; i++) {
if (v.jobs[i] === job) {
v.jobs.splice(i, 1);
!v.jobs.length && delete v.jobs;
break;
}
}
}
});
table.clear().rows.add(data).draw();
}).on("click", ".glyphicon-edit", function() {
var d = table.row($(this).parents("tr")).data();
var job = $(this).parents("li").text();
$("#name").text(d.name);
$("#job").val(job);
$("#myModal").data({
"original": d,
"job": job
}).find(".btn-primary").text("Update");
}).on("click", ".btn-primary", function() {
var d = table.row($(this).parents("tr")).data();
$("#myModal").data("original", d);
$("#name").text(d.name);
});
$("#myModal").on("click", ".btn-primary", function() {
var d = $("#myModal").data("original");
var j = $("#myModal").data("job");
$.each(data, function(k, v) {
if (v.name === d.name) {
if ($("#myModal").find(".btn-primary").text() === "Update") {
$.each(v.jobs, function(a, b) {
if (b === j) {
v.jobs[a] = $("#job").val();
}
});
} else {
if (v.hasOwnProperty("jobs") && Array.isArray(v.jobs)) {
v.jobs.push($("#job").val());
} else {
v.jobs = [$("#job").val()];
}
}
}
});
table.clear().rows.add(data).draw();
$("#myModal").modal("hide");
}).on("hidden.bs.modal", function() {
$("#job").val("");
$("#myModal")
.removeData("original")
.removeData("job")
.find(".btn-primary")
.text("Add");
});
});
Basically this allows us to interact with the underlying data used to generate the table without having to worry about rendering the data again. It's up and running here.
I've had to tweak the CSS a little as well, here it is:
.list-group {
text-align: left;
margin-bottom:0;
}
.glyphicon {
padding: 0 0 0 10px;
cursor: pointer;
float:right;
}