index.mustache revision 9563d8a01a40e508f7697d9c674c164512940371
<style type="text/css">
.yui3-datatable table {
width: auto;
}
.yui3-datatable td, .yui3-datatable th {
border: 0 none;
}
</style>
<div class="intro component">
<p>
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.
</p>
</div>
{{>getting-started}}
<h2 id="using">DataTable Basics</h2>
<p>
A basic DataTable is comprised 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.
</p>
```
// 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("#example1");
```
<p>This code produces this table:</p>
<div id="example1" class="yui3-skin-sam"></div>
<script>
YUI().use('datatable-base', function (Y) {
// 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,
caption: "My first DataTable!",
summary: "Example DataTable showing basic instantiation configuration"
});
table.render("#example1");
});
</script>
<h2 id="columns">Working with columns</h2>
<p>
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 these
columns in the table. By default, the key is also used as the label of the
column header.
</p>
<h3 id="column-configs">Column Configurations</h3>
<p>
For greater flexibility, columns can also be identified with configuration
objects. When identifying a column with a configuration object, use the
`key` property to reference the associated data field (the string you would
have used to identify the column if you didn't need more configuration).
Otherwise, you can include any number of additional configuration
properties to customize how your data renders and behaves, depending on
which table extensions or plugins you have included.
</p>
<p>
Some column configurations affect the table headers and others affect the
data cells. The full list of configurations is listed in <a
href="#column-config">Column Configurations list</a> below.
</p>
```
var cols = [
{
// The key relates this column to a data field
key: "mfr-parts-database-id",
// The label is the text that will be rendered in the table head
label: "Mfr Part ID",
// The abbr sets the <th>s abbr attribute
abbr: "ID"
},
{
key: "mfr-parts-database-name",
label: "Mfr Part Name",
abbr: "Name",
// Allows user clicks on the header to sort the table rows by the
// values in this column. Requires the `datatable-sort` module.
sortable: true
},
{
key: "mfr-parts-database-price",
label: "Wholesale Price",
abbr: "Price",
// The emptyCellValue provides default content for data cells if a data
// row has no value for this field
emptyCellValue: '<em>(not set)</em>',
// The allowHTML configuration permits markup in data values to pass
// directly into the data cell's innerHTML.
allowHTML: true,
sortable: true
}
];
var data = ...
var table = new Y.DataTable({
columns: cols,
data : data
});
table.render('#example2');
```
<p>This code produces this table:</p>
<div id="example2" class="yui3-skin-sam"></div>
<script>
YUI().use('datatable-sort', function (Y) {
var cols = [
{
key: "mfr-parts-database-id",
label: "Mfr Part ID",
abbr: "ID"
},
{
key: "mfr-parts-database-name",
label: "Mfr Part Name",
abbr: "Name",
sortable: true
},
{
key: "mfr-parts-database-price",
label: "Wholesale Price",
abbr: "Price",
emptyCellValue: '<em>(not set)</em>',
allowHTML: true,
sortable: true
}
];
var data = [
{ "mfr-parts-database-id": "ga-3475", "mfr-parts-database-name": "gadget", "mfr-parts-database-price": "$6.99", cost: "$5.99" },
{ "mfr-parts-database-id": "sp-9980", "mfr-parts-database-name": "sprocket", "mfr-parts-database-price": "$3.75", cost: "$3.25" },
{ "mfr-parts-database-id": "wi-0650", "mfr-parts-database-name": "widget", "mfr-parts-database-price": "", cost: "$3.75" },
{ "mfr-parts-database-id": "nu-0001", "mfr-parts-database-name": "nut", "mfr-parts-database-price": "$0.25", cost: "$3.75" }
];
var table = new Y.DataTable({
columns: cols,
data: data
});
table.render("#example2");
});
</script>
<h3 id="nested">Multi-row Headers</h3>
<p>
Use the `children` column configuration to created nested column headers.
The `children` configuration takes an array of column configurations, just
like the `columns` attribute itself. The columns defined in the `children`
property will have their header cells rendered in the row below that
column's header.
</p>
<p>
Because columns that have children don't relate directly to the data in the
table rows, they should not have a `key` configured. Instead, include a
`label` to provide the header's content.
</p>
```
var nestedCols = [
{
// Important: Parent columns do NOT get a key...
// but DO get a label
label: "Train Schedule",
// Pass an array of column configurations (strings or objects) as children
children: [
"track",
{
label: "Route",
children: [
{ key: "from" },
{ key: "to" }
]
}
]
}
];
var data = [
{ track: "1", from: "Paris", to: "Amsterdam" },
{ track: "2", from: "Paris", to: "London" },
{ track: "3", from: "Paris", to: "Zurich" }
];
var table = new Y.DataTable({
columns: nestedCols,
data : data,
caption: "Table with nested column headers"
}).render("#example3");
```
<p>This code produces this table:</p>
<div id="example3" class="yui3-skin-sam"></div>
<script>
YUI().use('datatable-base', function (Y) {
var nestedCols = [
{
label: "Train Schedule",
children: [
"track",
{
label: "Route",
children: [ { key: "from" }, { key: "to" } ]
}
]
}
];
var data = [
{ track: "1", from: "Paris", to: "Amsterdam" },
{ track: "2", from: "Paris", to: "London" },
{ track: "3", from: "Paris", to: "Zurich" }
];
var table = new Y.DataTable({
columns: nestedCols,
data : data,
caption: "Table with nested column headers"
}).render("#example3");
});
</script>
<h3 id="formatters">Formatting Cell Data</h3>
<p>
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.
</p>
<p>
In short, it is the role of the `data` attribute to hold data. It is the
role of the `columns` configuration to decide how to display it.
</p>
<p>
Out of the box, DataTable provides three primary ways to customize how your
data is formatted for display in the table cell: `formatter` strings,
`formatter` functions, and `nodeFormatter` functions. All are assigned in
the column configuration.
</p>
```
var cols = [
// It's ok to mix simple strings and configuration objects
'id',
'name',
{
label: 'formatter',
children: [
// 1. formatter strings
// mix the field value into the {value} placeholder
{
key: 'price',
label: 'string',
formatter: '${value}',
emptyCellValue: '(not set)'
},
// 2. formatter functions
// can provide alternate content, add cell classes, refer to other data
// fields, etc (more below)
{
key: 'price',
label: 'function',
formatter: function (o) {
if (o.value > 3) {
o.className += ' yellow-background';
o.value *= 0.75;
}
return o.value ? '$' + o.value.toFixed(2) : '(not set)';
}
},
// 3. nodeFormatter functions
// have access to the cell Node in the DOM, up to the <tbody> Node.
// Caveats apply; see below.
{
key: 'price',
label: 'nodeFormatter',
nodeFormatter: function (o) {
var content;
if (o.value > 4) {
// Add a class to the <tr>
o.cell.ancestor().addClass('red-text');
o.value *= 0.75;
}
content = o.value ? ('$' + o.value.toFixed(2)) : '(not set)';
o.cell.setContent(content);
}
}
}
];
```
<p>This code produces this table:</p>
<div id="example4" class="yui3-skin-sam"></div>
<script>
YUI().use('datatable-base', function (Y) {
var cols = [
'id',
'name',
{ label: 'formatter', children: [
{ key: 'price', label: 'string',
formatter: '${value}', emptyCellValue: '(not set)' },
{ key: 'price', label: 'function',
formatter: function (o) {
if (o.value > 3) {
o.className += ' yellow-background';
o.value *= 0.75;
}
return o.value ? '$' + o.value.toFixed(2) : '(not set)';
}
}]
},
{
key: 'price',
label: 'nodeFormatter',
nodeFormatter: function (o) {
var content;
if (o.value > 4) {
// Add a class to the <tr>
o.cell.ancestor().addClass('red-text');
o.value *= 0.75;
}
content = o.value ? ('$' + o.value.toFixed(2)) : '(not set)';
o.cell.setContent(content);
}
}
];
var data = [
{ id: "ga-3475", name: "gadget", price: 6.99 },
{ id: "sp-9980", name: "sprocket", price: 3.75 },
{ id: "wi-0650", name: "widget" },
{ id: "nu-0001", name: "nut", price: 0.25 }
];
var table = new Y.DataTable({
columns: cols,
data : data
}).render("#example4");
});
</script>
<p>
Functions assigned as a column's `formatter` may either return a content
string to populate the cell, or update the `value` property on the object
that is passed as its argument. See <a href="#formatter-props">Appendix
B</a> for a list of all properties passed to `formatter` functions.
</p>
<p>
Functions assigned as a column's `nodeFormatter` must assign content to
the cell via the Node provided in the `cell` property of the object passed
as its argument. See <a href="#nodeformatter-props">Appendix C</a> for a
list of all properties passed to `nodeFormatter` functions.
</p>
<p>
<strong>`nodeFormatter`s should return `false`</strong>.
<a href="formatter-vs-nodeformatter">See below</a> for details.
</p>
<h4 id="formatter-vs-nodeformatter">Why `formatter` and `nodeFormatter`?</h4>
<p>
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 `formatter`s are applied.
</p>
<p>
On the rare occasion that you <em>must</em> 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.
</p>
<p>
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. <strong>This will not remove the rendered DOM, but it will remove
event subscriptions made on those Nodes</strong>.
</p>
<p>
In general, `nodeFormatter`s should only be used if absolutely necessary,
and should <em>always return `false`</em>. Event subscriptions should be
delegated from the DataTable's `boundingBox` or `contentBox`.
</p>
<h4 id="formatters-vs-empty">Formatters vs. `emptyCellValue`</h4>
<p>
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.
</p>
<p>
String formatters will only be applied if the field data for that cell is
not `undefined`. This allows the `emptyCellValue` to populate the cell.
</p>
<p>
Function formatters are applied before the return value or (potentially
altered) `o.value` property is tested for `undefined` or the empty string.
In either of these cases, the `emptyCellValue` populates the cell.
</p>
<p>
The `emptyCellValue` configuration is ignored by columns configured with
`nodeFormatter`s. It is entirely the responsibility of the `nodeFormatter`
to populate the cell content.
</p>
<h2 id="data">Getting Row Data</h2>
<!-- TODO: describe data as array, data as ModelList instance, assigned and dynamic recordTypes -->
<p>
Integrate with the <a href="../datasource/">DataSource</a> data abstraction
utility to easily load data from remote sources and implement features such
as caching and polling.
</p>
```
var cols = [
"Title",
"Phone",
"Rating"
];
var myDataSource = new Y.DataSource.Get({
});
schema: {
resultListLocator: "query.results.Result",
resultFields: [
"Title",
"Phone",
{
key: "Rating",
locator: "Rating.AverageRating"
}
]
}
}),
var table = new Y.DataTable({
columns: cols,
summary: "Pizza places near 98089"
});
datasource: myDataSource
})
table.render("#pizza");
// Load the data into the table
request: "&q=select%20*%20from%20local.search%20where%20zip%3D%2794089%27%20and%20query%3D%27pizza%27"
});
// Make another request later
request: "&q=select%20*%20from%20local.search%20where%20zip%3D%2794089%27%20and%20query%3D%27chinese%27"
});
```
<p>
Enable DataSource caching.
</p>
```
var cols = [
"Title",
"Phone",
{ key: "Rating.AverageRating", label: "Rating" }
];
var myDataSource = new Y.DataSource.Get({
});
myDataSource
.plug(Y.Plugin.DataSourceJSONSchema, {
schema: {
resultListLocator: "query.results.Result",
resultFields: ["Title", "Phone", "Rating.AverageRating"]
}
})
.plug(Y.Plugin.DataSourceCache, {
max: 3
});
var table = new Y.DataTable({
columns: cols,
summary: "Pizza places near 98089",
caption: "Table with JSON data from YQL"
});
table
.plug(Y.Plugin.DataTableDataSource, {
datasource: myDataSource
})
.render("#pizza");
request: "&q=select%20*%20from%20local.search%20where%20zip%3D%2794089%27%20and%20query%3D%27chinese%27"
});
```
<p>
Enable DataSource polling.
</p>
```
var cols = ["Title", "Phone", "Rating"];
var myDataSource = new Y.DataSource.IO({
source: "/path/to/service.php?"
});
schema: {
resultListLocator: "Result",
resultFields: [
{ key: "Title", locator: "*[local-name() ='Title']" },
{ key: "Phone", locator: "*[local-name() ='Phone']" },
{ key: "Rating", locator: "*[local-name()='Rating']/*[local-name()='AverageRating']" }
]
}
});
var table = new Y.DataTable({
columns: cols,
summary: "Chinese restaurants near 98089",
caption: "Table with XML data from same-domain script"
});
table
.plug(Y.Plugin.DataTableDataSource, {
datasource: myDataSource,
initialRequest: "zip=94089&query=chinese"
})
.render("#chinese");
myDataSource.setInterval(5000, {
request: "zip=94089&query=chinese",
callback: {
}
});
```
<h3 id="sorting">Column sorting</h3>
<p>
Column sorting functionality can be added with the `datatable-sort` module
(included in the `datatable` rollup module).
Enable sorting for all columns by setting `sortable` to true during
instantiation. Alternately, pass `sortable` an array of column keys to
enable sortability of those specific columns, `false` to disable sorting,
or the string "auto" (the default) to determine which columns to make
sortable by reading the `sortable` property from the column configurations.
</p>
```
var cols = [
{ key: "Company", sortable: true },
{ key: "Phone" },
{ key: "Contact", sortable: true }
];
var data = [
{ Company: "Company Bee", Phone: "415-555-1234", Contact: "Sally Spencer"},
{ Company: "Acme Company", Phone: "650-555-4444", Contact: "John Jones"},
{ Company: "Indutrial Industries", Phone: "408-555-5678", Contact: "Robin Smith"}
];
// Alternately, include sortable: true or sortable: ["Company", "Contact"]
// in the DataTable configuration
var table = new Y.DataTable({
columns: cols,
data: data,
summary: "Contacts list",
caption: "Table with simple column sorting"
}).render("#sort");
```
<h3 id="scrolling">Scrolling</h3>
<p>
<strong>Note:</strong> Scrolling is not currently supported on the Android
WebKit browser.
</p>
<p>
Scrolling functionality can be added with the `datatable-scroll` module
(included in the `datatable` rollup module). Scrolling is enabled by the
`scrollable` attribute, which accepts values "x", "y", "xy", `true` (same
as "xy"), or `false` (the default).
</p>
<p>
Note, vertical scrolling also requires the table's `height` attribute to be
set, and horizontal scrolling requires the `width` to be set.
</p>
```
var cols = [
{ key: "Company" },
{ key: "Phone" },
{ key: "Contact" }
];
var data = [
{ Company: "Company Bee", Phone: "415-555-1234", Contact: "Sally Spencer"},
{ Company: "Acme Company", Phone: "650-555-4444", Contact: "John Jones"},
{ Company: "Indutrial Industries", Phone: "408-555-5678", Contact: "Robin Smith"}
];
var table = new Y.DataTable({
columns: cols,
data: data,
scrollable: "y",
height: "300px"
}).render("#scroll");
```
<h2 id="knownissues">Known Issues</h2>
<ul>
<li>
Scrolling is
<a href="http://yuilibrary.com/projects/yui3/ticket/2529761">not
currently supported on Android</a> WebKit browser.
</li>
<li>Scrolling DataTable does
<a href="http://yuilibrary.com/projects/yui3/ticket/2531047">not appear
scrollable</a> in iOS and OS X 10.7 in Safari 5.1+ and Chrome 15+.
</li>
</ul>
<h2 id="column-config">Appendix A: Column Configurations</h2>
<p>
The properties below are supported in the column configuration objects
passed in the `columns` attribute array.
</p>
<div id="column-config-table" class="yui3-skin-sam">
<table>
<thead>
<tr>
<th scope="col">Configuration</th>
<th scope="col">Description</th>
<th scope="col">Module</th>
<th scope="col">readOnly</th>
</tr>
</thead>
<tbody>
<tr>
<td>key</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>name</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>label</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>children</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>abbr</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>formatter</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>nodeFormatter</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>emptyCellValue</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>allowHTML</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>className</td>
<td></td>
<td>`datatable-base`</td>
<td>no</td>
</tr>
<tr>
<td>sortable</td>
<td></td>
<td>`datatable-sort`</td>
<td>no</td>
</tr>
<tr>
<td>sortFn</td>
<td></td>
<td>`datatable-sort`</td>
<td>no</td>
</tr>
<tr>
<td>sortDir</td>
<td></td>
<td>`datatable-sort`</td>
<td>no</td>
</tr>
<tr>
<td>width</td>
<td></td>
<td>`datatable-column-widths`</td>
<td>no</td>
</tr>
<tr>
<td>_yuid</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
<tr>
<td>_id</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
<tr>
<td>_colspan</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
<tr>
<td>_rowspan</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
<tr>
<td>_parent</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
<tr>
<td>_headers</td>
<td></td>
<td>`datatable-base`</td>
<td>YES</td>
</tr>
</tbody>
</table>
</div>
<h2 id="formatter-props">Appendix B: Formatter Argument Properties</h2>
<p>
The properties below are found on the object passed to `formatter`
functions defined in a column configuration. See
<a href="#nodeformatter-props">Appendix C</a> for the object properties
passed to `nodeFormatter`s.
</p>
<div id="formatter-props-table" class="yui3-skin-sam">
<table>
<thead>
<tr>
<th scope="col">Property</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<h2 id="nodeformatter-props">Appendix C: nodeFormatter Argument Properties</h2>
<p>
The properties below are found on the object passed to `nodeFormatter`
functions defined in a column configuration. See
<a href="#formatter-props">Appendix B</a> for the object properties
passed to `formatter`s.
</p>
<div id="nodeformatter-props-table" class="yui3-skin-sam">
<table>
<thead>
<tr>
<th scope="col">Property</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>