1
0
mirror of https://github.com/DataTables/DataTables.git synced 2024-11-29 11:24:10 +01:00

Fix: When mDataProp was used to get a nested object, but a parent object didn't exist it would throw an unrecoverable error. With this change the behaviour matches that of single level data whereby if data cannot be found, at any level, then undefined is returned from the data get object. This means that if sDefaultContent is defined then that will be used instead, and if not defined an error will still be given (although this one under DataTables' control).

Dev: Removed the "fast lookup" function for data get and set as they weren't really that useful in terms of speed and would require more code to be added to copy with the above change to the error handling for missing objects. Smaller code and virtually no difference in speed. Sold.
This commit is contained in:
Allan Jardine 2012-02-01 08:16:49 +00:00
parent d8f9e6289e
commit 468390c337
4 changed files with 334 additions and 97 deletions

View File

@ -805,33 +805,24 @@
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
{
/* If there is a . in the source string then the data source is in a nested object
* we provide two 'quick' functions for the look up to speed up the most common
* operation, and a generalised one for when it is needed
/* If there is a . in the source string then the data source is in a
* nested object so we loop over the data for each level to get the next
* level down. On each loop we test for undefined, and if found immediatly
* return. This allows entire objects to be missing and sDefaultContent to
* be used if defined, rather than throwing an error
*/
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data, type) {
return data[ a[0] ][ a[1] ];
};
}
else if ( a.length == 3 )
{
return function (data, type) {
return data[ a[0] ][ a[1] ][ a[2] ];
};
}
else
{
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
data = data[ a[i] ];
if ( data === undefined )
{
data = data[ a[i] ];
return undefined;
}
return data;
};
}
}
return data;
};
}
else
{
@ -865,32 +856,15 @@
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
{
/* Like the get, we need to get data from a nested object. Again two fast lookup
* functions are provided, and a generalised one.
*/
/* Like the get, we need to get data from a nested object. */
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data, val) {
data[ a[0] ][ a[1] ] = val;
};
}
else if ( a.length == 3 )
{
return function (data, val) {
data[ a[0] ][ a[1] ][ a[2] ] = val;
};
}
else
{
return function (data, val) {
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
};
}
return function (data, val) {
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
};
}
else
{

View File

@ -380,33 +380,24 @@ function _fnGetObjectDataFn( mSource )
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
{
/* If there is a . in the source string then the data source is in a nested object
* we provide two 'quick' functions for the look up to speed up the most common
* operation, and a generalised one for when it is needed
/* If there is a . in the source string then the data source is in a
* nested object so we loop over the data for each level to get the next
* level down. On each loop we test for undefined, and if found immediatly
* return. This allows entire objects to be missing and sDefaultContent to
* be used if defined, rather than throwing an error
*/
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data, type) {
return data[ a[0] ][ a[1] ];
};
}
else if ( a.length == 3 )
{
return function (data, type) {
return data[ a[0] ][ a[1] ][ a[2] ];
};
}
else
{
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
data = data[ a[i] ];
if ( data === undefined )
{
data = data[ a[i] ];
return undefined;
}
return data;
};
}
}
return data;
};
}
else
{
@ -440,32 +431,15 @@ function _fnSetObjectDataFn( mSource )
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
{
/* Like the get, we need to get data from a nested object. Again two fast lookup
* functions are provided, and a generalised one.
*/
/* Like the get, we need to get data from a nested object. */
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data, val) {
data[ a[0] ][ a[1] ] = val;
};
}
else if ( a.length == 3 )
{
return function (data, val) {
data[ a[0] ][ a[1] ][ a[2] ] = val;
};
}
else
{
return function (data, val) {
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
};
}
return function (data, val) {
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
};
}
else
{

View File

@ -0,0 +1,285 @@
// DATA_TEMPLATE: empty_table
oTest.fnStart( "6872 - mDataProp and sDefaultContent for deep objects" );
$(document).ready( function () {
var test = false;
$.fn.dataTable.ext.sErrMode = "throw";
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Shallow properties
*/
$('#example').dataTable( {
"aaData": [
{
"a": "a",
"b": "b",
"c": "c",
"d": "d",
"e": "e"
}
],
"aoColumns": [
{ "mDataProp": "a" },
{ "mDataProp": "b" },
{ "mDataProp": "c" },
{ "mDataProp": "d" },
{ "mDataProp": "e" }
]
} );
oTest.fnTest(
"Basic initialisation of objects works",
null,
function () { return $('#example tbody td:eq(0)').html() === "a"; }
);
oTest.fnTest(
"Error when property missing (no default content)",
function () {
oSession.fnRestore();
test = false;
try {
$('#example').dataTable( {
"aaData": [
{
"a": "a",
"b": "b",
"d": "d",
"e": "e"
}
],
"aoColumns": [
{ "mDataProp": "a" },
{ "mDataProp": "b" },
{ "mDataProp": "c" },
{ "mDataProp": "d" },
{ "mDataProp": "e" }
]
} );
} catch (e) {
test = true;
}
},
function () { return test; }
);
oTest.fnTest(
"Default content used for missing prop and no error",
function () {
oSession.fnRestore();
$('#example').dataTable( {
"aaData": [
{
"a": "a",
"b": "b",
"d": "d",
"e": "e"
}
],
"aoColumns": [
{ "mDataProp": "a" },
{ "mDataProp": "b" },
{ "mDataProp": "c", "sDefaultContent": "test" },
{ "mDataProp": "d" },
{ "mDataProp": "e" }
]
} );
},
function () { return $('#example tbody td:eq(2)').html() === "test"; }
);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Deep properties with a single object
*/
oTest.fnTest(
"Basic test with deep properties",
function () {
oSession.fnRestore();
$('#example').dataTable( {
"aaData": [
{
"z": {
"a": "a",
"b": "b",
"c": "c",
"d": "d",
"e": "e"
}
}
],
"aoColumns": [
{ "mDataProp": "z.a" },
{ "mDataProp": "z.b" },
{ "mDataProp": "z.c" },
{ "mDataProp": "z.d" },
{ "mDataProp": "z.e" }
]
} );
},
function () { return $('#example tbody td:eq(0)').html() === "a"; }
);
oTest.fnTest(
"Error when property missing on deep get (no default content)",
function () {
oSession.fnRestore();
test = false;
try {
$('#example').dataTable( {
"aaData": [
{
"z": {
"a": "a",
"b": "b",
"c": "c",
"e": "e"
}
}
],
"aoColumns": [
{ "mDataProp": "z.a" },
{ "mDataProp": "z.b" },
{ "mDataProp": "z.c" },
{ "mDataProp": "z.d" },
{ "mDataProp": "z.e" }
]
} );
} catch (e) {
test = true;
}
},
function () { return test; }
);
oTest.fnTest(
"Default content used for missing prop on deep get and no error",
function () {
oSession.fnRestore();
$('#example').dataTable( {
"aaData": [
{
"z": {
"a": "a",
"b": "b",
"c": "c",
"e": "e"
}
}
],
"aoColumns": [
{ "mDataProp": "z.a" },
{ "mDataProp": "z.b" },
{ "mDataProp": "z.c" },
{ "mDataProp": "z.d", "sDefaultContent": "test" },
{ "mDataProp": "z.e" }
]
} );
},
function () { return $('#example tbody td:eq(3)').html() === "test"; }
);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Deep properties with individual objects
*/
oTest.fnTest(
"Basic test with deep individual properties",
function () {
oSession.fnRestore();
$('#example').dataTable( {
"aaData": [
{
"m": { "a": "a" },
"n": { "b": "b" },
"o": { "c": "c" },
"p": { "d": "d" },
"q": { "e": "e" }
}
],
"aoColumns": [
{ "mDataProp": "m.a" },
{ "mDataProp": "n.b" },
{ "mDataProp": "o.c" },
{ "mDataProp": "p.d" },
{ "mDataProp": "q.e" }
]
} );
},
function () { return $('#example tbody td:eq(0)').html() === "a"; }
);
oTest.fnTest(
"Error when property missing on deep individual get (no default content)",
function () {
oSession.fnRestore();
test = false;
try {
$('#example').dataTable( {
"aaData": [
{
"m": { "a": "a" },
"n": { "b": "b" },
"p": { "d": "d" },
"q": { "e": "e" }
}
],
"aoColumns": [
{ "mDataProp": "m.a" },
{ "mDataProp": "n.b" },
{ "mDataProp": "o.c" },
{ "mDataProp": "p.d" },
{ "mDataProp": "q.e" }
]
} );
} catch (e) {
test = true;
}
},
function () { return test; }
);
oTest.fnTest(
"Default content used for missing prop on deep individual get and no error",
function () {
oSession.fnRestore();
$('#example').dataTable( {
"aaData": [
{
"m": { "a": "a" },
"n": { "b": "b" },
"p": { "d": "d" },
"q": { "e": "e" }
}
],
"aoColumns": [
{ "mDataProp": "m.a" },
{ "mDataProp": "n.b" },
{ "mDataProp": "o.c", "sDefaultContent": "test" },
{ "mDataProp": "p.d" },
{ "mDataProp": "q.e" }
]
} );
},
function () { return $('#example tbody td:eq(2)').html() === "test"; }
);
oTest.fnComplete();
} );

View File

@ -387,7 +387,11 @@ var oSession = {
{
while( $.fn.dataTableSettings.length > 0 )
{
$.fn.dataTableSettings[0].oInstance.fnDestroy();
try {
$.fn.dataTableSettings[0].oInstance.fnDestroy();
} catch (e) {
$.fn.dataTableSettings.splice( 0, 1 );
}
}
//$.fn.dataTableSettings.splice( 0, $.fn.dataTableSettings.length );
var nDemo = document.getElementById('demo');