initialization modularity for multi-table page
initialization modularity for multi-table page
Despite the ... obscure title, a fairly simple problem, really.
I have a page with multiple tables on it. They each need their own initializations because they pull from different server-side resources, have different options enabled, etc. However, SOME of the parameters are shared. Now, if I store each COMPLETE initialization object separately, everything is fine. But I tried to make it more modular and ran into a problem. Like some of my other recent questions, probably more of a general JavaScript question.
So, given three arrays: the shared, the custom, and the full or "spliced" array, here's what the attempt looks like (simplified from actual code).
[code]
var initShared = new Array();
var initCustom = new Array();
var initArray = new Array();
initShared = {
"bAutoWidth": false,
"bJQueryUI": true,
"bProcessing": false
}
initCustom = {
"iDisplayLength" : 25,
"aLengthMenu": [[10, 25, 50, 100, 200, -1], [10, 25, 50, 100, 200, "All"]]
}
initArray = initShared.concat(initCustom);
[/code]
It's telling me that concat is not a valid function of initShared. Which means that for whatever reason it doesn't think that initShared is an array...? In any event, the concat doesn't work. And maybe my way of defining the arrays is misguided to begin with...?
One thing's for sure: in a test defining the arrays as [1,2,3] and [4,5,6] (ie. one-dimensional arrays) the concat function works. So it's mainly just simply that concat() can't do what I want it to do on the objects I am trying to pass to it. That leaves me looking for another option.
Any insight on how to keep the code somewhat modular would be great. Since concat() doesn't work, I suspect push() won't work either (about to go try), so I'll have to think outside the box a bit I believe.
Cheers,
Greg
I have a page with multiple tables on it. They each need their own initializations because they pull from different server-side resources, have different options enabled, etc. However, SOME of the parameters are shared. Now, if I store each COMPLETE initialization object separately, everything is fine. But I tried to make it more modular and ran into a problem. Like some of my other recent questions, probably more of a general JavaScript question.
So, given three arrays: the shared, the custom, and the full or "spliced" array, here's what the attempt looks like (simplified from actual code).
[code]
var initShared = new Array();
var initCustom = new Array();
var initArray = new Array();
initShared = {
"bAutoWidth": false,
"bJQueryUI": true,
"bProcessing": false
}
initCustom = {
"iDisplayLength" : 25,
"aLengthMenu": [[10, 25, 50, 100, 200, -1], [10, 25, 50, 100, 200, "All"]]
}
initArray = initShared.concat(initCustom);
[/code]
It's telling me that concat is not a valid function of initShared. Which means that for whatever reason it doesn't think that initShared is an array...? In any event, the concat doesn't work. And maybe my way of defining the arrays is misguided to begin with...?
One thing's for sure: in a test defining the arrays as [1,2,3] and [4,5,6] (ie. one-dimensional arrays) the concat function works. So it's mainly just simply that concat() can't do what I want it to do on the objects I am trying to pass to it. That leaves me looking for another option.
Any insight on how to keep the code somewhat modular would be great. Since concat() doesn't work, I suspect push() won't work either (about to go try), so I'll have to think outside the box a bit I believe.
Cheers,
Greg
This discussion has been closed.
Replies
You are quite right that concat is not quite the way to go there - its an array method, not an object one - and initShared is an object. What you are looking for here can be done with jQuery's extend method: http://api.jquery.com/jQuery.extend/ . With that you can do something like:
[code]
initObject = $.extend( true, {}, initShared, initCustom );
[/code]
Allan
Let me provide some code so that you can see what I'm talking about.
On the same page, I have 2+ DataTables. Let's say that one of them has this initialization:
[code]
alarmsInit = {
"sAjaxSource": "servlet?type=Alarms",
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
/* Based on hidden columns, determine if sources and destinations are Server, Client, or unknown */
/* and then apply a relevant class. */
if (aData[2] == "Server") {
$('td:eq(0)', nRow).addClass('server')
} else if (aData[2] == "Client") {
$('td:eq(0)', nRow).addClass('client')
} else {
$('td:eq(0)', nRow).addClass('unknown')
}
return nRow;
}
[/code]
And the other has this:
[code]
nodesInit = {
"sAjaxSource": "servlet?type=Nodes",
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
/* Based on hidden columns, determine if sources and destinations are Server, Client, or unknown */
/* and then apply a relevant class. */
if (aData[3] == "Server") {
$('td:eq(1)', nRow).addClass('server')
} else if (aData[3] == "Client") {
$('td:eq(1)', nRow).addClass('client')
} else {
$('td:eq(1)', nRow).addClass('unknown')
}
return nRow;
}
[/code]
You can see the problem. I'm doing essentially the same work, with the only difference being the column of the returned data and the visible column (via td) to which a class is applied.
I don't know how I can break out the callback function into something more modular. If the function was not based on dynamic information, I could just declare it as a variable. But since those indexes are different each time, I need to be able to call it as a function, appClassAdder(aDataIndex,tdIndex).
Is this even possible, or am I doomed to copy/paste each time I want to do the same thing?
Apologies for what is essentially a JavaScript question rather than a DataTables question!
[code]
var globalConfig = { ... whatever ... };
var table1config = $.extend( true, globalConfig, { ... table 1 config ... } );
var table2config = $.extend( true, globalConfig, { ... table 2 config ... } );
[/code]
The next major version of DataTables will provide the ability to override the defaults (implemented in a similar manner) which hopefully will help this kind of thing.
Allan
I should probably just implement this to see what happens before commenting back, but I'm a fool, so here goes:
My understanding from earlier in the thread is that this will work great for relatively static configurations. But I'm missing in the above code how I'm able to pass dynamic information. It's the content of the {table 1 config} and {table 2 config} that I need to modularize. I've already implemented an extended config object (the alarmsInit and nodesInit are the equivalent of table1config and table2config)... the part I'm trying to break out now is dynamically applying the class based on cell contents. This part is repeated in each extended configuration object:
[code]
/* Based on hidden columns, determine if sources and destinations are Server, Client, or unknown */
/* and then apply a relevant class. */
if (aData[dataColumn] == "Server") {
$('td:eq(visibleColumn)', nRow).addClass('server')
} else if (aData[dataColumn] == "Client") {
$('td:eq(visibleColumn)', nRow).addClass('client')
} else {
$('td:eq(visibleColumn)', nRow).addClass('unknown')
}
[/code]
I could copy/paste into each of the callbacks with a set number instead of dynamic variables (dataColumn, visibleColumn) but it would be ideal to be able to just do something like:
[code]
nodesInit = {
"sAjaxSource": "servlet?type=Nodes",
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
renderIcons(3,1);
return nRow;
}
[/code]
But "renderIcons()" would have to have access to the aData object and possibly nRow... and I don't think that's possible in terms of scope and in the context of the callback.
If each part of the default initialisation object needs to be overridden then certainly there is scope for this getting a little messy (and confusing :-) ). At that point there really isn't any point in having defaults - although aoColumnDefs with a target class applied to columns might be able to help in some cases - perhaps not this one.
You say:
> But "renderIcons()" would have to have access to the aData object and possibly nRow... and I don't think that's possible in terms of scope and in the context of the callback.
Fair enough - but if renderIcons needs aData and nRow, why not just pass them into the function and have it deal with them as parameters?
Allan
I'm seeing some possibilities!
Do you anticipate much of a performance hit passing around the aData and nRow like that?
Allan