+ The DataTable widget is responsible for rendering columnar data into a + highly customizable and fully accessible HTML table. The core + functionality of DataTable is to visualize structured data as a table. + A variety of class extensions can then be used to add features to the + table such as sorting and scrolling. +
+Getting Started
+ ++To include the source files for DataTable and its dependencies, first load +the YUI seed file if you haven't already loaded it. +
+ +<script src="http://yui.yahooapis.com/3.10.3/build/yui/yui-min.js"></script>+ + +
+Next, create a new YUI instance for your application and populate it with the
+modules you need by specifying them as arguments to the YUI().use() method.
+YUI will automatically load any dependencies required by the modules you
+specify.
+
<script>
+// Create a new YUI instance and populate it with the required modules.
+YUI().use('datatable', function (Y) {
+ // DataTable is available and ready for use. Add implementation
+ // code here.
+});
+</script>
+
+
+
+For more information on creating YUI instances and on the
+use() method, see the
+documentation for the YUI Global Object.
+
+Note: be sure to add the yui3-skin-sam classname to the
+page's <body> element or to a parent element of the widget in order to apply
+the default CSS skin. See Understanding Skinning.
+
Upgrading from version 3.4.1 or older?
+ ++ DataTable was refactored for 3.5.0. Some APIs were changed in backward + incompatible ways. +
+ ++ Read the 3.5.0 Migration Guide for tips to + avoid unpleasant surprises. If you still run into issues, please + file a ticket. +
+ +
+ If you are unable to upgrade due to unresolvable issues, you can use the
+ datatable-deprecated
+ module suite, which is equivalent to the 3.4.1 implementation. But be
+ aware that these modules will be removed in a future version of YUI.
+
DataTable Basics
+ +
+ A basic DataTable is made of columns and rows. Define the columns you
+ want to display in your DataTable with the columns attribute. Rows are
+ created for you based on the data you provide to the data attribute.
+
+ Under the hood, the DataTable class uses a + ModelList instance to manage the row + data properties. Read the Table Data Configuration + section below for details about how to load, configure, and work with the + table data. +
+ +// Columns must match data object property names
+var data = [
+ { id: "ga-3475", name: "gadget", price: "$6.99", cost: "$5.99" },
+ { id: "sp-9980", name: "sprocket", price: "$3.75", cost: "$3.25" },
+ { id: "wi-0650", name: "widget", price: "$4.25", cost: "$3.75" }
+];
+
+var table = new Y.DataTable({
+ columns: ["id", "name", "price"],
+ data: data,
+
+ // Optionally configure your table with a caption
+ caption: "My first DataTable!",
+
+ // and/or a summary (table attribute)
+ summary: "Example DataTable showing basic instantiation configuration"
+});
+
+table.render("#example");
+
+
+This code produces this table:
+ + + + + +Column Configuration
+ +
+ The columns attribute takes an array of field names that correspond to
+ property names in the data objects. These field names are called "keys".
+ As long as these keys exist in your data, DataTable will display the
+ values in the table. By default, the key is also used as the label of the
+ column header.
+
+ Use objects instead of key strings to customize how the cells in a column + display. +
+ +// Columns must match data object property names
+var data = [
+ { id: "ga-3475", name: "gadget", price: "$6.99", cost: "$5.99" },
+ { id: "sp-9980", name: "sprocket", price: "$3.75", cost: "$3.25" },
+ { id: "wi-0650", name: "widget", /* missing */ cost: "$3.75" }
+];
+
+var table = new Y.DataTable({
+ columns: [
+ "id",
+ { key: "name", label: "part name" },
+ { key: "price", allowHTML: true, emptyCellValue: "<em>(not set)</em>" },
+ "cost"
+ ],
+ data: data
+});
+
+table.render("#example");
+
+
+This code produces this table:
+ + + + + ++ Some column configurations affect the table headers and others affect the + data cells. +
+ +
+ Use the key property to reference the associated data field when
+ configuring columns with objects. Other supported configuration
+ properties are listed in Appendix A below.
+
Stacked Column Headers
+ +
+ Use the children column configuration to create multiple rows of column
+ headers.
+
var columns = [
+ 'username',
+ {
+ // Important: Parent columns do NOT get a key...
+
+ // but DO get a label
+ label: "Access",
+
+ // Pass an array of column configurations (strings or objects) as children
+ children: [
+ 'read',
+ 'write',
+ ]
+ }
+];
+
+var data = [
+ { username: "root", read: true, write: true },
+ { username: "spilgrim", read: true, write: false },
+ { username: "fizzgig", read: false, write: false }
+];
+
+var table = new Y.DataTable({
+ columns: columns,
+ data : data
+}).render("#example");
+
+
+This code produces this table:
+ + + + + +
+ children takes an array of column configurations, just like the columns
+ attribute itself. The columns defined in the children property will have
+ header cells rendered below the parent column's header.
+
+ Columns that have children don't relate directly to the data cells in the
+ table rows, so they should not have a key configured.
+ They should, however, include a label to provide the header's content.
+
Formatting Cell Data
+ ++ Customizing the content of the cells in your table is done using column + configurations. The most common formatting-related column configurations + are: +
+ +-
+
-
+
allowHTML- set this totrueif your cell data,emptyCellValue, or +formatteroutputs HTML. By default, cell data is HTML escaped for + security. +
+ -
+
emptyCellValue- string to populate cells where no data (empty + string,undefined, ornull) is available in a record. +
+ -
+
formatter- string or function used to translate the raw record data + for each cell in a given column into a format better suited to display. +
+ -
+
nodeFormatter- function used to customize the DOM structure of a + cell, its row, or its surrounding elements. Use with caution. +
+
+ When the formatter configuration setting contains a string it will be assumed
+ to be the key into the hash of formatting functions at Y.DataTable.BodyView.Formatters.
+ If any such function is found, it will be used, otherwise, the string will be
+ presumed to be a template which may contain placeholders for data enclosed
+ in curly braces. The {value} placeholder would use the value destined for
+ the current cell. The values of other fields in the record corresponding
+ to the current row can be shown by providing their name enclosed in curly braces.
+ These other fields
+ don't need to have column definitions of their own, they will simply be read
+ from the underlying Model instance.
+
+ The Y.DataTable.BodyView.Formatters is empty for the developers to provide
+ their own formatting functions. A basic set is provided in module
+ datatable-formatters that has to be explicitly loaded. Some of these
+ named formatters accept extra configuration settings in the column definition,
+ as described in their
+
+ API docs.
+
+ formatter functions are expected to return the string content to populate each
+ cell in that column, and nodeFormatters are provided with the cell Nodes
+ and expected to populate them using the Node API.
+
+ For best performance, avoid
+ nodeFormatters unless absolutely necessary.
+
var columns = [
+ {
+ key: 'item',
+ formatter: '<a href="#{value}">{value}</a>',
+ allowHTML: true // Must be set or the html will be escaped
+ },
+ {
+ key: 'cost',
+ formatter: '${value}' // formatter template string
+ },
+ {
+ key: 'price',
+ formatter: function (o) {
+ if (o.value > 3) {
+ o.className += 'expensive';
+ }
+
+ return '$' + o.value.toFixed(2);
+ }
+ },
+ {
+ label: 'profit',
+ nodeFormatter: function (o) {
+ var profit = o.data.price - o.data.cost,
+ prefix = '$',
+ row;
+
+ if (profit < 0) {
+ prefix = '-' + prefix;
+ profit = Math.abs(profit);
+ row = o.cell.ancestor();
+
+ o.cell.addClass('negative');
+
+ // Assign a rowspan to the first cell and add a new row
+ // below this one to span the last three columns
+ row.one('td').setAttribute('rowspan', 2);
+
+ row.insert(
+ '<tr class="auth"><td colspan="3">' +
+ '<button class="ok">authorize</button>' +
+ '<button class="stop">discontinue</button>' +
+ '</td></tr>',
+ 'after');
+ }
+
+ o.cell.set('text', prefix + profit.toFixed(2));
+ }
+ }
+];
+
+
+This code produces this table:
+ +
+ The parameters passed to formatter functions and nodeFormatter
+ functions are described in Appendix B and Appendix C, respectively. Also look for
+ what can be passed in to the columns in
+ Appendix A.
+
+ Note: It's highly recommended to keep the data in the
+ underlying data ModelList as pure data, free from presentational
+ concerns. For example, use real numbers, not numeric strings, and store
+ link urls and labels either in separate data fields or in a single data
+ field, but as separate properties of a value object. This allows the data
+ to be used for calculations such as sorting or averaging.
+
Setting content with formatter functions
+
+
+ Set the cell content with column formatters by returning the desired
+ content string from the function. Alternately, just update o.value with
+ the new value in the object passed as an argument to the formatter. When
+ updating o.value do not include a return statement.
+
+ formatters are very powerful because not only do they have access to the
+ record's value for that column's field, but they also receive the rest of
+ the record's data, the record Model instance itself, and the column
+ configuration object. This allows you to include any extra configurations
+ in your column configuration that might be useful to customizing how cells
+ in the column are rendered.
+
function currency(o) {
+ return Y.DataType.Number.format(o.value, {
+ prefix : o.column.currencySymbol || '$',
+ decimalPlaces : o.column.decimalPlaces || 2,
+ decimalSeparator : o.column.decimalSeparator || '.',
+ thousandsSeparator: o.column.thousandsSeparator || ','
+ });
+}
+
+var cols = [
+ { key: "price", formatter: currency, decimalPlaces: 3 },
+ ...
+
+
+ If such a formatter will be used regularly, it is best to store it in the
+ Y.DataTable.BodyView.Formatters hash. The formatter can later be used
+ by its name.
+
+ Named formatters are structured slightly differently in + order to improve performance: +
+Y.DataTable.BodyView.Formatters.currency = function (col) {
+ // This is done just once per rendering cycle:
+ var fn = Y.DataType.Number.format,
+ format = {
+ prefix : col.currencySymbol || '$',
+ decimalPlaces : col.decimalPlaces || 2,
+ decimalSeparator : col.decimalSeparator || '.',
+ thousandsSeparator: col.thousandsSeparator || ','
+ };
+ return function (o) {
+ // This is done once per row:
+ return fn(o.value, format);
+ }
+}
+
+
+ The function stored in the Formatters table is not the formatter function
+ itself, instead, it returns the formatting function. The outer function is called just
+ once per rendering cycle and does any preliminary setup usually based on the
+ column configuration which it receives as its only argument, storing any
+ information in local variables. The returned formatting function is then
+ run once per row accessing all the setup information via closure.
+
+ An optional datatable-formatters module provides
+ a collection of such formatters.
+ See the API docs
+ for more information on them.
+
+ See Appendix B for a list of all properties
+ passed to formatter functions.
+
Setting content with nodeFormatter functions
+
+
+ Unlike formatters which can effectively default to the normal rendering
+ logic by leaving o.value unchanged, nodeFormatters must assign content
+ to the cells themselves. The cell's initial classes will be set up, but
+ that's it. Everything else is your responsibility.
+
+ nodeFormatters should return false.
+ See below for details.
+
+ While there are few scenarios that
+ require nodeFormatters, they do have the benefits of having the Node
+ API for constructing more complex DOM subtrees and the ability to access
+ all nodes in the <tbody>. This means they can reference, and even modify,
+ cells in other rows.
+
+ Like formatters, nodeFormatters are provided with the data field value,
+ the record data, the record Model instance, and the column configuration
+ object.
+
+ See Appendix C for a list of all
+ properties passed to nodeFormatter functions.
+
Why formatter and nodeFormatter?
+
+
+ For good rendering performance and memory management, DataTable creates
+ table content by assembling innerHTML strings from templates, with
+ {placeholder} tokens replaced with your data. However, this means that
+ the Nodes don't exist yet when a column's formatters are applied.
+
+ To minimize the need to create Nodes for each cell, the default rendering
+ logic supports the addition of cell classes as well as row classes via
+ formatter functions. Event subscriptions should be
+ delegated
+ from the DataTable instance itself using the
+ delegate() method.
+
+ On the rare occasion that you must use Nodes to supply the cell + data, DataTable allows a second pass over the generated DOM elements once + the initial string concatenation has been completed and the full HTML + content created. +
+ +
+ It is important to note that nodeFormatters will necessarily create a
+ Node instance for each cell in that column, which will increase the memory
+ footprint of your application. If the Node instance wrappers around the
+ DOM elements don't need to be maintained beyond the life of the
+ nodeFormatter, return false to remove them from the internal object
+ cache. This will not remove the rendered DOM, but it will remove
+ event subscriptions made on those Nodes.
+
+ In general, nodeFormatters should only be used if absolutely necessary,
+ and should always return false.
+
Formatters vs. emptyCellValue
+
+
+ The emptyCellValue configuration is useful to provide fallback content in
+ the case of missing or empty column data, but it interacts with each type of
+ formatter differently.
+
+ String formatters will only be applied if the field data for that cell is
+ not undefined. This allows the emptyCellValue to populate the cell.
+
+ Function formatters are applied before the return value or (potentially
+ altered) o.value property is tested for undefined, null, or the empty
+ string. In any of these cases, the emptyCellValue populates the cell.
+
+ The emptyCellValue configuration is ignored by columns configured with
+ nodeFormatters.
+
Table Data Configuration
+ +
+ Each record in the table is stored as a
+ Model instance, where the
+ keys of the record objects become Model attributes. This allows you to
+ interact with the models as you would any other Base-based class, with get(attr),
+ set(attr, value), and subscribing to attribute change events.
+
var data = [
+ { item: "widget", cost: 23.57, price: 47.5 },
+ { item: "gadget", cost: 0.11, price: 6.99 },
+ { item: "sprocket", cost: 4.08, price: 3.75 },
+ { item: "nut", cost: 0.01, price: 0.25 }
+];
+
+var table = new Y.DataTable({
+ columns: ["item", "cost", "price"],
+ data: data
+});
+
+var sprocket = table.getRecord(2);
+
+// Fires a costChange event, and the table is updated if rendered
+sprocket.set('cost', 2.65);
+
+
+
+ The Model class used to store the record data is created for you, based on
+ the objects in the data array. If data is not set, the column keys
+ identified in the columns configuration is used.
+
Specifying the Record Model
+ +
+ To use a custom Model for your records, pass your Model subclass to the
+ recordType attribute.
+
var pieTable = new Y.DataTable({
+ recordType: Y.PieModel,
+ columns: ['slices', 'type'],
+ data: [
+ // Y.PieModel has attributes 'slices', which defaults to 6, and 'type',
+ // which defaults to 'apple'. Records can use these defaults.
+ { type: 'lemon meringue' },
+ { type: 'chocolate creme', slices: 8 },
+ {} // equivalent to { type: 'apple', slices: 6 }
+ ]
+});
+
+// Y.PieModel has its idAttribute assigned to 'type', overriding the default
+// of 'id'. Fetch a PieModel by its id.
+var applePie = pieTable.getRecord('apple');
+
+// eatSlice is a method on the Y.PieModel prototype
+applePie.eatSlice();
+
+
+
+ Alternately, recordType will accept an array of attribute strings or an
+ ATTRS configuration object to make it easier to create custom attribute
+ behaviors without needing to explicitly build the Model subclass.
+
+ If the columns configuration is omitted, but the recordType is set, the
+ columns will default to the recordType's attributes.
+
var data = [
+ { item: "widget", cost: 23.57, price: 47.5 },
+ { item: "gadget", cost: 0.11, price: 6.99 },
+ { item: "sprocket", cost: 4.08, price: 3.75 },
+ { item: "nut", cost: 0.01, price: 0.25 }
+];
+
+// Effectively synonymous with setting the columns attribute if no special
+// column configuration is needed.
+var table = new Y.DataTable({
+ recordType: [ 'item', 'cost', 'price' ],
+ data: data
+});
+
+// Or for more control, pass an ATTRS configuration object
+var table = new Y.DataTable({
+ recordType: {
+ item: {},
+ cost: {
+ value: 0,
+ setter: function (val) { return +val || 0; }
+ },
+ price: {
+ valueFn: function () { return (this.get('cost') + 0.1) * 10; },
+ setter: function (val) { return +val || 0; }
+ }
+ },
+ data: data
+});
+
+
+
+ When the table data is loaded asychronously, it is often a good idea to
+ configure the recordType. This can prevent the generation of a record
+ Model that is missing fields that are omitted from the columns
+ configuration because they aren't intended for viewing.
+
The data ModelList
+
+
+ The record Models are stored in a
+ ModelList, which is assigned to the
+ data property on the instance (for easier access than going through table.get('data')).
+
var records = [
+ { item: "widget", cost: 23.57, price: 47.5 },
+ { item: "gadget", cost: 0.11, price: 6.99 },
+ { item: "sprocket", cost: 4.08, price: 3.75 }
+];
+
+var table = new Y.DataTable({
+ columns: ["item", "cost", "price"],
+ data : records
+});
+
+// Add a new Model using the ModelList API. This will fire
+// events and change the table if rendered.
+table.data.add({ item: "nut", cost: 0.01, price: 0.25 });
+
+
+
+ When assigning the DataTable's data attribute with an array, a ModelList
+ is created for you. But you can also pass a ModelList instance if you are
+ sharing a ModelList between widgets on the page, or you have created custom
+ Model and ModelList classes with additional logic, such as adding a
+ data sync layer.
+
var table = new Y.DataTable({
+ columns: ['type', 'slices'],
+ data: new Y.PieList()
+});
+
+// The Y.PieList class implements a sync layer, enabling its load() method
+table.data.load(function () {
+ table.render('#pies');
+});
+
+
+Getting Remote Table Data
+ ++ To fetch remote data, you have three options: +
+ +-
+
-
+
+ For quick one-offs, you can load and parse the + data manually, using
+Y.io(...),Y.jsonp(...), etc., then assign + that data to the DataTable'sdataattribute. This isn't very + elegant or maintainable, so is best avoided for anything other than + proofs of concept. +
+ -
+
+ For the most control, better maintainability, and + better encapsulation of business logic, create Model and ModelList + subclasses that + implement a + sync layer as suggested above. +
+
+ -
+
+ For common read-only scenarios, use the +
+Y.Plugin.DataTableDataSource+ plugin to bind your table to a +DataSourceinstance. Use + plugins to add DataSource features. +
+
// Create a JSONP DataSource to query YQL
+var myDataSource = new Y.DataSource.Get({
+ source: 'http://query.yahooapis.com/v1/public/yql?format=json&' +
+ 'env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&q='
+});
+
+myDataSource.plug(Y.Plugin.DataSourceJSONSchema, {
+ schema: {
+ resultListLocator: 'query.results.Result',
+ resultFields: [
+ 'Title',
+ 'Phone',
+ {
+ // Important that record fields NOT include ".", so
+ // extract nested data with locators
+ key: 'Rating',
+ locator: "Rating.AverageRating"
+ }
+ ]
+ }
+ })
+ .plug(Y.Plugin.DataSourceCache, {
+ max: 3
+ });
+
+// No data is provided at construction because it will load via the
+// DataTableDataSource plugin
+var table = new Y.DataTable({
+ columns: ['Title', 'Phone', 'Rating'],
+ summary: 'Pizza places near 98089'
+});
+
+table.plug(Y.Plugin.DataTableDataSource, {
+ datasource: myDataSource
+})
+
+// Initially render an empty table and show a loading message
+table.render('#pizza')
+ .showMessage('loadingMessage');
+
+// Load the data into the table
+table.datasource.load({
+ request: encodeURIComponent(
+ 'select *' +
+ ' from local.search' +
+ ' where zip="94089"' +
+ ' and query="pizza"');
+});
+
+
+DataTable Modules and Features
+ +
+ For a basic, stripped down Y.DataTable class, include the datatable-base
+ module in your use().
+
+ Feature modules, such as datatable-sort, will bring in datatable-base
+ automatically. By including only feature modules in your use(), you will
+ get a Y.DataTable that supports specifically those features, without
+ extra code for other features you won't be using.
+
+ The datatable module is a bundle of datatable-base plus a set of common
+ feature modules. Other feature modules need to be included explicitly in
+ use().
+
| Module | +Description | +In datatable? |
+
|---|---|---|
datatable-core |
+
+ The core API for DataTable, implemented as a class extension, used
+ by datatable-base to create Y.DataTable and Y.DataTable.Base.
+ |
+ yes | +
datatable-base |
+
+ Creates the Y.DataTable and Y.DataTable.Base classes, and
+ defaults the headerView and bodyView to Y.DataTable.HeaderView
+ and Y.DataTable.BodyView respectively.
+ |
+ yes | +
datatable-head |
+
+ Creates the Y.DataTable.HeaderView class as a subclass of
+ Y.View. DataTable defers rendering of the <thead> content to
+ this View when it is passed as the DataTable's headerView
+ attribute (the default, as set by datatable-base).
+ |
+ yes | +
datatable-body |
+
+ Creates the Y.DataTable.BodyView class as a subclass of
+ Y.View. DataTable defers rendering of the <tbody> content to
+ this View when it is passed as the DataTable's bodyView
+ attribute (the default, as set by datatable-base).
+ |
+ yes | +
datatable-message |
+
+ Creates the Y.DataTable.Message class extension and adds
+ showMessage and hideMessage methods to Y.DataTable.
+ |
+ yes | +
datatable-column-widths |
+
+ Creates the Y.DataTable.ColumnWidths class extension, and adds
+ support for the width property in column configuration objects
+ to Y.DataTable.
+ |
+ yes | +
datatable-mutable |
+
+ Creates the Y.DataTable.Mutable class extension and adds methods
+ such as addRow, removeRow, and moveColumn to Y.DataTable.
+ |
+ yes | +
datatable-sort |
+
+ Creates the Y.DataTable.Sortable class extension and adds methods
+ sort and toggleSort as well as attributes sortable and
+ sortBy to Y.DataTable. Enables sorting the table rows by
+ clicking on column headers.
+ |
+ yes | +
datatable-datasource |
+
+ Creates the Y.Plugin.DataTableDataSource plugin for binding a
+ DataSource instance to the table as its source of record data.
+ |
+ yes | +
datatable-scroll |
+
+ Creates the Y.DataTable.Scroll class extension and adds attribute
+ scrollable to Y.DataTable. Adds support for vertically and/or
+ horizontally scrolling table rows within fixed table dimensions.
+ |
+ no | +
datatable-formatters |
+
+ Populates Y.DataTable.BodyView.Formatters with a collection of
+ cell formatting functions.
+ |
+ no | +
Features in DataTable.Base
+
+
+ By including only datatable-base in your use() line, you get both
+ Y.DataTable and Y.DataTable.Base classes. With no other module
+ inclusion, these classes are effectively the same. When additional
+ DataTable related modules are included, those modules' features will
+ usually be added to Y.DataTable, but never to
+ Y.DataTable.Base.
+
+ Though it can be instantiated, the purpose of Y.DataTable.Base is
+ primarily as a superclass to a custom DataTable implementation that has a
+ locked set of features that will not be modified, as Y.DataTable can be,
+ by the inclusion of other modules.
+
// Create a custom DataTable that includes only the core set of APIs, plus
+// sorting and message support.
+Y.MyDataTable = Y.Base.create('myTable', Y.DataTable.Base,
+ [ Y.DataTable.Sortable, Y.DataTable.Message ]);
+
+Y.use('datatable-scroll', function (Y) {
+ // Y.DataTable now has support for scrolling
+ var table = new Y.DataTable({ scrollable: 'y', ... });
+
+ // Y.MyDataTable does not (the config does nothing)
+ var myTable = new Y.MyDataTable({ scrollable: 'y', ... });
+});
+
+
+
+ Y.DataTable.Base includes the columns, data, caption, and other
+ basic table attributes, the underlying ModelList and View rendering
+ architecture, as well as methods to fetch rows and cells or columns and
+ records.
+
+ Rendering features include most column configurations, such as children
+ and allowHTML, as well as column formatting options formatter,
+ nodeFormatter, cellTemplate, etc.
+
Table Messages
+ +
+ The datatable-message module adds the ability to display a message in the
+ table body. By default, the "emptyMessage" will display when the table's
+ ModelList has no data records. The message will hide when data is added.
+
var table = new Y.DataTable({
+ columns: ["id", "name", "price"],
+ data: []
+}).render('#example');
+
+
+This code produces this table:
+ + + + + +
+ Use table.showMessage("message") and table.hideMessage() to toggle the
+ message display.
+
+ showMessage supports internationalized strings by using a few named
+ strings, which are registered in the language packs for the
+ datatable-message module . These strings are currently:
+
-
+
-
+
table.showMessage("emptyMessage")defaults to "No data to display". +
+ -
+
table.showMessage("loadingMessage")defaults to "Loading...". +
+
+ Other values passed to showMessage will pass that content directly
+ through to the message Node.
+
Column Width Configuration
+ +
+ The datatable-column-widths module adds basic support for specifying
+ column widths.
+
var table = new Y.DataTable({
+ columns: [
+ { key: 'item', width: '125px' },
+ { key: 'cost', formatter: '${value}' },
+ ...
+ ],
+ data : data
+}).render("#example");
+
+
+This code produces this table:
+ + + + + +
+ CAVEAT: Column widths will expand beyond the configured
+ value if column cells contain data that is long and can't line-wrap. Also,
+ column widths may be reduced below the configured value if the table width
+ (by configuring the DataTable's width attribute, or constrained by a
+ narrow containing element) is too narrow to fit all data at the configured
+ widths.
+
+ To force column widths, including cell data truncation and allowing the
+ table to spill beyond its configured or inherited width, wrap the cell
+ content in a <div> either by configuring the column's formatter or
+ cellTemplate, then assign the <div>'s CSS style with the desired width
+ (or "inherit"), plus overflow: hidden;. Then set the DataTable column's
+ width configuration accordingly.
+
Column sorting
+ +
+ The datatable-sort module adds support for sorting the table rows either
+ through the added APIs or by clicking on the table headers.
+
+ By default, when datatable-sort is included, DataTables will inspects
+ the columns objects, looking for sortable: true to enable table sorting
+ by those columns, triggered by clicking on their respective headers.
+
var cols = [
+ { key: "Company", sortable: true },
+ { key: "Phone" },
+ { key: "Contact", sortable: true }
+];
+
+
+
+ For convenience, you can enable header-click sorting for all columns by
+ setting the sortable attribute to true, or pass an array of column keys
+ to enable just those column's headers.
+
// Set all columns to be sortable
+var table = new Y.DataTable({
+ columns: ["Company", "Phone", "Contact"],
+ data: ...
+ sortable: true
+}).render("#example");
+
+
+This code produces this table:
+ + + + + +
+ Hold down the shift key while clicking on column headers to subsort by
+ that column. Doing so repeatedly will toggle the subsort direction.
+
+ As long as the datatable-sort module has been included, you will always
+ be able to sort the table data through the API, even by columns that aren't
+ configured to accept header-click sorting.
+
+ When a table is sorted, any new records added to the DataTable's ModelList + will be inserted at the proper sorted index, as will the created table + rows. +
+ +
+ Disable header-click sorting by setting sortable to false.
+
+ The default sort order is case insensitive, the sort order can be set to case sensitive
+ by using the caseSensitive attribute, see Appendix A below.
+
Custom Sorting
+ +
+ Assign a function to a column's sortFn to support customized sorting. The
+ function will receive the two records being compared and a boolean flag
+ indicating a descending sort was requested.
+
var columns = [
+ {
+ key: 'id',
+ label: '●', // a big dot
+ formatter: function (o) {
+ return o.value ? '' : '●'; // only new records have a dot
+ },
+ sortable: true,
+ sortFn: function (a, b, desc) {
+ var aid = a.get('id'),
+ bid = b.get('id'),
+ acid = a.get('clientId'),
+ bcid = b.get('clientId'),
+ order = // existing records are equivalent
+ (aid && bid) ? 0 :
+ // new records are grouped apart from existing records
+ (aid && -1) || (bid && 1) ||
+ // new records are sorted by insertion order
+ (acid > bcid) ? 1 : -(acid < bcid);
+
+ return desc ? -order : order;
+ }
+ },
+ ...
+
+
++ The function must return 1, 0, or -1. 1 specifies that the Model passed as + the first parameter should sort below the Model passed as the second + parameter. -1 for above, and 0 if they are equivalent for the purpose of + this sort. +
+ + +Sorting Methods
+ +
+ To sort the table in the code, call table.sort(NAME OR KEY). To
+ toggle the sort direction, call table.toggleSort(NAME OR KEY).
+
// Sorts the table by values in the price field in ascending order
+table.sort('price');
+
+// Flips to descending
+table.toggleSort('price');
+
+
+
+ To sort by multiple columns, pass an array of column keys to sort or
+ toggleSort.
+
+ Calling toggleSort with no arguments will reverse all current sort
+ directions. Calling with specific column names or keys will toggle only
+ those columns.
+
// Sort first by author, subsort by title in ascending order
+table.sort(['author', 'title']);
+
+// Now descending by author then title
+// same as table.toggleSort(['author', 'title']);
+table.toggleSort();
+
+// Now ascending by author, descending by title
+table.toggleSort('author');
+
+
+
+ To specify a sort direction, pass an object instead of a string to sort.
+ The object should have the column name as the key, and sort direction as its
+ value.
+
// Explicitly sort by price in descending order
+table.sort({ price: 'desc' });
+
+// Each column gets its own object
+table.sort([{ author: 'desc' }, { title: 'desc' }]);
+
+
++ Acceptable values for the sort direction are "asc", "desc", 1, and -1. 1 is + equivalent to "asc", and -1 to "desc". +
+ +The sortBy Attribute
+
+
+ Every sort operation updates the sortBy attribute. You can also trigger
+ a sort by setting this attribute directly. It accepts the same values as
+ the sort method.
+
// Sort by author in descending order, then by title in ascending order
+table.set('sortBy', [{ author: -1 }, 'title']);
+
+
++ To specify an initial sort order for your table, assign this attribute + during instantiation. This will sort the data as soon as it is added + to the table's ModelList. +
+ +// Pre-sort the data
+var table = new Y.DataTable({
+ columns: ['item', 'cost', 'price'],
+ data: [...],
+ sortBy: { price: -1 }
+});
+
+
+The sort Event
+
+
+ Clicking on a column header, or calling the sort or toggleSort methods
+ will fire a sort method containing an e.sortBy property that
+ corresponds to the requested sort column and direction. The value will be
+ in either string or object format, depending on how each method was used.
+
+ Preventing the sort event will prevent the sortBy attribute from being
+ updated. Updating the sortBy attribute directly will not fire the sort
+ event, but will still sort the data and update the table.
+
Table Mutation APIs (addRow, etc)
+
+
+ The datatable-mutable module adds APIs for adding, removing, and
+ modifying records and columns.
+
Column Mutation Methods
+ +
+ Use the methods addColumn, removeColumn, modifyColumn, and
+ moveColumn to update the table's configured columns.
+
// Insert a column for the profit field in the data records as the third column
+table.addColumn('profit', 2);
+
+// Actually, make that the fourth column
+table.moveColumn('profit', 3);
+
+// Actually, strike that. Don't show it after all
+table.removeColumn('profit');
+
+// Instead, add a formatter to the price column that includes the profit data
+table.modifyColumn('price', {
+ formatter: function (o) {
+ return o.value + ' (' + (o.data.profit / o.data.cost).toFixed(2) + '%)';
+ }
+});
+
+
++ Each column mutation method fires an identically named event. See + the API docs for details. +
+ +Row Mutation Methods
+ +
+ Use the methods addRow, addRows, removeRow, and modifyRow to update
+ the table's ModelList.
+
table.addRow({ item: 'collet', cost: 0.42, price: 2.65 });
+
+table.addRows([
+ { item: 'nut', cost: 0.42, price: 2.65 },
+ { item: 'washer', cost: 0.01, price: 0.08 },
+ { item: 'bit', cost: 0.19, price: 0.97 }
+]);
+
+// Remove table records by their Model, id, clientId, or index
+table.removeRow(0);
+
+// Modify a record by passing its id, clientId, or index, followed by an
+// object with new field values
+table.modifyRow('record_4', { cost: 0.74 });
+
++ Everything that's done by these methods can be accomplished through the + table's ModelList instance methods, but having methods on the table itself + can make the code more readable. +
+ +// Same as table.addRow(...);
+table.data.add({ item: 'collet', cost: 0.42, price: 2.65 });
+
+
+
+ By default, changes made to the table are only local, they don't update the
+ server or other data origin if the data was served remotely. However, if
+ your table's ModelList is built with a sync layer, the mutation methods
+ can also trigger the appropriate sync behavior by passing an additional
+ argument to the methods, an object with the property sync set to true.
+
// Tell the server we're down to one slice of apple pie!
+table.modifyRow('apple', { slices: 1 }, { sync: true });
+
+// Uh oh, make that 0. No more apple pie :(
+table.removeRow('apple', { sync: true });
+
+
+
+ If all modifications are destined for the server/origin, you can set the
+ autoSync attribute to true, and the row mutation methods will
+ automatically call into the sync layer.
+
var pies = new Y.DataTable({
+ columns: ['type', 'slices'],
+ data: new Y.PieList()
+ autoSync: true
+});
+
+pies.data.load(function () {
+
+ pies.render('#pie-cart');
+
+ // The new PieModel's save() method is called, notifying the server
+ pies.addRow({ type: 'pecan', slices: 8 });
+
+ // Let us eat some pie!
+ pies.modifyRow('lemon meringue', { slices: 5 });
+});
+
+
+Scrolling
+ ++ Note: Scrolling is not currently supported on the Android + WebKit browser. +
+ +
+ Scrolling functionality can be added to Y.DataTable by including
+ datatable-scroll module in your use(). datatable-scroll is
+ NOT included in the datatable rollup module, so must be
+ included separately.
+
+ Enable scrolling by setting the scrollable attribute, which accepts values
+ "x", "y", "xy", true (same as "xy"), or false (the default).
+
+ Note, vertical scrolling also requires the table's height attribute to be
+ set, and horizontal scrolling requires the width to be set.
+
// Data from the seafoodwatch YQL table as of 3/16/2012
+var data = [
+ { "fish": "Barramundi (Imported Farmed in Open Systems)", "recommendation": "avoid" },
+ { "fish": "Caviar, Paddlefish (Wild caught from U.S.)", "recommendation": "avoid" },
+ { "fish": "Caviar, Sturgeon (Imported Wild-caught)", "recommendation": "avoid" },
+ ...
+];
+
+// Enable vertical scrolling with scrollable "y". The width is also set, but
+// because scrollable is not "x" or "xy", this just sets the table width.
+var table = new Y.DataTable({
+ caption: 'Seafood tips for the US West Coast',
+ columns: ['fish', 'recommendation'],
+ data: data,
+ scrollable: "y",
+ height: "200px",
+ width: "400px"
+}).render("#scroll");
+
+
+This code produces this table:
+ + + + + +DataTable Events
+ +
+ DataTable is a composition of supporting class instances and extensions, so
+ to centralize event reporting, it is a bubble target for its data
+ ModelList as well as the View instances used for rendering.
+
+ In other words, some events you may need to subscribe to using an event + prefix to be notified. Often, using a wildcard prefix is the simplest + method to ensure your subscribers will be notified, even if classes change. +
+ +// The sort event is from an extension, so it originates from DataTable
+table.after('sort', function (e) { ... });
+
+// Model changes originate from the record's Model instance, propagate to the
+// table's ModelList, then finally to the DataTable, so they must be
+// subscribed with an event prefix. In this case, we'll use a wildcard
+// prefix.
+table.after('*:priceChange', function (e) { ... });
+
+
+
+ DataTable generates a custom Model class with the "record" event prefix, if
+ you want to be more specific. Otherwise, if your table uses a custom Model
+ class for its recordType, you can prefix Model events with the appropriate
+ prefix.
+
// Allow DataTable to generate the Model class automatically
+var table = new Y.DataTable({
+ columns: ['items', 'cost', 'price'],
+ data: [
+ { item: "widget", cost: 23.57, price: 47.5 },
+ { item: "gadget", cost: 0.11, price: 6.99 },
+ ...
+ ]
+});
+
+// generated Model classes have prefix "record"
+table.after('record:change', function (e) { ... });
+
+// PieList uses PieModels, which have a prefix of, you guessed it, "pie"
+var pies = new Y.DataTable({
+ columns: ['type', 'slices'],
+ data: new Y.PieList()
+});
+
+pies.on('pie:slicesChange', function (e) {
+ if (e.target.get('type') === 'chocolate creme') {
+ // Oh no you don't!
+ e.preventDefault();
+ }
+});
+
+
++ The full list of events is included in the DataTable API docs. +
+ +Known Issues
+ +-
+
- + Scrolling is + not + currently supported on Android WebKit browser. + +
- + Scrolling DataTable + may not + appear scrollable on iOS browsers or OS X 10.7 depending on the + system preference "Show scroll bars" (General). + +
Appendix A: Column Configurations
+ +
+ The properties below are supported in the column configuration objects
+ passed in the columns attribute array.
+
| Configuration | +Description | +Module | +
|---|---|---|
| key | +
+{ key: 'username' }
+
+
+ Binds the column values to the named property in the +
+ Optional if It should not be set if
+ The value is used for the |
+ datatable-base |
+
| name | +
+{ name: 'fullname', formatter: ... }
+
+
+
+ Use this to assign a name to pass to
+ The value is used for the |
+ datatable-base |
+
| field | +
+{ field: 'fullname', formatter: ... }
+
+
+ An alias for |
+ datatable-base |
+
| id | +
+{
+ name: 'checkAll',
+ id: 'check-all',
+ label: ...
+ formatter: ...
+}
+
+
+ Overrides the default unique id assigned + Use this with caution, since it can result in + duplicate ids in the DOM. + + |
+ datatable-base |
+
| label | +
+{ key: 'MfgPrtNum', label: 'Part Number' }
+
+
+ HTML to populate the header |
+ datatable-base |
+
| children | +
+ + Used to create stacked headers. + See the example above. + + +
+ Child columns may also contain
+ Columns configured with |
+ datatable-base |
+
| abbr | +
+{
+ key : 'forecast',
+ label: '1yr Target Forecast',
+ abbr : 'Forecast'
+}
+
+
+ Assigns the value |
+ datatable-base |
+
| title | +
+{
+ key : 'forecast',
+ label: '1yr Target Forecast',
+ title: 'Target Forecast for the Next 12 Months'
+}
+
+
+ Assigns the value |
+ datatable-base |
+
| headerTemplate | +
+{
+ headerTemplate:
+ '<th id="{id}" ' +
+ 'title="Unread" ' +
+ 'class="{className}" ' +
+ '{_id}>●</th>'
+}
+
+
+
+ Overrides the default
+ CELL_TEMPLATE
+ used by
+ Use the
+ Implementers are strongly encouraged to preserve at least
+ the |
+ datatable-base |
+
| cellTemplate | +
+{
+ key: 'id',
+ cellTemplate:
+ '<td class="{className}">' +
+ '<input type="checkbox" ' +
+ 'id="{content}">' +
+ '</td>'
+}
+
+
+
+ Overrides the default
+ CELL_TEMPLATE
+ used by |
+ datatable-base |
+
| formatter | +
+ + Used to customize the content of the data cells for this + column. + + + + |
+ datatable-base |
+
| nodeFormatter | +
+ + Used to customize the content of the data cells for this + column. + + + + |
+ datatable-base |
+
| emptyCellValue | +
+{
+ key: 'price',
+ emptyCellValue: '???'
+}
+
+
+
+ Provides the default value to populate the cell if the data
+ for that cell is |
+ datatable-base |
+
| allowHTML | +
+{
+ key: 'preview',
+ allowHTML: true
+}
+
+
+
+ Skips the security step of HTML escaping the value for cells
+ in this column. This is also necessary if
+ |
+ datatable-base |
+
| className | +
+{
+ key: 'symbol',
+ className: 'no-hide'
+}
+
+
+
+ A string of CSS classes that will be added to the
+ Note, all cells will automatically have a class in the
+ form of "yui3-datatable-col-KEY" added to the |
+ datatable-base |
+
| width | +
+{ key: 'a', width: '400px' },
+{ key: 'b', width: '10em' }
+
+
+
+ Adds a style
+ Note, the assigned width will not truncate cell content, and
+ it will not preserve the configured width if doing so would
+ compromise either the instance's
+ If absolute widths are required, it can be accomplished with
+ some custom CSS and the use of a |
+ datatable-column-widths |
+
| sortable | +
+{ key: 'lastLogin', sortable: true }
+
+
+
+ Used when the instance's
+ If the instance's |
+ datatable-sort |
+
| caseSensitive | +
+{ key: 'lastLogin', sortable: true, caseSensitive: true }
+
+
+
+ When the instance's + Case sensitive sort is marginally more efficient and should be considered + for large data sets when case insensitive sort is not required. + + |
+ datatable-sort |
+
| sortFn | +
+{
+ label: 'Name',
+ sortFn: function (a, b, desc) {
+ var an = a.get('lname') + b.get('fname'),
+ bn = a.get('lname') + b.get('fname'),
+ order = (an > bn) ? 1 : -(an < bn);
+
+ return desc ? -order : order;
+ },
+ formatter: function (o) {
+ return o.data.lname + ', ' + o.data.fname;
+ }
+}
+
+
+
+ Allows a column to be sorted using a custom algorithm. The
+ function receives three parameters, the first two being the
+ two record Models to compare, and the third being a boolean
+
+ The function should return
+ The |
+ datatable-sort |
+
| sortDir | +
+
+ (read-only) If a column is sorted, this
+ will be set to |
+ datatable-sort |
+
| _yuid | +
+
+ (read-only) The unique identifier assigned
+ to each column. This is used for the |
+ datatable-base |
+
| _id | +
+
+ (read-only) A unique-to-this-instance name
+ used extensively in the rendering process. It is also used
+ to create the column's classname, as the input name
+
+ The value is populated by the first of |
+ datatable-base |
+
| _colspan | +
+
+ (read-only) Used by
+ |
+ datatable-base |
+
| _rowspan | +
+
+ (read-only) Used by
+ |
+ datatable-base |
+
| _parent | +
+
+ (read-only) Assigned to all columns in a
+ column's |
+ datatable-base |
+
| _headers | +
+
+ (read-only) Array of the |
+ datatable-base |
+
Appendix B: Formatter Argument Properties
+ +
+ The properties below are found on the object passed to formatter
+ functions defined in a column configuration. See
+ Appendix C for the object properties
+ passed to nodeFormatters.
+
| Property | +Description | +
|---|---|
value |
+
+formatter: function (o) {
+ // assumes a numeric value for this column
+ return '$' + o.value.toFixed(2);
+}
+
+
+
+ The raw value from the record Model to populate this cell.
+ Equivalent to |
+
data |
+
+formatter: function (o) {
+ return o.data.lname + ', ' + o.data.fname;
+}
+
+
+ + The Model data for this row in simple object format. + + |
+
record |
+
+formatter: function (o) {
+ return '<a href="/service/' + o.record.get('id') + '">' +
+ o.value + '</a>';
+}
+
+
+ + The Model for this row. + + |
+
column |
+
+formatter: function (o) {
+ // Use a custom column property
+ var format = o.column.dateFormat || '%D';
+
+ return Y.DataType.Data.format(o.value, format);
+}
+
+
+ + The column configuration object. + + |
+
className |
+
+formatter: function (o) {
+ if (o.value < 0) {
+ o.className += 'loss';
+ }
+}
+
+
+
+ A string of class names to add |
+
rowIndex |
+
+formatter: function (o) {
+ return (o.rowIndex + 1) + ' - ' + o.value;
+}
+
+
+ + The index of the current Model in the ModelList. + Typically correlates to the row index as well. + + |
+
rowClass |
+
+formatter: function (o) {
+ if (o.value < 0) {
+ o.rowClass += 'loss';
+ }
+}
+
+
+
+ A string of css classes to add
+ This is useful to avoid the need for |
+
Appendix C: nodeFormatter Argument Properties
+ +
+ The properties below are found on the object passed to nodeFormatter
+ functions defined in a column configuration. See
+ Appendix B for the object properties
+ passed to formatters.
+
// Reference nodeFormatter
+nodeFormatter: function (o) {
+ if (o.value < o.data.quota) {
+ o.td.setAttribute('rowspan', 2);
+ o.td.setAttribute('data-term-id', this.record.get('id'));
+
+ o.td.ancestor().insert(
+ '<tr><td colspan"3">' +
+ '<button class="term">terminate</button>' +
+ '</td></tr>',
+ 'after');
+ }
+
+ o.cell.setHTML(o.value);
+}
+
+
+| Property | +Description | +
|---|---|
td |
+ The <td> Node for this cell. |
+
cell |
+
+
+ If the cell
+ By default, liner elements aren't rendered into cells, but
+ to implement absolute column widths, some cell liner
+ element with
+ Generally, the liner, if present, corresponds to where the
+ content should go, so use |
+
value |
+
+ The raw value from the record Model to populate this cell.
+ Equivalent to o.record.get(o.column.key) or
+ o.data[o.column.key].
+ |
+
data |
+ The Model data for this row in simple object format. | +
record |
+ The Model for this row. | +
column |
+ The column configuration object. | +
rowIndex |
+ + The index of the current Model in the ModelList. + Typically correlates to the row index as well. + | +
