One-to-many nested datatable in editor
One-to-many nested datatable in editor
Link to test case:
Debugger code (debug.datatables.net):
Error messages shown:
Description of problem:
Is it possible to have a one-to-many nested editor table? I see how you do it in the example here with a checkbox. But I need to have a nested table.
I have a list of tickets which displays fine and I can edit as normal. But then I also have the list of TicketDetails that need edited. See my model below.
data: [
{
"TicketID": 4650,
"TicketTypeID": 1,
"StatusID": 1,
"StatusTitle": "New",
"SeverityID": 1,
"SeverityTitle": "High",
"Subject": "Test 14",
"DateExpected": "/Date(1648699200000)/",
"DateCreated": "/Date(1648758398023)/",
"DateModified": "/Date(1648758398023)/",
"DateCompleted": null,
"CreatedBy": "edavis",
"DepartmentID": 2,
"DepartmentTitle": "IT",
"AssignedTo": null,
"AssignedToDate": null,
"ResolutionID": null,
"ResolutionTitle": null,
"Hours": null,
"TicketDetails": [
{
"Key": 15864,
"TicketDetailID": 15864,
"TicketID": 4650,
"DateCreated": "/Date(1648758398027)/",
"CreatedBy": "edavis",
"Details": "Testing 14"
}
]
}
]
In my editor I have setup my fields as follows
fields: [
{ name: "TicketID", label: 'ID', type: "readonly"},
{
name: "StatusID", label: 'Status',
type: "select",
options: [getStatusDropdownEdit()]},
//{ name: "StatusTitle", label: 'Status' },
{
name: "SeverityID", label: 'Severity',
type: "select",
options: [getSeverityDropdownEdit()] },
//{ name: "SeverityTitle", label: 'Severity' },
{ name: "Subject", label: 'Subject' },
{
name: "DepartmentID", label: 'Department',
type: "select",
options: [getDepartmentDropdownEdit()] },
//{ name: "DepartmentTitle", label: 'Department' },
{
name: "DateCreated", label: 'Date Created', type: "readonly",
data: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}
},
{
name: "DateExpected", label: 'Date Expected', type: "datetime",
data: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}
},
{
name: "DateModified", label: 'Date Modified', type: "readonly",
data: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}, visible: false
},
{
name: "DateCompleted", label: 'Date Completed', type: "readonly",
data: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}
},
{ name: "CreatedBy", label: 'Created By' },
{
name: "AssignedTo", label: 'Assigned To',
type: "select",
options: [getAssignedToDropdownEdit()] },
{
name: "AssignedToDate", label: 'Assigned Date', type: "readonly",
data: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}
},
{
name: "ResolutionID", label: 'Resolution',
type: "select",
options: [getResolutionDropdownEdit()] },
//{ name: "ResolutionTitle", label: 'Resolution' },
{ name: "Hours", label: 'Hours' },
{
label: 'Ticket Details:',
name: 'TicketDetails[]',
type: 'datatable',
editor: ticketDetailsEditor,
optionsPair: {
value: 'id',
},
config: {
searching: false,
info: false,
paging: false,
select: false,
order: [[0, 'asc']],
data: 'TicketDetails[]',
columns: [
{
title: 'ID',
data: 'TicketDetailID',
type: "readonly",
},
{
title: 'Ticket ID',
data: 'TicketID',
type: "readonly",
visible: false
},
{
title: 'Created By',
data: 'CreatedBy',
type: "readonly",
},
{
data: "DateCreated", title: 'Created', type: "date",
render: function (d) {
if (d != null) { return moment(d).format("MM/DD/YYYY HH:mm:ss"); }
else { return ''; }
}
},
{
title: 'Details',
data: 'Details',
type: "readonly",
orderable: false,
}
],
buttons: [
{ extend: "create", className: 'btn-dark', editor: ticketDetailsEditor }
]
}
}
]
You can see in my TicketDetails field I'm trying to pass the data 'TicketDetails[]' but this doesn't work.
I'm trying to set this up so that the nested table (TicketDetails) basically uses local editing, which would allow changes to be submit when I update the parent editor (Tickets) rather than setting this up to have 2 calls to return my data and 2 calls to submit my changes.
Any suggestions? I've found examples of creating a nested child table in the parent table like an accordion but that's not what I'm trying to do. I'm wanting this all to be done in one editor.
Thanks!
Answers
Hi,
Do you mean like this?
It isn't currently possible to have the data batch submitted - i.e. if you edit the child information then that will get submitted and then you come back to the parent view and can select from it.
That specific example shows a single selection only, but you can do multi-selection as well.
Regards,
Allan
Yes, I guess I should have mentioned that I used your nested example to set it up originally. That works but requires multiple ajax calls. I then tried to merge it together with the one-to-many join example.
Would this be a possible future feature request? It seems like between these 2 examples and local table editing you have a lot of what's needed but understand things can be a lot more complicated than meets the eye.
It isn't something that I'd been planning on adding I'm afraid, as I generally consider the Ajax requests to be fairly cheep and at the moment the two Editors would typically call two different controllers. If it was all submitted as one, then there would been to be knowledge about the child Editor instance form the parent. I'd also be concerned about validation errors - say there is a validation error in the child when submitting a parent.
I fear that this would probably be a significant amount of work to remove an Ajax call. Sorry.
Allan
Alright, that makes sense.
One more thing with the nested editor field, how do I pass the TicketID from my parent editor? It's set as the idSrc.
My nested editor ajax call looks like this but I need "3640" to not be hard coded so I can pull the correct details for the ticket.
You could use a variable instead, it doesn't have to be a string constant. How are you expecting to get the value?
Colin
Something like this but it doesn't work because the parent editor (editorEdit) isn't finished initializing yet.
Could you get the value from the table instead - using
row().data()
orcell().data()
? The table itself would be initialised,Colin
I haven't been able to get that to work either.
Looking more into this functionality I'm confused how the optionsPair works. It looks like this situation is what it's used for? It allows to pass the ID to the linked datatable?
Am I not understanding this correctly? Because even when I set it like this I'm not seeing anywhere to grab this value.
By default Editor expected the
options
to containlabel
andvalue
properties in an array of objects. Not all data is structured like that though, so theoptionsPair
let's you control the properties that it looks for - e.g.:I'm not sure that is what you need in this case though! You probably want to reference the TicketID from the host table, rather than the editor form.
Consider the example here I've used
d.site = rowData.id;
whererowData
is the selected row's data (from the parent table).Is that more in keeping with that you are looking for? Perhaps you can link to your page so I can see the full picture?
Allan
best I could come up with is doing an onselect to get my data and store it to a global variable
Then in my nested table ajax call I use
I still don't like this solution though. Seems like there should be an easier way to pass a variable to a nested editor. I've went through the forums and found quite a few post of people trying to do this but it's not possible. Most of the solution suggest creating a child table rather than a nested editor but that's not what I'm looking for.
The solution I posted above has an issue on page load still. When the table is loaded it automatically tries loading the nested datatable data. Since I haven't selected a row yet it's undefined. Is there a way to not make this request until the editor window has been requested? Thanks
Could you send me the full Javascript file you are using there please? It isn't quite clicking for me how all this fits together .
It should certainly be possible to do this without a global variable, but I'm wondering if we might be able to make it easier with some kind of field method
.field('myTable').ajaxData( { ... } )
for example?Allan
Alright here is my entire javascript file. I have a lot going on here. I do actually create a "child table" for my ticket details which can be viewed by hitting the green plus in the row. However, I don't want it editable here. I want everything to be editable in the "main editor" only.
And here are my 2 editors. I had to split everything up due to the length and I am still not showing everything but this should give you a better understanding.
Many thanks. I think this is what I would do in that case:
So when a row is selected in
ticketTable
it causes a redraw of theTicketDetails
DataTable. That, since you have server-side processing enabled for it, will result in an Ajax request to the server, which will trigger thepreXhr
which gets the data for the selected row and appends it to the request.Allan