DataTable being wrapped in another DataTable trying to display data on load
DataTable being wrapped in another DataTable trying to display data on load
Link to test case:
Debugger code (debug.datatables.net): esecax
Error messages shown: N/A
Description of problem:
This is directly related to this question and it pertains to the auto-loading of the data that I'm passing to the initial DT creation. I was attempting to circumvent this problem by simply calling ajax.reload() manually after the table is created from my index file, like so:
<div class="container text-white">
<div class="card">
<div class="card-header">{{ $title }}</div>
<div class="card-body">
{{ $dataTable->table(['data' => $data]) }}
</div>
</div>
</div>
@push('scripts')
{{ $dataTable->scripts(attributes: ['type' => 'module']) }}
<script>
var table = new DataTable('#{{ strtolower($title) }}-table');
table.ajax.reload();
</script>
@endpush
For some reason, it's doing this:
I've included my debug screen so you can see another weird thing that's happening, and that's that it says there's 0 tables on the screen?? It's been doing this for a while, even though my DT is obviously there. In any case, when I run the reload code manually in the console, it works perfectly fine. All I'm trying to do is duplicate that functionality on load, since it won't load the $data I'm passing to it.
If I don't reload the table programmatically, everything in my original DT works perfectly fine (after I hit the callback with an action):
Even if I call the reload from index, the inner DT works fine (after hitting the ajax callback) but the outer DT seems to do nothing no matter what I do. It's as if my new DataTable
call is creating an entirely new table, even though I'm calling it after the original table has been created (that's what the @push('scripts')
is doing)... so anyways, here's the autogenerated HTML:
<div class="container">
<div class="card">
<div class="card-header">REGIONS</div>
<div class="card-body">
<div id="regions-table_wrapper" class="dt-container dt-tailwindcss dt-empty-footer">
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="justify-self-start ">
<div class="dt-length">
<select name="regions-table_length" aria-controls="regions-table" id="dt-length-0">
<option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option>
</select>
<label for="dt-length-0"> entries per page</label>
</div>
</div>
<div class="col-start-2 justify-self-end ">
<div class="dt-search">
<label for="dt-search-0">Search:</label>
<input type="search" id="dt-search-0" placeholder="" aria-controls="regions-table">
</div>
</div>
</div>
<div class="grid grid-cols-1 gap-4 mb-4">
<div class="col-span-2 ">
<div id="regions-table_wrapper" class="dt-container">
<div class="dt-layout-row">
<div class="dt-layout-cell dt-start ">
<div class="dt-length">
<select name="regions-table_length" aria-controls="regions-table" class="dt-input" id="dt-length-0">
<option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option>
</select>
<label for="dt-length-0"> entries per page</label>
</div>
</div>
<div class="dt-layout-cell dt-end ">
<div class="dt-search">
<label for="dt-search-0">Search:</label>
<input type="search" class="dt-input" id="dt-search-0" placeholder="" aria-controls="regions-table">
</div>
</div>
</div>
<div class="dt-layout-row dt-layout-table">
<div class="dt-layout-cell">
<div id="regions-table_processing" class="dt-processing" role="status">
<div>
<div></div><div></div><div></div><div></div>
</div>
</div>
<table class="table dataTable min-w-full text-sm align-middle whitespace-nowrap" id="regions-table" aria-describedby="regions-table_info" style="width: 1060px;">
<colgroup>
<col data-dt-column="0"><col data-dt-column="1"><col data-dt-column="2"><col data-dt-column="3"><col data-dt-column="4">
</colgroup>
<colgroup>
<col data-dt-column="0" style="width: 60px;"><col data-dt-column="1" style="width: 240px;"><col data-dt-column="2" style="width: 240px;"><col data-dt-column="3" style="width: 260px;"><col data-dt-column="4" style="width: 260px;">
</colgroup>
<thead>
<tr role="row">
<th title="Id" width="60" class="dt-orderable-asc dt-orderable-desc dt-ordering-asc" data-dt-column="0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Id: Activate to invert sorting" tabindex="0">
<span class="dt-column-title">Id</span><span class="dt-column-order"></span>
</th>
<th title="Name" width="240" class="dt-orderable-asc dt-orderable-desc" data-dt-column="1" rowspan="1" colspan="1" aria-label="Name: Activate to sort" tabindex="0">
<span class="dt-column-title">Name</span><span class="dt-column-order"></span>
</th>
<th title="Display" width="240" class="dt-orderable-asc dt-orderable-desc" data-dt-column="2" rowspan="1" colspan="1" aria-label="Display: Activate to sort" tabindex="0">
<span class="dt-column-title">Display</span><span class="dt-column-order"></span>
</th>
<th title="Created" width="260" class="dt-orderable-asc dt-orderable-desc" data-dt-column="3" rowspan="1" colspan="1" aria-label="Created: Activate to sort" tabindex="0">
<span class="dt-column-title">Created</span><span class="dt-column-order"></span>
</th>
<th title="Last Updated" width="260" class="dt-orderable-asc dt-orderable-desc" data-dt-column="4" rowspan="1" colspan="1" aria-label="Last Updated: Activate to sort" tabindex="0">
<span class="dt-column-title">Last Updated</span><span class="dt-column-order"></span>
</th>
</tr>
</thead>
<tbody><tr><td colspan="5" class="dt-empty">No data available in table</td></tr></tbody>
<tfoot></tfoot>
</table>
</div>
</div>
<div class="dt-layout-row">
<div class="dt-layout-cell dt-start ">
<div class="dt-info" aria-live="polite" id="regions-table_info" role="status"></div>
</div>
<div class="dt-layout-cell dt-end ">
<div class="dt-paging paging_full_numbers"></div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="justify-self-start ">
<div class="dt-info" aria-live="polite" id="regions-table_info" role="status">Showing 0 to 0 of 0 entries</div>
</div>
<div class="col-start-2 justify-self-end ">
<div class="dt-paging paging_full_numbers">
<ul class="pagination">
<a class="first" aria-controls="regions-table" aria-disabled="true" aria-label="First" data-dt-idx="first" tabindex="-1">«</a>
<a class="previous" aria-controls="regions-table" aria-disabled="true" aria-label="Previous" data-dt-idx="previous" tabindex="-1">‹</a>
<a class="next" aria-controls="regions-table" aria-disabled="true" aria-label="Next" data-dt-idx="next" tabindex="-1">›</a>
<a class="last" aria-controls="regions-table" aria-disabled="true" aria-label="Last" data-dt-idx="last" tabindex="-1">»</a>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
And of course, the JS:
<script>
$(function(){window.LaravelDataTables=window.LaravelDataTables||{};window.LaravelDataTables["regions-table"]=$("#regions-table").DataTable({"serverSide":true,"processing":true,"ajax":"https:\/\/jetstream.lab.utopiafiber.dev\/region-data","columns":[{"data":"id","name":"id","title":"Id","orderable":true,"searchable":true,"width":60},{"data":"name","name":"name","title":"Name","orderable":true,"searchable":true,"width":240},{"data":"display","name":"display","title":"Display","orderable":true,"searchable":true,"width":240},{"data":"created","name":"created","title":"Created","orderable":true,"searchable":true,"width":260},{"data":"last_updated","name":"last updated","title":"Last Updated","orderable":true,"searchable":true,"width":260}],"order":[[1,"desc"]],"paging":true});});
</script>
<script>
var table = new DataTable('#regions-table');
table.ajax.reload();
</script>
And finally, the weirdest part: why my 'after-load' DT looks so much better than my original?? I've deleted non-essential CSS classnames from the above HTML for readability, but the important thing to note is they were both auto-generated. I don't exactly know where or how, so I couldn't tell you if it was a side effect of not creating it through the yajra plugin, or what?
Sorry for throwing so much at y'all, but again, I'm so close to getting it exactly how I want it, but there's just this last hurdle of getting it to show the data on load (or after load, I don't care!) that I can't seem to get past. Thanks in advance for any ideas/suggestions on how to fix this!
Update: Okay so I managed to get the auto-load portion working by using a setTimeout, but I still would like to know why the 2nd DT (not the wrapped/original one) looks so much better, if anyone can shed any light on that? Please??
Answers
So I figured out why (I think) it looks so much better: because it appears to be finishing loading completely. The first DT is throwing an error on load:
Uncaught TypeError: Cannot read properties of undefined (reading '_select')
after which it stops loading and doesn't ever get to load the pagination. I have seen this error before, but was unable to find anything on it online, so I've just been kind of dealing with/ignoring it. But with my "extra" DT that I'm creating in my extra JS, it appears to not be tied to anything (which is why it doesn't work), so it just finishes loading completely (and correctly). So I would assume that my 2nd/extra DT is in fact being created first, which is why my 1st/original DT is nested inside it...
Has anyone ever seen anything like this before? Sorry if this falls outside the scope of DataTables.net, but I've hit up the yajra community multiple times and have got no responses, so...shot in the dark.
Not sure why you need the setTimeout.. I suspect an order of operations issue. I'm not sure what you mean by inner and outer Datatable. We don't know how the Yarja Datatables library functions as its not supported here
The code snippets aren't enough to understand what your solution is. I think the only way we can help is to see a running test case showing the issues so we can understand the code flow and how you are deploying the two Datatables.
https://datatables.net/manual/tech-notes/10
The
var table = new DataTable('#regions-table');
is initializing a new Datatable. It doesn't look like you havedestroy
in line 2, line 5 should result in the Cannot reinitialise DataTable error. Line 5 should look likevar table = $("#regions-table").DataTable();
to get an instance of the Datatable API. For example:Are you saying this is the Datatable that doesn't initially show the data? I would start by looking at the browser's network inspector to see what the response is in the ajax request from line 2. You can post the response here if nothing obvious stands out. Make sure the
draw
parameter matches the value sent. On Datatable initialization thedraw
parameter will always be1
. If the response has a different value it will be ignored.Kevin
...Not sure where my response went...that's the 2nd time I've lost a comment on this site...
anyways, thank you for your response, and great news! I am currently in communication with Yajra, and he is helping me get the DataTable working correctly within Laravel. Hopefully that will also resolve this issue, but so far I'm still experiencing it. I would like to keep this discussion open until I have an answer as to why the DT is getting nested, but at the very least I'd like to provide more information on this forum as far as how Yajra DataTables works in this outlier case.
I agree with you, I don't feel like I should need to use setTimeout (or reload ftm); it should just display the data on initial load. I also feel like it's an order of operations issue, and currently using this line (inside my setTimeout) is working just fine to "fake" the initial load:
$('#regions-table').DataTable().ajax.reload();
. Getting rid of thenew DataTable
call, however, did not get rid of the nested DT. Only my setTimeout is successfully doing that.I'm not quite sure how to see the response from line 2. All I'm seeing is the raw HTML & JS code and then the response from the
ajax.reload
, which would be the response from line 6. I think that's part of my problem, that when line 2 tries to hit the ajax call, it dies with the_select
error. The response from theajax.reload
on line 6 does indeed havedraw: 1
in it.I apologize for not having a running test case I can give you. I fully understand how useful that would be in diagnosing this issue, but I believe part of the reason this is happening at all is because of my weird "database" that this is all built around, and it's that database that prevents me from making a test case for you to look at. I can't actually get to any of the data without logging in, and on top of that, the API endpoint I'm using is inside a VPN. Believe me, I feel your pain.
Are you saying that in the browser's network inspector you are seeing the web page (HTML and JS) in the XHR response?
What do you see if you paste the URL into a web browser?
https://jetstream.lab.utopiafiber.dev/region-data
The request/response to the
ajax.reload()
should havedraw
with the value of 2 since its the second ajax request. Check the payload sent to see the sentdraw
parameter and make sure it matches the response.I'm confused about your description. The code you posted shows one Datatable but you refer to DT 1 and DT 2. Are these two different Datatables? When you say nested Datatable are you saying that
#regions-table
is displayed twice?Can you post a screenshot of the issue?
Kevin
Sorry. Caught by the auto-spam filter. I've marked your account so it shouldn't happen again.
Allan
Much appreciated @allan, thanks!
@kthorngren, I apologize for the confusion. I posted a screenshot of the nesting issue here.
Ehh, not exactly. There's still only ever one
#regions-table
, as you can see in the HTML output I posted (above); however there are two#regions-table_wrapper
s. When I use setTimeout to reload my DT "manually", like so:it does not generate two
#regions-table_wrapper
s, and everything works perfectly (other than initial data load).When I don't use setTimeout, but just call it directly, like so:
there seems to be an order of operations issue (see screenshot above), and I believe the
ajax.reload()
call is getting hit first, and nesting the DT inside the duplicate wrapper (inside the one that saysShowing 0 to 0 of 0 entries
), thus "duplicating" the table. Technically, I guess it's only duplicating the header/footer, but the actual DT is still not generating the paging footer on initial load. The outer wrapper doesn't function, of course, since it's not configured, but the inner one works just fine if I change the number of items to show, thus hitting the callback (correctly). I posted a pic of that (here); that's what it does even if it's nested. I don't care about the whole "nesting" issue so much as I want to get it loading initially correctly. I'm sure that will resolve the nesting issue, as I will no longer need to use a separateajax.reload()
call.Like I mentioned before, Arjay is working with me trying to get this whole mess working correctly, and as helpful as he's been thus far, he's also asked me for a test case. I don't know what more I can do, as I'm limited by my company's access to the data. I apologize again for not having a test case; it's kind of out of my hands. I'm talking to the best & brightest (you and Arjay) in hopes that I can somehow get this working correctly. It's all the fault of my custom "database" that I had to "build"; it's basically just a static object inside the working memory of Laravel (atm) so I had to point Laravel back to the stored data inside my custom class whenever it wants to do a "query". Everything seems to be working just fine once the reload call is hit by the DT, so I don't know what else could possibly need "fixing".
However, Arjay has already had me correct quite a few things, and that's causing some other errors I've fought with previously, so hopefully he can get it working the right way, and hopefully that will fix the initial load issue.
So I apologize if it seems like I'm wasting your time. I'm just...trying to put both of your suggestions together in hopes that I can somehow miraculously get this thing working.
Thank you again so much for all your help.
Sorry I missed seeing the duplicated elements in your original screenshot. See this thread for some simple things too look at.
I also noticed a similar issue with the Datatables examples in this thread. In this case the example pages are loading the datatables.js twice. Make sure you are loading datatables.js and jquery.js once.
Kevin