From b2de50229e9389c8ba5f6cced85f49997448f8ff Mon Sep 17 00:00:00 2001 From: Allan Jardine Date: Mon, 4 Feb 2013 11:05:40 +0000 Subject: [PATCH] New: `data` and `render` options for columns support function notation - As part of completing the planning development for reading data, I've added support for calling functions from the string defined in `data` and `render` column options. So you can now do something like: `render: 'name()'` rather than needing to use an anon function and calling name() in that. This is useful for cases where you want to give DataTables an array of Javascript instances, rather than objects or arrays (see example below). It also fully supports the continuation of the dotted notation DataTables supports, so you could use `name().first` if `name()` returns an object. Again to make it easier than needed to define a function. - Documentation for `data` and `render` updated to reflect this abilities - Unit tests for this still to come - There is one backwards incompatiblity that should be noted - although I think this is a real edge case and I just can't see it being an issue. If before, you had `data:null` without `render` or `defaultContent` specified, DataTables would have output an empty cell. Now it will output the original data source object. Can't see this being an issue since, why would you have a column empty cells? If this is an issue, then you simply need to add `defaultContent:''` now. - Example use case, using Javascript instances: $(document).ready(function() { var z = function (i) { this.a = function (set) { if ( set ) { return this; } return i+'-0'; }; this.b = function (set) { if ( set ) { return this; } return i+'-1'; }; this.c = function (set) { if ( set ) { return this; } return i+'-2'; }; this.d = function (set) { if ( set ) { return this; } return i+'-3'; }; this.e = function (set) { if ( set ) { return this; } return { q: i+'-4q', w: i+'-4w' }; }; }; window.dataset = [ new z(0), new z(1), new z(2), new z(3), new z(4), new z(5) ]; $('#example').dataTable( { columns: [ { data: null, /*render: 'a()'*/ }, { data: 'b()' }, { data: 'c' }, { data: 'd()' }, { data: 'e().q' } ], data: dataset } ); } ); --- media/src/core/core.data.js | 64 +++++-- media/src/model/model.defaults.columns.js | 216 ++++++++++++++++------ 2 files changed, 211 insertions(+), 69 deletions(-) diff --git a/media/src/core/core.data.js b/media/src/core/core.data.js index c6e63223..b7bd0c6b 100644 --- a/media/src/core/core.data.js +++ b/media/src/core/core.data.js @@ -187,17 +187,17 @@ function _fnGetCellData( oSettings, iRow, iCol, sSpecific ) } /* When the data source is null, we can use default column data */ - if ( sData === null && oCol.sDefaultContent !== null ) + if ( (sData === oData || sData === null) && oCol.sDefaultContent !== null ) { sData = oCol.sDefaultContent; } else if ( typeof sData === 'function' ) { - /* If the data source is a function, then we run it and use the return */ + // If the data source is a function, then we run it and use the return return sData(); } - if ( sSpecific == 'display' && sData === null ) + if ( sData === null && sSpecific == 'display' ) { return ''; } @@ -222,8 +222,9 @@ function _fnSetCellData( oSettings, iRow, iCol, val ) } -// Private variable that is used to match array syntax in the data property object +// Private variable that is used to match action syntax in the data property object var __reArray = /\[.*?\]$/; +var __reFn = /\(\)$/; /** * Return a function that can be used to get data from a source object, taking @@ -238,7 +239,7 @@ function _fnGetObjectDataFn( mSource ) { /* Give an empty string for rendering / sorting etc */ return function (data, type) { - return null; + return data; }; } else if ( typeof mSource === 'function' ) @@ -247,9 +248,10 @@ function _fnGetObjectDataFn( mSource ) return mSource( data, type, extra ); }; } - else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) ) + else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || + mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) { - /* If there is a . in the source string then the data source is in a + /* 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 immediately * return. This allows entire objects to be missing and sDefaultContent to @@ -257,16 +259,19 @@ function _fnGetObjectDataFn( mSource ) */ var fetchData = function (data, type, src) { var a = src.split('.'); - var arrayNotation, out, innerSrc; + var arrayNotation, funcNotation, out, innerSrc; if ( src !== "" ) { for ( var i=0, iLen=a.length ; iUse automatically calculated column index * * @name DataTable.defaults.column.data * @dtopt Columns - * + * * @example * // Read table data from objects + * // JSON structure for each row: + * // { + * // "engine": {value}, + * // "browser": {value}, + * // "platform": {value}, + * // "version": {value}, + * // "grade": {value} + * // } + * $(document).ready( function() { + * $('#example').dataTable( { + * "ajaxSource": "sources/objects.txt", + * "columns": [ + * { "data": "engine" }, + * { "data": "browser" }, + * { "data": "platform" }, + * { "data": "version" }, + * { "data": "grade" } + * ] + * } ); + * } ); + * + * @example + * // Read information from deeply nested objects + * // JSON structure for each row: + * // { + * // "engine": {value}, + * // "browser": {value}, + * // "platform": { + * // "inner": {value} + * // }, + * // "details": [ + * // {value}, {value} + * // ] + * // } * $(document).ready( function() { * $('#example').dataTable( { * "ajaxSource": "sources/deep.txt", @@ -317,7 +380,7 @@ DataTable.defaults.column = { * ] * } ); * } ); - * + * * @example * // Using `data` as a function to provide different information for * // sorting, filtering and display. In this case, currency (price) @@ -345,38 +408,75 @@ DataTable.defaults.column = { * } ] * } ); * } ); + * + * @example + * // Using default content + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": null, + * "defaultContent": "Click to edit" + * } ] + * } ); + * } ); + * + * @example + * // Using array notation - outputting a list from an array + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": "name[, ]" + * } ] + * } ); + * } ); + * */ "mData": null, /** * This property is the rendering partner to `data` and it is suggested that - * when you want to manipulate data for display (including filtering, sorting etc) - * but not altering the underlying data for the table, use this property. `data` - * can actually do everything this property can and more, but this parameter is - * easier to use since there is no 'set' option. Like `data` this can be given - * in a number of different ways to effect its behaviour, with the addition of - * supporting array syntax for easy outputting of arrays (including arrays of - * objects): + * when you want to manipulate data for display (including filtering, + * sorting etc) but not altering the underlying data for the table, use this + * property. `data` can actually do everything this property can and more, + * but this parameter is much easier to use as there is no 'set' option. + * Like `data` this option can be given in a number of different ways to + * effect its behaviour: * - * * integer - treated as an array index for the data source. This is the + * * `integer` - treated as an array index for the data source. This is the * default that DataTables uses (incrementally increased for each column). - * * string - read an object property from the data source. Note that you can - * use Javascript dotted notation to read deep properties / arrays from the - * data source and also array brackets to indicate that the data reader should - * loop over the data source array. When characters are given between the array - * brackets, these characters are used to join the data source array together. - * For example: "accounts[, ].name" would result in a comma separated list with - * the 'name' value from the 'accounts' array of objects. - * * function - the function given will be executed whenever DataTables - * needs to set or get the data for a cell in the column. The function + * * `string` - read an object property from the data source. There are + * three 'special' options that can be used in the string to alter how + * DataTables reads the data from the source object: + * * `.` - Dotted Javascript notation. Just as you use a `.` in + * Javascript to read from nested objects, so to can the options + * specified in `data`. For example: `browser.version` or + * `browser.name`. + * * `[]` - Array notation. DataTables can automatically combine data + * from and array source, joining the data with the characters provided + * between the two brackets. For example: `name[, ]` would provide a + * comma-space separated list from the source array. If no characters + * are provided between the brackets, the original array source is + * returned. + * * `()` - Function notation. Adding `()` to the end of a parameter will + * execute a function of the name given. For example: `browser()` for a + * simple function on the data source, `browser.version()` for a + * function in a nested property or even `browser().version` to get an + * object property if the function called returns an object. + * * `function` - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function * takes three parameters: - * * {array|object} The data source for the row (based on `data`) - * * {string} The type call data requested - this will be 'filter', 'display', - * 'type' or 'sort'. - * * {array|object} The full data source for the row (not based on `data`) - * * The return value from the function is what will be used for the data - * requested. + * * Parameters: + * * {array|object} The data source for the row (based on `data`) + * * {string} The type call data requested - this will be 'filter', + * 'display', 'type' or 'sort'. + * * {array|object} The full data source for the row (not based on + * `data`) + * * Return: + * * The return value from the function is what will be used for the + * data requested. * * @type string|int|function|null * @default null _Use `data`_ @@ -401,6 +501,18 @@ DataTable.defaults.column = { * } ); * * @example + * // Execute a function to obtain data + * $(document).ready( function() { + * $('#example').dataTable( { + * "columnDefs": [ { + * "targets": [ 0 ], + * "data": null, // Use the full data source object for the renderer's source + * "render": "browserName()" + * } ] + * } ); + * } ); + * + * @example * // Use as a function to create a link from the data source * $(document).ready( function() { * $('#example').dataTable( {