1
0
mirror of https://github.com/DataTables/DataTables.git synced 2025-01-18 11:52:11 +01:00

Updated: mDataProp syntax now has the ability to accept array syntax (for example "access[].name" would get an array of the 'name' properties from the access property of the data source). This is exceptionally useful for manipulating arrays - however, you are very _strongly_ advised not to use in in mDataProp itself, since when setting arrays, you will overwrite the old array (thus destroying any other properties that it already has!). Instead, see the new mRender property if you want to make use of this syntax for drawing the table.

This commit is contained in:
Allan Jardine 2012-06-29 17:47:00 +01:00
parent 56b0d11c96
commit 0ed6ceda95
4 changed files with 765 additions and 26 deletions

View File

@ -785,6 +785,9 @@
}
// Private variable that is used to match array syntax in the data property object
var __reArray = /\[.*?\]$/;
/**
* Return a function that can be used to get data from a source object, taking
* into account the ability to use nested objects as a source
@ -807,26 +810,63 @@
return mSource( data, type );
};
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
{
/* 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
* level down. On each loop we test for undefined, and if found immediately
* return. This allows entire objects to be missing and sDefaultContent to
* be used if defined, rather than throwing an error
*/
var a = mSource.split('.');
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
var fetchData = function (data, type, src) {
var a = src.split('.');
var arrayNotation, out, innerSrc;
if ( src !== "" )
{
data = data[ a[i] ];
if ( data === undefined )
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
return undefined;
// Check if we are dealing with an array notation request
arrayNotation = a[i].match(__reArray);
if ( arrayNotation ) {
a[i] = a[i].replace(__reArray, '');
data = data[ a[i] ];
out = [];
// Get the remainder of the nested object to get
a.splice( 0, i+1 );
innerSrc = a.join('.');
// Traverse each entry in the array getting the properties requested
for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
out.push( fetchData( data[j], type, innerSrc ) );
}
// If a string is given in between the array notation indicators, that
// is used to join the strings together, otherwise an array is returned
var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
data = (join==="") ? out : out.join(join);
// The inner call to fetchData has already traversed through the remainder
// of the source requested, so we exit from the loop
break;
}
data = data[ a[i] ];
if ( data === undefined )
{
return undefined;
}
}
}
return data;
};
return function (data, type) {
return fetchData( data, type, mSource );
};
}
else
{
@ -858,13 +898,41 @@
mSource( data, 'set', val );
};
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
{
/* Like the get, we need to get data from a nested object. */
var a = mSource.split('.');
return function (data, val) {
/* Like the get, we need to get data from a nested object */
var setData = function (data, val, src) {
var a = src.split('.'), b;
var arrayNotation, o, innerSrc;
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
// Check if we are dealing with an array notation request
arrayNotation = a[i].match(__reArray);
if ( arrayNotation )
{
a[i] = a[i].replace(__reArray, '');
data[ a[i] ] = [];
// Get the remainder of the nested object to set so we can recurse
b = a.slice();
b.splice( 0, i+1 );
innerSrc = b.join('.');
// Traverse each entry in the array setting the properties requested
for ( var j=0, jLen=val.length ; j<jLen ; j++ )
{
o = {};
setData( o, val[j], innerSrc );
data[ a[i] ].push( o );
}
// The inner call to setData has already traversed through the remainder
// of the source and has set the data, thus we can exit here
return;
}
// If the nested object doesn't currently exist - since we are
// trying to set the value - create it
if ( data[ a[i] ] === undefined )
@ -873,7 +941,14 @@
}
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
// If array notation is used, we just want to strip it and use the property name
// and assign the value. If it isn't used, then we get the result we want anyway
data[ a[a.length-1].replace(__reArray, '') ] = val;
};
return function (data, val) {
return setData( data, val, mSource );
};
}
else

View File

@ -360,6 +360,9 @@ function _fnSetCellData( oSettings, iRow, iCol, val )
}
// Private variable that is used to match array syntax in the data property object
var __reArray = /\[.*?\]$/;
/**
* Return a function that can be used to get data from a source object, taking
* into account the ability to use nested objects as a source
@ -382,26 +385,63 @@ function _fnGetObjectDataFn( mSource )
return mSource( data, type );
};
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
{
/* 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
* level down. On each loop we test for undefined, and if found immediately
* return. This allows entire objects to be missing and sDefaultContent to
* be used if defined, rather than throwing an error
*/
var a = mSource.split('.');
return function (data, type) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
var fetchData = function (data, type, src) {
var a = src.split('.');
var arrayNotation, out, innerSrc;
if ( src !== "" )
{
data = data[ a[i] ];
if ( data === undefined )
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
return undefined;
// Check if we are dealing with an array notation request
arrayNotation = a[i].match(__reArray);
if ( arrayNotation ) {
a[i] = a[i].replace(__reArray, '');
data = data[ a[i] ];
out = [];
// Get the remainder of the nested object to get
a.splice( 0, i+1 );
innerSrc = a.join('.');
// Traverse each entry in the array getting the properties requested
for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
out.push( fetchData( data[j], type, innerSrc ) );
}
// If a string is given in between the array notation indicators, that
// is used to join the strings together, otherwise an array is returned
var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
data = (join==="") ? out : out.join(join);
// The inner call to fetchData has already traversed through the remainder
// of the source requested, so we exit from the loop
break;
}
data = data[ a[i] ];
if ( data === undefined )
{
return undefined;
}
}
}
return data;
};
return function (data, type) {
return fetchData( data, type, mSource );
};
}
else
{
@ -433,13 +473,41 @@ function _fnSetObjectDataFn( mSource )
mSource( data, 'set', val );
};
}
else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
{
/* Like the get, we need to get data from a nested object. */
var a = mSource.split('.');
return function (data, val) {
/* Like the get, we need to get data from a nested object */
var setData = function (data, val, src) {
var a = src.split('.'), b;
var arrayNotation, o, innerSrc;
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
// Check if we are dealing with an array notation request
arrayNotation = a[i].match(__reArray);
if ( arrayNotation )
{
a[i] = a[i].replace(__reArray, '');
data[ a[i] ] = [];
// Get the remainder of the nested object to set so we can recurse
b = a.slice();
b.splice( 0, i+1 );
innerSrc = b.join('.');
// Traverse each entry in the array setting the properties requested
for ( var j=0, jLen=val.length ; j<jLen ; j++ )
{
o = {};
setData( o, val[j], innerSrc );
data[ a[i] ].push( o );
}
// The inner call to setData has already traversed through the remainder
// of the source and has set the data, thus we can exit here
return;
}
// If the nested object doesn't currently exist - since we are
// trying to set the value - create it
if ( data[ a[i] ] === undefined )
@ -448,7 +516,14 @@ function _fnSetObjectDataFn( mSource )
}
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
// If array notation is used, we just want to strip it and use the property name
// and assign the value. If it isn't used, then we get the result we want anyway
data[ a[a.length-1].replace(__reArray, '') ] = val;
};
return function (data, val) {
return setData( data, val, mSource );
};
}
else

View File

@ -0,0 +1,399 @@
// DATA_TEMPLATE: dom_data
oTest.fnStart( "Check behaviour of the data get functions that DataTables uses" );
$(document).ready( function () {
// Slightly unusual test set this one, in that we don't really care about the DOM
// but want to test the internal data handling functions but we do need a table to
// get at the functions!
var table = $('#example').dataTable();
var fn, test;
// Object property access
oTest.fnTest(
"Single object, single property",
function () {
fn = table.oApi._fnGetObjectDataFn('test');
test = fn( { "test": true } );
},
function () { return test }
);
oTest.fnTest(
"Single property from object",
function () {
fn = table.oApi._fnGetObjectDataFn('test');
test = fn( { "test": true, "test2": false } );
},
function () { return test }
);
oTest.fnTest(
"Single property from object - different property",
function () {
fn = table.oApi._fnGetObjectDataFn('test2');
test = fn( { "test": true, "test2": false } );
},
function () { return test===false }
);
oTest.fnTest(
"Undefined property from object",
function () {
fn = table.oApi._fnGetObjectDataFn('test3');
test = fn( { "test": true, "test2": false } );
},
function () { return test===undefined }
);
// Array index access
oTest.fnTest(
"Array access - index 0",
function () {
fn = table.oApi._fnGetObjectDataFn(0);
test = fn( [true, false, false, false] );
},
function () { return test }
);
oTest.fnTest(
"Array access - index 1",
function () {
fn = table.oApi._fnGetObjectDataFn(2);
test = fn( [false, false, true, false] );
},
function () { return test }
);
oTest.fnTest(
"Array access - undefined",
function () {
fn = table.oApi._fnGetObjectDataFn(7);
test = fn( [false, false, true, false] );
},
function () { return test===undefined }
);
// null source
oTest.fnTest(
"null source",
function () {
fn = table.oApi._fnGetObjectDataFn( null );
test = fn( [false, false, true, false] );
},
function () { return test===null }
);
// nested objects
oTest.fnTest(
"Nested object property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.b' );
test = fn( {
"a":{
"b": true,
"c": false,
"d": 1
}
} );
},
function () { return test }
);
oTest.fnTest(
"Nested object property - different prop",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.d' );
test = fn( {
"a":{
"b": true,
"c": false,
"d": 1
}
} );
},
function () { return test===1 }
);
oTest.fnTest(
"Nested object property - undefined prop",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.z' );
test = fn( {
"a":{
"b": true,
"c": false,
"d": 1
}
} );
},
function () { return test===undefined }
);
// Nested array
oTest.fnTest(
"Nested array index property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.0' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test }
);
oTest.fnTest(
"Nested array index property - different index",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.2' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test===1 }
);
oTest.fnTest(
"Nested array index property - undefined index",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.10' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test===undefined }
);
// Nested array object property
oTest.fnTest(
"Nested array index object property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.0.m' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () { return test }
);
oTest.fnTest(
"Nested array index object property - different index",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.2.n' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () { return test===3 }
);
oTest.fnTest(
"Nested array index object property - undefined index",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a.0.z' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () { return test===undefined }
);
// Array notation - no join
oTest.fnTest(
"Array notation - no join - property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[].n' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () {
return test.length===3 && test[0]===1
&& test[1]===2 && test[2]===3;
}
);
oTest.fnTest(
"Array notation - no join - property (2)",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[].m' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 }
]
} );
},
function () {
return test.length===2 && test[0]===true
&& test[1]===false;
}
);
oTest.fnTest(
"Array notation - no join - undefined property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[].z' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 }
]
} );
},
function () {
return test.length===2 && test[0]===undefined
&& test[1]===undefined;
}
);
// Array notation - join
oTest.fnTest(
"Array notation - space join - property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[ ].n' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () { return test === '1 2 3'; }
);
oTest.fnTest(
"Array notation - space join - property (2)",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[ ].m' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 }
]
} );
},
function () { return test === 'true false'; }
);
oTest.fnTest(
"Array notation - sapce join - undefined property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[ ].z' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 }
]
} );
},
function () { return test === ' '; }
);
oTest.fnTest(
"Array notation - string join - property",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[qwerty].n' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 },
{ "m": false, "n": 3 }
]
} );
},
function () { return test === '1qwerty2qwerty3'; }
);
oTest.fnTest(
"Array notation - string join - property (2)",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[qwerty].m' );
test = fn( {
"a": [
{ "m": true, "n": 1 },
{ "m": false, "n": 2 }
]
} );
},
function () { return test === 'trueqwertyfalse'; }
);
// Array alone join
oTest.fnTest(
"Flat array join",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[ ]' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test==="true false 1"; }
);
oTest.fnTest(
"Flat array string join",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[qwerty]' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test==="trueqwertyfalseqwerty1"; }
);
oTest.fnTest(
"Flat array no join",
function () {
fn = table.oApi._fnGetObjectDataFn( 'a[]' );
test = fn( {
"a": [
true,
false,
1
]
} );
},
function () { return test.length===3 && test[0]===true &&
test[1]===false && test[2]===1; }
);
oTest.fnComplete();
} );

View File

@ -0,0 +1,190 @@
// DATA_TEMPLATE: dom_data
oTest.fnStart( "Check behaviour of the data set functions that DataTables uses" );
$(document).ready( function () {
// Slightly unusual test set this one, in that we don't really care about the DOM
// but want to test the internal data handling functions but we do need a table to
// get at the functions!
var table = $('#example').dataTable();
var fn, test, o;
// Object property access
oTest.fnTest(
"Create property",
function () {
fn = table.oApi._fnSetObjectDataFn('test');
o = {};
fn( o, true );
},
function () { return o.test }
);
oTest.fnTest(
"Single property doesn't kill other properties",
function () {
fn = table.oApi._fnSetObjectDataFn('test');
o = {
"test2": false
};
fn( o, true );
},
function () { return o.test && o.test2===false; }
);
oTest.fnTest(
"Single property overwrite old property",
function () {
fn = table.oApi._fnSetObjectDataFn('test');
o = {
"test": false,
"test2": false
};
fn( o, true );
},
function () { return o.test && o.test2===false; }
);
// Nested
oTest.fnTest(
"Create nested property",
function () {
fn = table.oApi._fnSetObjectDataFn('test.inner');
o = {
"test": {}
};
fn( o, true );
},
function () { return o.test.inner }
);
oTest.fnTest(
"Deep create nested property",
function () {
fn = table.oApi._fnSetObjectDataFn('test.inner');
o = {};
fn( o, true );
},
function () { return o.test.inner }
);
oTest.fnTest(
"Nested property doesn't kill other properties",
function () {
fn = table.oApi._fnSetObjectDataFn('test.inner');
o = {
"test": {
"test2": false
}
};
fn( o, true );
},
function () { return o.test.inner && o.test.test2===false; }
);
oTest.fnTest(
"Single property overwrite old property",
function () {
fn = table.oApi._fnSetObjectDataFn('nested.test');
o = {
"nested": {
"test": false,
"test2": false
}
};
fn( o, true );
},
function () { return o.nested.test && o.nested.test2===false; }
);
// Set arrays / objects
oTest.fnTest(
"Create object",
function () {
fn = table.oApi._fnSetObjectDataFn('test');
o = {};
fn( o, {"a":true, "b":false} );
},
function () { return o.test.a && o.test.b===false }
);
oTest.fnTest(
"Create nested object",
function () {
fn = table.oApi._fnSetObjectDataFn('nested.test');
o = {};
fn( o, {"a":true, "b":false} );
},
function () { return o.nested.test.a && o.nested.test.b===false }
);
oTest.fnTest(
"Create array",
function () {
fn = table.oApi._fnSetObjectDataFn('test');
o = {};
fn( o, [1,2,3] );
},
function () { return o.test[0]===1 && o.test[2]===3 }
);
oTest.fnTest(
"Create nested array",
function () {
fn = table.oApi._fnSetObjectDataFn('nested.test');
o = {};
fn( o, [1,2,3] );
},
function () { return o.nested.test[0]===1 && o.nested.test[2]===3 }
);
// Array notation
oTest.fnTest(
"Create array of objects",
function () {
fn = table.oApi._fnSetObjectDataFn('test[].a');
o = {};
fn( o, [1,2,3] );
},
function () { return o.test.length===3 && o.test[0].a===1 && o.test[1].a===2; }
);
oTest.fnTest(
"Create array of nested objects",
function () {
fn = table.oApi._fnSetObjectDataFn('test[].a.b');
o = {};
fn( o, [1,2,3] );
},
function () { return o.test.length===3 && o.test[0].a.b===1 && o.test[1].a.b===2; }
);
oTest.fnTest(
"Create array",
function () {
fn = table.oApi._fnSetObjectDataFn('test[]');
o = {};
fn( o, [1,2,3] );
},
function () { return o.test.length===3 && o.test[0]===1 && o.test[1]===2; }
);
oTest.fnComplete();
} );