replicating Parent / child editing in child rows blog
replicating Parent / child editing in child rows blog
Link to test case:
Debugger code (debug.datatables.net):
Error messages shown:
Description of problem:
I am trying to replicate the Parent / child editing in child rows blog on my server.
https://datatables.net/blog/2019-01-11
The section of the client file commented out results in an error when enabled i.e. uncommented.
var siteTable = $("#sites").DataTable({
dom: "Bfrtip",
ajax: "../../Editor-PHP-1.9.4/controllers/sites.php",
order: [1, "asc"],
columns: [
/* {
className: "details-control",
orderable: false,
data: null,
defaultContent: "",
width: "10%"
},
*/
{ data: "name" },
{
data: "users",
render: function(data) {
return data.length;
}
}
],
the error is as follows
jquery-3.3.1.js:3827 Uncaught TypeError: Cannot read property 'style' of undefined
at Fa (jquery.dataTables.min.js:62)
at ha (jquery.dataTables.min.js:48)
at e (jquery.dataTables.min.js:93)
at HTMLTableElement.<anonymous> (jquery.dataTables.min.js:93)
at Function.each (jquery-3.3.1.js:354)
at jQuery.fn.init.each (jquery-3.3.1.js:189)
at jQuery.fn.init.n [as dataTable] (jquery.dataTables.min.js:83)
at jQuery.fn.init.h.fn.DataTable (jquery.dataTables.min.js:165)
at HTMLDocument.<anonymous> ((index):472)
I have created the client file as shown below, the server files are exactly as shown in blog users.php and sites.php.
I have added the CSS and pointed to my server
/* Paren Child CSS */
td.child-table {
background-color: #bfdbff;
}
td.details-control {
background: url('https://dividendlook.co.uk/Editor-PHP-1.9.4/examples/resources/details_open.png') no-repeat center center;
cursor: pointer;
}
tr.shown td.details-control {
background: url('https://dividendlook.co.uk/Editor-PHP-1.9.4/examples/resources/details_open.png') no-repeat center center;
}
Any help in this would be appreciated. I can provide access to my system via PM to investigate if required, with thanks.
To invoke the script
https://www.dividendlook.co.uk/testparentchilde/
PHP script below
https://www.dividendlook.co.uk/wp-admin/post.php?post=25438&action=edit
Best Regards
Colin
Client File below
<head>
<title>Sites Users</title>
<!--
https://editor.datatables.net/examples/advanced/parentChild
https://datatables.net/blog/2016-03-25
-->
<!-- Basic Datatables Editor Initilisation -->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.5.6/css/buttons.dataTables.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/select/1.3.0/css/select.dataTables.min.css" />
<link rel="stylesheet" type="text/css" href="https://www.dividendlook.co.uk/Editor-PHP-1.9.4/css/editor.dataTables.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/css/select2.min.css">
<!-- Basic Datatables Editor Initilisation -->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.4/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/select/1.3.0/js/dataTables.select.min.js"></script>
<script type="text/javascript" src="https://www.dividendlook.co.uk/Editor-PHP-1.9.4/js/dataTables.editor.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/responsive/2.2.3/js/dataTables.responsive.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/js/select2.min.js"></script>
</head>
<table id="sites" class="display">
<thead>
<tr>
<th>Name</th>
<th>Users</th>
</tr>
</thead>
<tbody>
<?php
global $wpdb;
global $current_user;
get_currentuserinfo();
$user_id = $current_user->ID;
$rows = $wpdb->get_results("
SELECT
sites.name AS site,
'1' AS users,
country.name AS country,
first_name AS firstname,
last_name AS lastname,
phone AS phone,
FROM
users
INNER JOIN sites ON (sites.id = users.site)
INNER JOIN country ON (country.id = sites.country_id)
");
foreach ($rows as $row ){
echo "<tr>";
echo "<td>$row->site</td>";
echo "<td>$row->users</td>";
echo "</tr>";
}
<?php
>
?>
<table id="users" class="display">
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Phone #</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<?php
global $wpdb;
global $current_user;
get_currentuserinfo();
$user_id = $current_user->ID;
$rows = $wpdb->get_results("
SELECT
sites.name AS site,
'1' AS users,
first_name AS firstname,
last_name AS lastname,
phone AS phone
FROM
users
INNER JOIN sites ON (sites.id = users.site)
");
foreach ($rows as $row ){
echo "<tr>";
echo "<td>$row->firstname</td>";
echo "<td>$row->lastname</td>";
echo "<td>$row->phone</td>";
echo "<td>$row->location</td>";
echo "</tr>";
}
<?php
>
?>
<input type='hidden' id='passuserid' value='<?php echo $current_user->ID; ?>'>
<script type="text/javascript">
(function($) {
var editor; // use a global for the submit and return data rendering in the examples
$(document).ready(function() {
function createChild(row) {
var rowData = row.data();
// This is the table we'll convert into a DataTable
var table = $('<table class="display" width="100%"/>');
// Display it the child row
row.child(table).show();
// Editor definition for the child table
var usersEditor = new $.fn.dataTable.Editor({
ajax: {
url: "../../Editor-PHP-1.9.4/controllers/users.php",
data: function(d) {
d.site = rowData.id;
}
},
table: table,
fields: [
{
label: "First name:",
name: "users.first_name"
},
{
label: "Last name:",
name: "users.last_name"
},
{
label: "Phone #:",
name: "users.phone"
},
{
label: "Site:",
name: "users.site",
type: "select",
placeholder: "Select a location",
def: rowData.id
}
]
});
// Child row DataTable configuration, always passes the parent row's id to server
var usersTable = table.DataTable({
dom: "Bfrtip",
pageLength: 5,
ajax: {
url: "../../Editor-PHP-1.9.4/controllers/users.php",
type: "post",
data: function(d) {
d.site = rowData.id;
}
},
columns: [
{ title: "First name", data: "users.first_name" },
{ title: "Last name", data: "users.last_name" },
{ title: "Phone #", data: "users.phone" },
{ title: "Location", data: "sites.name" }
],
select: true,
buttons: [
{ extend: "create", editor: usersEditor },
{ extend: "edit", editor: usersEditor },
{ extend: "remove", editor: usersEditor }
]
});
// On change, update the content of the parent table's host row
// This isn't particularly efficient as it requires the child row
// to be regenerated once the main table has been reloaded. A
// better method would be to query the data for the new user counts
// and update each existing row, but that is beyond the scope of
// this post.
usersEditor.on( 'submitSuccess', function (e, json, data, action) {
row.ajax.reload(function () {
$(row.cell( row.id(true), 0 ).node()).click();
});
} );
}
function updateChild(row) {
$("table", row.child())
.DataTable()
.ajax.reload();
}
function destroyChild(row) {
// Remove and destroy the DataTable in the child row
var table = $("table", row.child());
table.detach();
table.DataTable().destroy();
// And then hide the row
row.child.hide();
}
$(document).ready(function() {
var siteEditor = new $.fn.dataTable.Editor({
ajax: "../../Editor-PHP-1.9.4/controllers/sites.php",
table: "#sites",
fields: [
{
label: "Site name:",
name: "name"
}
]
});
var siteTable = $("#sites").DataTable({
dom: "Bfrtip",
ajax: "../../Editor-PHP-1.9.4/controllers/sites.php",
order: [1, "asc"],
columns: [
{
className: "details-control",
orderable: false,
data: null,
defaultContent: "",
width: "10%"
},
//*/
{ data: "name" },
{
data: "users",
render: function(data) {
return data.length;
}
}
],
select: {
style: "os",
selector: "td:not(:first-child)"
},
buttons: [
{ extend: "create", editor: siteEditor },
{ extend: "edit", editor: siteEditor },
{ extend: "remove", editor: siteEditor }
]
});
// Add event listener for opening and closing details
$("#sites tbody").on("click", "td.details-control", function() {
var tr = $(this).closest("tr");
var row = siteTable.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
destroyChild(row);
tr.removeClass("shown");
} else {
// Open this row
createChild(row);
tr.addClass("shown");
}
});
// When updating a site label, we want to update the child table's site labels as well
siteEditor.on("submitSuccess", function() {
siteTable.rows().every(function() {
if (this.child.isShown()) {
updateChild(this);
}
});
});
});
});
}(jQuery));</script>
This question has an accepted answers - jump to answer
Answers
This is usually a mismatch of the number of columns defined in your HTML
table
and the number in Datatables. You have this in yourtable
:But in Datatables you have:
Looks like you need to define a column for the
details-control
.Kevin
Hi Kevin
Thanks for your quick response, that does make sense now to define a column for the details_open.png file icon.
I will take a look and get back to you.
Best Regards Colin
Hi Kevin
All working now, great, so now I will build the equivalent for my website, changes to the client script shown below
also useful reading and HTML example on the following link
https://datatables.net/examples/api/row_details.html
thanks again.
Best Regards
Colin