Having to use setTimeout to pause before executing functions fired by DataTables events
Having to use setTimeout to pause before executing functions fired by DataTables events
There have been plenty of cases when working with DataTables events that I have to find some work-around, because it seems like DataTables is firing off the event before its actually doing the event, or at least before its actually done... has anyone ran into this?
Heres an example, I use the the jQuery x-editable plugin to allow the contents of the table to be edited, however, whenever any new rows are introduced to the DOM after x-editable has already been initiated, then it needs to be re-initiated.
I threw the functionality to re-initiate x-editables inside a start_editable()
function, and here is what I tried at first..
$assets_dt
.on( 'order.dt', function () {
start_editable();
} )
.on( 'length.dt', function ( e, settings, len ) {
start_editable();
} );
Which wasnt working at all, despite when I ran start_editable()
via the JS console, it would work fine.
So I started finding stupid work around, like...
// Execute xEditables on pagination changes (Not sure why it wont work without this..)
$( "ul.pagination, ul.pagination > li, ul.pagination > li > a" ).click(function(){
start_editable();
});
// Needs to also be initiated when the row limit is changed
$('.dataTables_length').find('select').change(function(){
start_editable();
});
Then after having to repeatedly find stupid workarounds like the above for many different events, I thought that maybe the event was being fired off before the new elements in the dom were.. "Settled", if thats the right word. So I tried applying a setTimeout()
with a very short timeout:
// x-editable needs to be re-initiated whenever new rows are introduced to the DOM..
$assets_dt
// Ordering DataTables..
.on( 'order.dt', function () {
setTimeout(function(){
start_editable();
}, 5)
} )
// Changing the page length
.on( 'length.dt', function ( e, settings, len ) {
setTimeout(function(){
start_editable();
}, 5)
} )
// Changing the page itself
.on( 'page.dt', function () {
setTimeout(function(){
start_editable();
}, 5)
} );
And it worked!
So what im asking is, is this a "problem"? or is it normal behavior? Im not a JS/jQuery professional by any means, I just like to code, so maybe this is normal. It just seems to me that the events should be fired off when the event is 100% completed.
This question has an accepted answers - jump to answer
Answers
And while im here...
I run
start_editable()
by itself right after I initialize DataTables, but I think the "proper" way of doing it would be to have it run when DataTables fires theinit
, or even thedraw
.. So I have this setup:But it doesnt seem to work, the Init and Draw dont show up right away in the console, the Draw shows up when I do something else (sort, page, etc), but neither of them fire off when I first load the page... Is there a way to accomplish that?
P.S. It seems clear that if I can get the
init
to work, then that along with thedraw
should be all I need, so I can drop thepage
,length
andorder
Look at the InitComplete configuration option. That's where I run my ApplyEvents() code. The other place I've looked at that sort of things is in the footer draw call back function. I think I used to have some ties to .draw(), but I don't think I do anymore (it is at work).
I did have some funny behavior in IE 8 where I would loose events after filtering. I fixed that with changes in my jQuery selectors.
http://datatables.net/forums/discussion/29740/fixed-header-3-ie-11-in-8-mode-loss-of-events-jquery-selector-fun#latest
@ThomD Ill look at the
initComplete
option callback, but shouldnt the init.dt work as well?..@ThomD So i tried the
initComplete
, and I ran into another issue with using that.So The DataTable is first initialized in the function I have
assets.list()
, this creates the HTML table, then initialized DataTable, then a second function is called,assets.editable()
, which handles all of the editable features (This is because both functions are called in other times, without each other).I can re-initialize DataTables in
assets.editable()
to get a handle on it, but if I add any options to it, I get an error, sayingHeres some of the current code, with the
initComplete
:FYI, I really doubt it matters, but I tried moving all my event hooks above the line wiere DataTables is initialized (in
assets.editable()
, and changed the hooks CSS selector from$assets_dt
to$assets_table
, with no availDT isn't going to like a simple reinitialization, but you can destroy and recreate if needed.
http://datatables.net/reference/api/destroy()
Why are you trying to reInit the DT object?
Take a look a the API reference, there are all sorts of functions to reinit, reload, redraw, etc.
http://datatables.net/reference/api/
Reviewing my code (now that I'm at work), I only apply my on click events in the initComplete option. At one time I had it also triggered by .draw(), but I am not doing that anymore. The key for me is that all of my data is pulled down at once, so all of my processing (filter, sort, search) end with a .draw() event.
I'd start with removing that re-Init part, hooking into InitComplete and see where that gets you. Then, maybe hooking into .draw() if needed.
I asked @allan how to get a handler for a table that was already initialized, but in a different function, he said "Just re-initialize it and you can use that", so it looks like DT doesnt mind simple reinitialization, its the non-simple reinitialization that it doesnt like, meaning any config options will make it throw a hissy fit.
So you have your event handlers inside the
iniComplete
? wow, thats smart...However that doesnt change my issue, i would have to throw them inside the
iniComplete
in the 2nd function, not the function that DT is originally initialized in, so I would have the same error. And theres no way ill destroy it, that will just create issues in the other function, the one that originally initializes it.. lol.Im guessing my
init
isnt working because its trying to run in the 2nd function, meaning DT has already been initialized... hmmTime to step back and take a breath. :) Why do you want to reInit the table?
Is there a way to hand down the DT instance to a function executed via the
initComplete
? So I dont have to execute it manually..Example (Doesnt work im sure):
@thomd, so I can have a handler for it in a different function, but if I can accomplish what I posted above, then I wont need to
actually, I think this might work..
Testing it, ill let ya know :-D
Well this is weird, everything seems to work as I expected, heres the code
But theres an error when I re-order a column... heres the console logs
That error is happening on the line with
.on( 'init.dt', function () {
... So why is it throwing an error in theinit
when that shouldnt even be firing off (its re-ordering, its already successfully initialized)EDIT: Scratch the last error...
assets.editable()
was being called somewhere else, without the DT handler being handed down..So I got it all to work :-D!
/thread
Thanks @thomD !!
Well crap.. I guess I was wrong. I was expecting
this
inside theinitComplete
and whatever variable I assigned the DataTables() to to be the same, which it isn't I guess.I did the following for debugging:
And heres the console: http://d.pr/i/15wZb
I was hoping it would work like that, because inside the
assets.editable()
function, I have some api functions, such asWhich throws an error
!@$(*@#%!@#
I got it to work by doing a crappy work-around (or atleast I think its crappy, is it?)
Relevant code:
So can anyone tell me the difference between what
this
is (inside theDataTables()
, and$assets_dt
? (as invar $assets_dt = $table.DataTable()
@ThomD
Created a LiveDT instance: http://live.datatables.net/qihigezi/1/edit?js,output
That works, so I guess all im asking is, is there a way to accomplish all that, without having to re-init the DT instance inside
assets.editable()
?For example, I have to use
$assets_dt.column( 1 )
in that example, I was hoping i could just use$dt.column( 1 )
, and scrap the re-initialization insideassets.editable()
P.S. Obviously if you wanna see the console log... you know what to do, lol
Oh so close (ain't it always like that?). Inside the InitComplete option, "this" is the parent of the datatables object, so you need to append the .api() method.
For example, here is how I add a column filter to the top of a few columns. Note that my "this" changes once I step into that "every" loop.
Also, I would not try to .draw() individual cells. I use inline editing, so when I update a single row and I need to refresh the data, I make an ajax call. When the results come back, I run this.
When I created the rows, I add an id attribute to the row that hold my key.
I can't help with the X-editable bits. Unless you really like it, you should take a look at the Editor library. It seemlessly integrates with DataTables. (Time is money.)
Hah, perfect! Thanks @ThomD, seems like its working 100% now!
This is probably one of the more complicated set of functions ive coded, which was all to basically do the same thing that DataTables Edit does, but this is going to end up being an Open Source project :( or else I would definitely get it.
Ill end up getting it anyways, might have a paid extension for it or something.
If you see any more room for improvement in here (regarding DataTables, or anything I guess), just by glancing over, let me know! im no JS pro - http://code.linuxdigest.org/view/630f994e
A lot of info here, so I've only scanned it - apologies if I've missed anything. @ThomD is absolutely correct - the execution scope of the callbacks is the HTML table element with an
api()
function attached to it to get the DataTables API instance.Another option is simply to attach the
draw()
event before you initialise the table:Note that the first
draw
will happen before theDataTable()
function has finished executing (and thereforemyTable === undefined
at that point).Allan
Hey @allan. Sorry about the amount of info, the problem kinda morphed into something different than the original post.. lol. What the original problem was, and still is, is that I have to use
setTimeout
in any of the event handlers fired off by DataTable for them to work, if they are affecting things that are in the DOM, within DataTables.Example:
If I dont do that, then they fire off before DataTables is done with whatever event its executing.
I would suggest simply listening for the
draw
event. All of the events you list will proceed a draw event. Which also is why the required elements might not be immediately available in the DOM - they haven't been drawn yet:The
order
event states:That applies to the other events as well.
Allan
Ok, I know I tried this before..
And the problem I had was that it was just wayyy to slow. Maybe I forgot to take the
setTimeout
out, because its out now and it works perfectly fine...Thanks @ThomD & @Allan!