| ColorPalette | [inline:color_picker.png] |
| Editor | [inline:editor.png] |
| Grid (1.0) | [inline:grid_terms.gif] |
| InlineEditBox (1.0) For 0.9, see dijit.form.InlineEditBox | [inline:inline_edit.png] |
| Tree | [inline:tree.png] |
ColorPalette is a color picker for Web pages. You can do lots of stuff with this kind of widget like allowing your user to choose color for theming interactively. Color palette is an abstraction of popular hexa color codes by dijit.
|
dijit.ColorPalette
Grid showing various colors, so the user can pick a certain color
|
||
|
Attributes
|
||
| defaultTimeout | Number 500 |
The number of milliseconds before a held key or button becomes typematic |
| timeoutChangeRate | Number 0.90 |
Fraction of time used to change the typematic timer between events; 1.0 means that each typematic event fires at defaultTimeout intervals < 1.0 means that each typematic event fires at an increasing faster rate |
| palette | String 7x10 |
Size of grid, either "7x10" or "3x4". |
|
Extension Points
|
||
| onChange(/* String */color) | Callback when a color is selected. Parameter is the hex color. | |
| Action | Key |
|---|---|
| Navigate colors | Arrow keys |
| Pick a color | Spacebar or enter |
Screen readers will read the name of each color as it is highlighted. For example, "white", "seashell", "cornsilk", and so on.
This widget is only available in 1.0. Grid is a DojoX project, but is documented here for user convenience.
Grids are familiar in the client/server development world. Basically a grid is a kind of mini spreadsheet, commonly used to display details on master-detail forms. From HTML terms, a grid is a "super-table" with its own scrollable viewport.
The Dojo grid is fast, robust, and very functional. In particular, grid has:
To begin working with Grid, let's start with a simple example. The Dijit class directory is kept in /dijit/tests/_data/dijits.json. We'll base on a grid on it, and add embellishments throughout the next few sections.
Every page using Grid needs to import the basic grid style sheet. When used with Dijit and Dojo, your combined style loading block should look like:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}Each Grid begins with data, and two DIV tags will define our data source. Because of the same-origin security rule, you will need to place the data file on your web server. You can download this file, dijits.json, at the bottom of this page. Just place it in the same directory as the example: /* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
The first DIV should look familiar. It's the good ol' dojo.Data definition you use with the Dijit components ComboBox or Tree. The second is new - it's the dojox.grid.data.DojoData adapter that turns a data source into a Grid model. The model has options for which items to select. In this example, we turn the datasource jsonStore into the model named "model".
Models can also be created from JavaScript arrays, which we'll see in: Model Options.
In standard spreadsheet and table terminology, a cell is the basic unit of displayed data. A row is a horizontally aligned contiguous group of cells, and a column is a vertically aligned contiguous group of cells. (Wow, that makes a simple concept sound complex!)
In grid-land, there's a distinction between rows and subrows. A subrow is what people normally think of as a row - it's exactly one cell tall. In Grid, a row may be more than one subrow - but it is selectable as a unit. So you'll notice in our demo grid that logical rows are exactly 2 subrows tall.
A View is a group of contiguous logical rows with the same inner and outer "shape". In our example above, each logical row is two subrows tall, with 2 columns on the top physical row and 1 column on the bottom physical row (the last cell spanning 2 columns). You specify this in JavaScript with an array of arrays. Each array element is an object literal. The most important property of the object is "name", which names the column. The column name always appear as the top logical row of the grid, and unlike other rows, it doesn't scroll up or down.
// a grid view is a group of columns
var view1 = {
cells: [[
{name: 'Namespace', field: "namespace"},
{name: 'Class', width: "25em", field: "className"}
],
[
{name: 'Summary', colSpan:"2", field: "summary"}
]
]
};
Fields in the model are applied across each view cell in order. Property names are ignored. In our example, Namespace holds field 0, Class holds field 1, and so on.
As in good ol' HTML tables, you can specify:
Finally, views can be grouped together into a structure. You can think of a structure as a dijit.layout.LayoutContainer applied to views - you can place views in the top, bottom, left and/or right sides, plus one in the middle. Our simple example only has one view:
var layout = [ view1 ];
The model and structure (which is composed of views) come together in the grid widget:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}The model and structure attributes point to our JavaScript variables for the model and structure. Nice! And with no other code, the grid is:
So, here's the entire program:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}Note that normally with CDN, you would need to wrap the view1 initialization code like in a dojo.addOnLoad. But that's not necessary here because no DOM needs to be drawn yet. We're just setting up anonymous objects. Because these are available when the widgets are drawn, we can use the structure property in the Grid tag. The design is nice and clean.
Now let's cover the model, view and structure elements in more depth:
That's nice so far. The column header stays in place while the user scrolls down, making them easy to identify. Can we apply to that rows as well?
Yup. You can make row headers that stay in place and act as selection points.. What's more, you can split your grid into arbitrary scrollable sections that can stay in sync or scroll independently. You do this by gluing more than one view into a structure.
By default, when you click on a cell, you select that cell and the entire containing row. A special view called dojox.grid.GridRowView draws a column of empty handles. When clicked, these handles select the row without selecting a particular cell. Unlike most other views, GridRowView has no "cells" property, only a width. So adding this to the structure on our last page:
var rowbar = {
type: 'dojox.GridRowView', width: '20px'
};
// a grid layout is an array of views.
var layout = [ rowbar, view1 ];
The resulting page (downloadable below as grid1.html), yields:
As you would expect, CTRL+click selects non-contiguous rows and SHIFT+click selects contiguous ones. As it stands, the selection is only for display. In the Events section, we'll actually do something with the rows.
You may have noticed that the Selection bar rows and the data rows scroll together. So it's no surprise that when you add another view, it too scrolls vertically in sync.
To see this, we'll split off the Dijit class name into its own view:
// a grid view is a group of columns
var view1 = {
cells: [[
{name: 'Namespace', field:0, width: "25em"}
],
[
{name: 'Summary', colSpan:"2", field:2}
]
]
};
var rowbar = {
type: 'dojox.GridRowView', width: '20px'
};
var fixedColumn = {
cells: [[ {name: 'Class', field:1, width:"25em"} ]]
};
Since we're using fields in a different order, specifying the field numbers in each cell definition is mandatory. Now combine that into a layout like this:
var layout = [ rowbar, fixedColumn, view1 ];
And you get two grids with separate scroll bars. By default each scrollbar moves both views in sync with each other.
Admittedly, the extra scroll bar isn't very useful. But when you add fields to the right hand grid like so:
var view1 = {
cells: [[
{name: 'Namespace', field:0, width:"20em"},
{name: 'Description', field:3, width:"20em"}
],
[
{name: 'Summary', field:2},
{nane: 'Examples', field:4}
]
]
};
And run the example, you find the bottom scroll bar scrolls the views independently. We say the views are vertically dependent, but horizontally independent.
Now you turn off the scroll bar in the left hand view with the noscroll property:
var fixedColumn = {
noscroll: true,
cells: [[
Yields:
By default, when dojo.data datasources feed a Grid, the columns are not user-sortable. That's easy to rectify. Just set clientSort="true" in the tag:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}Now the user can click on any column to sort it. You may also set the sort order programmatically:
// Sort 4'th field in ascending order myGrid.setSortIndex(3, true);
To filter a list, you can create a new adapter with a different query then attach it to the grid.
//Construct a new model. The store needs to be passed into the constructor, as the constructor for the
//DojoData model examines the store and configures the model to support various features of the store
//such as Write, Identity, and Notification. Setting the store after the constructor will leave the
//model in a misconfigured state and be unable to support data writebacks in the case of Write implementing
// datastores.
var newModel = new dojox.grid.data.DojoData(null,null,{rowsPerPage: 20, store: myStore, query: {type: someOtherType}, clientSort: true});
myGrid.setModel(newModel);
// Remember to call newModel.destroy() when you're done.
A popular use of filtering is to display a grid with everything, then let the user chop the list down incrementally. In this case, you can define an initial model with a minimal query. Save it, and then you can setModel back to it for quickly resetting all the filters. But do not keep unused models lying around! They take up memory.
Up until now, we've showed grid contents in view mode. Now, let's add some interactivity.
An editable cell is handled by a cell editor. To make a cell editable, you simply specify the cell editor class in the column definition. Here is a part of the view definition code in /dojoroot/dojox/grid/tests/test_edit.html.
gridLayout = [
cells: [[
{ name: 'Priority', styles: 'text-align: center;',
editor: dojox.grid.editors.select,
options: ["normal", "note", "important"]
},
{ name: 'Mark', width: 3, styles: 'text-align: center;',
editor: dojox.grid.editors.bool
},
{ field: 2, name: 'Status', styles: 'text-align: center;',
editor: dojox.grid.editors.select,
options: [ "new", "read", "replied" ]
}
In the actual grid, you double-click on a cell to begin editing. Here, we've double clicked on the status box, and a SELECT appears in place of the data:
[inline:gredit_edit1.png]Some of the cell editors, like dojox.grid.editors.DateTextBox are just wrappers for their Dijit form widget counterparts. All the functionality and properties are available to you. This is an example from /dojoroot/dojox/grid/tests/test_edit_dijit.html.
gridLayout = {
cells: [[
{ name: 'Date', width: 10, field: 7,
editor: dojox.grid.editors.DateTextBox,
formatter: formatDate,
constraint: {formatLength: 'long', selector: "date"}
}
]]
};
Editing the Date cell brings up the familiar Dijit date box:
[inline:gredit_edit2.png]Now, what do you actually do with an edited cell? That's really up to you, and you hook in your desired code by connecting to an event, which we'll cover next.
| Cell Editor Class | Attributes |
| dojox.grid.editors.CheckBox | See dijit.form.CheckBox |
| dojox.grid.editors.ComboBox | See dijit.form.ComboBox |
| dojox.grid.editors.DateTextBox | See dijit.form.DateTextBox |
| dojox.grid.editors.Editor | See dijit.Editor |
| dojox.grid.editors.select | Similar to dojox.grid.editors.ComboBox, but doesn't allow freeform values String[] options: text of each item String[] values: value for each item Boolean returnIndex: editor returns only the index of the selected option and not the value |
| dojox.grid.editors.TextBox | See dijit.form.TextBox |
| dojox.grid.editors.TimeTextBox | See dijit.form.TimeTextBox |
As we alluded to in the last few pages, selection and cell editing is pointless without some kind of background processing. So how do you hook code into these places? Through Dojo's event model, of course!
If you're using a writable dojo.data datastore, you simply hook your procedures into the dojo.data Notification API. Suppose in our running example, we make the Description field editable:
cells: [[
{name: 'Namespace', field:0, width:"30em"},
{name: 'Description', field:3, width:"30em",
editor: dojox.grid.editors.Dijit }
]
],
Then, we place the hook into dojo.data.Notification's onSet extension point:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}Here is the entire source code. Note how we place the layout initialization code in a dojo/method block inside the Grid tag. That's due to the editor class dojox.grid.editors.Dijit in the view definition. When you're using CDN, the dojox.grid.editors package is not available directly after the dojo.require., so we can't place the initialization code after it (as we did in our previous examples). By using a dojo/method, we can place this code close to its use (the Grid tag) and it's guaranteed to run after all dojo.require'd modules have loaded. You can also use dojo.addOnLoad to accomplish this.
You can read more on the dojo.data Notification API in Part 3 of the book, but here are the basics for your Grid needs:
For more granular event processing, you can hook into Grid events. Each event calls the function you provide, passing back the event object. If e is the event, the interesting stuff is in:
| Entity | click/double click | mouse over/out | right click |
| Data Cell | onCellClick onCellDblClick |
onCellMouseOver onCellMouseOut |
onCellContextMenu |
| Hdr Cell | onHeaderCellClick onHeaderCellDblClick |
onHeaderCellMouseOver onHeaderCellMouseOut |
onHeaderCellContextMenu |
| Data Row | onRowClick onRowDblClick |
onRowMouseOver onRowMouseOut |
onRowContextMenu |
| Hdr Row | onHeaderClick onHeaderDblClick |
onHeaderMouseOver onHeaderMouseOut |
onHeaderContextMenu |
Fixed styles that apply to all cells of a column are settable in the view. The properties you need:
The above properties make sweeping style changes across a column. But how do you change styles for individual cells? For example, suppose you want to color negative numbers red and positive numbers black.
The onStyleRow extension point can do this. Grid passes a Row object to your onStyleRow method. You set the properties customStyles and/or customClasses in this object, and Grid will restyle your row accordingly. The Row object has the following properties:
In the following example, we look at each row and color the row text red if the Dijit contains a description.
function colorDescriptions(inRow) {
if (model.getRow(inRow.index) === undefined)
return;
if (model.getRow(inRow.index).description != '')
inRow.customStyles = 'color:red';
}
You connect this function to the extension point in the Grid tag:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}And behold ... red text where the row has a non-blank description
[inline:grid_demo4.png]A cell formatter alters the text in the cell, not the styles. As you might guess, this is useful for formatting numbers, currency, dates, percentages, etc. The cell formatter is specified with the formatter extension point in the cell object:
{ name: 'Amount', formatter: formatCurrency, field: "moola"},
And define the formatter itself separately. (You can also use a function literal inside the cell definition).
function formatCurrency(inDatum){
return isNaN(inDatum) ? '...' : dojo.currency.format(inDatum, { currency: 'USD' });
}
Liberal use of Dojo i18n for formatting dates and numbers is strongly encouraged!
Grouping data for summarization requires a simple strategy. We will calculate a summary subrow for every row in the table, then just hide the ones not on a group boundary. So here is some (boring!) numeric data:
{
identifier: 'id',
label: 'name',
items: [
{ id:'Q1_06', name: 'Q1 2006', year:2006, quarter:1, sales:345436 },
{ id:'Q2_06', name: 'Q2 2006', year:2006, quarter:2, sales:234525 },
{ id:'Q3_06', name: 'Q3 2006', year:2006, quarter:3, sales:129104 },
{ id:'Q4_06', name: 'Q4 2006', year:2006, quarter:4, sales:-10000 },
{ id:'Q1_07', name: 'Q1 2007', year:2007, quarter:1, sales:-178775 },
{ id:'Q2_07', name: 'Q2 2007', year:2007, quarter:2, sales:286027 },
{ id:'Q3_07', name: 'Q3 2007', year:2007, quarter:3, sales:429546 },
{ id:'Q4_07', name: 'Q4 2007', year:2007, quarter:4, sales:946375 }
]
}
To implement our strategy, we first build two functions which supply the total and total label for each totalling subrow.
function getYearlyLabel(inRowIndex) {
return model.getRow(inRowIndex) ? "Total for " + model.getRow(inRowIndex).year : 'None';
}
function getYearlyTotal(inRowIndex) {
return model.getRow(inRowIndex) ? (yearlyTotal += model.getRow(inRowIndex).sales) : -1;
}
Next, we make an onAfterRow procedure to hide all the rows that are not after Q4
// inRow is an array of subRows. we hide the summary subRow except for every nth row
function onAfterRow(inDataIndex, inRow) {
// note that header row inDataIndex == -1
inRow[1].hidden = true;
// Before rows 3, 7, 11 turn on display of the total
if (inDataIndex != -1 && inDataIndex % 4 == 3) {
yearlyTotal = 0;
inRow[1].hidden = false;
}
}
Then we wire it all up in the view definition:
var view1 = {
onAfterRow: onAfterRow,
cells: [[
{name: 'Year/Quarter', field:'name'},
{name: 'Sales', field:'sales'}
],[
// The summary subrow, which will be hidden on most rows
{name: 'Cell2', get: getYearlyLabel },
{name: 'Yearly Sales', get:getYearlyTotal, styles:'font-weight:bold;'},
]]
};
And the summary rows are displayed. Currently this example shows the summary row for all rows. A question is pending on the forums about this, and the example will be fixed accordingly.
Instead of feeding dojo.data sources to the grid, you may feed it a two-dimensional array. This approach works well for grids with fixed data, e.g. static reference tables. Here's an example culled from the unit test /dojoroot/dojox/grid/tests/test_grid.html. Note the following:
You can watch for changes to cells at the model level. This is called setting an observer and it followed the familiar Observer Design Pattern. With array-fed Grids, these are your only hook-in points for sending XHR back to the server. As we saw in Events, you can use dojo.Data's notification API, or the Observer API for the same thing.
To observe a model, you first create an object literal with function properties. These functions must be named:
For example, this observer watches all model changes and updates a visible row count.
var modelObservers = {
modelChange:function(){
dojo.byId("rowCount").innerHTML = 'Row count: ' + model.count;
}
}
Then you register the observer with the model:
model.observer(modelObservers);
|
dojox.grid.data.Model
The raw data behind a grid. Can be retrieved from a grid by accessing the
grid's public 'model' attribute. The model can be set for a grid by calling
setModel(newModel).
|
||
|
Properties
|
||
| clientSort | Boolean | User is allowed to sort by clicking column headers (dojo.data models only) |
| count | Integer | Number of rows currently in the model |
| query | Object | dojo.data query for current store (dojo.data stores only) |
| rowsPerPage | Integer | Rows to scroll down before another set of rows is rendered. |
| store | String | dojo.data store variable (dojo.data stores only) |
| updating | Integer | Number of rows in an UPDATING state |
|
Methods
|
||
| String getDatum(/* Integer */inRowIndex, /* Integer */inColIndex) | Return data at the location. Column indexes are id's for dojo.data models, integers for array models. | |
| Integer getColCount() | Return number of columns | |
| Object getRow(/* Integer */inRowIndex) | Returns item for dojo.data elements, array for array-based elements, at inRowIndex | |
| Integer getRowCount() | Returns number of rows in model | |
| notObserver(/* Object */ inObserver) | De-register an observer. | |
| observer(/* Object */ inObserver, /* String */inPrefix) | Register an observer object with the model. inPrefix is added to each function name before calling, as in myPrefixModelChange. That way you can specify multiple observers in the same object. | |
| Integer pageToRow(/* Integer */inPageIndex) | Starting row number on given page | |
| Integer rowToPage(/* Integer */inRowIndex) | Return page number for this row | |
| setDatum(/* Object */inDatum, /* Integer */inRowIndex, /* Integer */inColIndex) | Set the data at the given position. Normally called by cell editing. | |
| setRow(/* Object */inRow,/* Integer */inRowIndex) | Overwrite the row at the given index. Row must be in same object format as other rows, e.g. an item for dojo.data models or array for array models. | |
| swap(/* Integer */inIndexA, /* Integer */inIndexB) | Swap rows A and B in model. | |
Grid neatly separates the model from the view in its MVC implementation. We just covered the model. Now we'll cover the view - that is, everything used to display the model elements.
In the world of Grid, the structure is the largest unit. Structures are composed of views. Views are composed of cells (what we normally think of as a column). We'll start at this lowest level first. As we've seen a cell is defined by a JavaScript object like this:
{ name: 'Apple', field: 'apple', width: '4.5em' }
This defines a column with the heading of Apple and initial width of 4.5em, and mapped to the field 'apple' in the model. The field index can be a string, as is the case for dojo.Data-fed grids, or a number, as in array-fed Grids.
Cells themselves are not directly addressable. You usually get them by starting with a grid variable and work downwards:
// get the cell in the third view, second subrow, fourth column (all indexes are 0-based). var thisCell = mygrid.structure[2].cells[1][3];
From here, you can access these properties and call these methods on thisCell:
|
Attributes
|
||
| cellClasses | String | CSS class applied to data |
| cellStyles | String | CSS Styles applied to data |
| classes | String | CSS Classes applied to all column: data and header |
| colSpan | Integer | Like colspan in HTML, number of columns each cell occupies. Only meaningful if there are subrows in each row, otherwise ignored. |
| editor | Class | For editable cells, this can be either "dojox.grid.editors.Dijit" for a Dijit form control or "dojox.grid.editors.Editor" for the rich text editor. (The rich text editoris essentially Dijit's with some modifications to make it nicer in a grid - like a shared toolbar.) Grid also bundles its own editors like dojox.grid.editors.bool for Booleans, but they are redundant with the Dijit widgets. |
| editorClass | String | If editor="dojox.grid.editors.Dijit", this designates the Dijit form widget to use. Note: this is a string with the class name, not the class itself. |
| extraField | Integer | Index field like "field", but tacked on |
| field | Integer | Index of field data in from model |
| headerClasses | String | CSS class applied to column header |
| headerStyles | String | CSS Styles applied to column header |
| name | String | Name used for the column header |
| noresize | Boolean | If true, column cannot be resized. |
| rowSpan | Integer | Number of subrows that each cell in this column occupies. |
| styles | String | CSS styles applied to all column: data and header |
| value | String | Constant value to placed in each column cell. Can contain HTML. |
| width | Number | Initial width of the column in ems |
|
Extension Points
|
||
| formatter(/* String */ inDatum) | Function which handles formatting the cell data. | |
| get(/* Integer */ inRowIndex) | Name of the function called to get a value. | |
|
Attributes
|
||
| cells | dojox.grid.cell[] | Array of cell objects, each defining a column |
| defaultCell | dojox.grid.cell | Properties of this cell are used as defaults in all cells |
| defaultWidth | String | width of cells (columns), if not specified in the cell itself |
| noscroll | Boolean | If true, do not draw scroll bars on right or bottom. |
| rowPad | Integer | Space to use between rows, in pixels |
| type | String | Name of class for programmatically-generated views like GridRowView. |
| viewWidth | String | Width of entire view in valid CSS units. |
|
Methods
|
|
| Node getCellNode(/* Integer */ inRowIndex, /* Integer */ inCellIndex) | Get cell at the specified location |
| Integer getColumnsWidth() | Width of data columns, in px |
| String getContentWidth() | Width of the containing box in CSS units, minus scrollbar (= getColumnsWidth + padding and borders, etc.) |
| Node getRowNode(/* Integer */ inRowIndex) | Get row at the specified location |
| Integer getScrollbarWidth() | Width of scrollbar in px, 0 for noscroll |
| String getWidth() | Total width of scrollbar and columns in CSS units |
| Boolean hasScrollbar() | True if there are enough rows to display a scrollbar. |
| resize() | resizeHeight(), then resizeWidth() |
| resizeHeight() | Resize to fit new height of containing box |
| resizeWidth() | Resize to fit new width of containing box |
| setColWidth(/* Integer */ inIndex, /* Integer */inWidth) | Resize cell (column) at inIndex to inWidth pixels |
| setSize(/* Integer */ w, /* Integer */ h) | Set size of the bounding box. Call resize() after. |
By default, the grid fits exactly in the parent DOM node provided for it. If all of the rows do not fit, a vertical scroll bar appears. Likewise, if all the columns don't fit, the horizontal scroll bar appears. Nothing surprising there.
The following properties resize the grid to fit all of the columns. In essence, setting either of these makes the appropriate scroll bar disappear.
You may either set these on the Grid tag itself, or set the properties through JavaScript and call dojox.grid.Grid.update() to redraw. You can also resize the width and height of the container (dojo.contentBox is good for this) and call update().
|
dijit.Grid
A grid widget with virtual scrolling, cell editing, complex rows, sorting, fixed columns, sizeable columns, etc.
|
||
|
Attributes
|
||
| autoHeight | Boolean | If autoHeight is true, grid height is automatically set to fit the data. |
| autoRender | Boolean | If autoRender is true, grid will render itself after initialization. |
| autoWidth | Boolean | If autoWidth is true, grid width is automatically set to fit the data. |
| defaultHeight | string | default height of the grid, measured in any valid css unit. |
| elasticView | Integer | One of the views in the grid may be "elastic", that is: expanding or contracting to fill the remaining size when all non-elastic elements are placed. By default, the middle view is elastic. Specifying this property makes the indexed grid view elastic. |
| fastScroll | Boolean | flag modifies vertical scrolling behavior. Defaults to true but set to false for slower scroll performance but more immediate scrolling feedback |
| keepRows | Integer | Number of rows to keep in the rendering cache. |
| model | String or Object | Current grid data model. Should only be used for retrieving the model. Setting should be accomplished using setModel(newModel) as outlined below. |
| rowCount | Integer | Number of rows to display |
| rowsPerPage | Integer | Number of rows to render at a time. |
| singleClickEdit | Boolean | Single-click starts editing. Default is double-click |
| structure | Object or String | View layout defintion. Can be set to a layout object, or to the (string) name of a layout object. |
|
Methods
|
||
| addRow(/* Array */ inRowData, /* Integer */ inIndex) | Add row inRowData after row[inIndex] in both displayed grid and model | |
| String get(/* Integer */ inRowIndex) | Get raw data at row inRowIndex in the current cell position. | |
| dojox.grid.Cell getCell(/* Integer */ inIndex) | Get the cell object (the column definition) in column inIndex | |
| String getCellName(/* Integer */ inIndex) | Get the column name of inIndex | |
| Boolean canSort(/* Integer */ inSortInfo) | Sort information, in sortInfo is 1-based index of column on which to sort, positive for an ascending sort and negative for a descending sort returns true if grid can be sorted on the given column in the given direction | |
| Boolean getSortAsc(/* Integer */ inSortInfo) | returns true if grid is sorted in an ascending direction. | |
| Integer getSortIndex() | returns index of sorted field | |
| refresh() | re-render the grid with the new data model | |
| removeSelectedRows() | remove all selected rows in displayed grid and model | |
| render() | Render the grid, headers, and views. Edit and scrolling states are reset. To retain edit and scrolling states, see Update. | |
| renderAtIdle() | Same as render, but wait until all background processing has completed. | |
| resize() | Call after setting width or height | |
| resizeHeight() | Call after setting just the height | |
| setCellWidth(/* Integer */ inIndex. /* String */ inUnitWidth) | Set column size to a given CSS unit width | |
| setModel(/* dojox.grid.model */ inModel) | set the grid's data model | |
| setSortIndex(/* Integer */ inIndex, /* Boolean */ inAsc) | Sets a sort column and direction (true=ascending, false=descending). | |
| setStructure(/* dojox.grid.Structure */ inStructure) | Install a new structure and rebuild the grid. | |
| scrollTo(/* Integer */ inTop) | Vertically scroll the grid to a given pixel position | |
| scrollToRow(/* Integer */ inRowIndex) | Scroll the grid to a specific row. | |
| sort() | sort on current sort field | |
| update() | Update the grid, retaining edit and scrolling states. | |
| updateRow(/* Integer */inRowIndex) | Change the number of rows. | |
| updateRowCount(/* Integer */inRowCount) | Update row count property to inRowCount | |
| updateRowStyles(/* Integer */inRowIndex) | Update the styles for a row after it's state has changed. | |
InlineEditBox is best described as a behavior on some text on the page, such that clicking that text brings up an editor, and when the text is saved, the screen is reverted to it's original state (but with the new text). The editor is created on-demand, so as to not slow down page load.
When a user loads the page, they see the text "Edit me - I trigger the onChange callback". If the user clicks the text, a TextBox widget containing the text "Edit me - I trigger the onChange callback" appears. When the user changes the value and clicks away, the TextBox disappears and the TextBox's contents appear inline.
InlineEditBox supports the textarea mode through the Textarea widget. By simply saying editor=dijit.form.Textarea, you can use that editor. Furthermore, by adding renderAsHtml=true, users can enter HTML into the Textarea and have it appear inline as rich text. :
I'm one big paragraph. Go ahead and edit me. I dare you. The quick brown fox jumped over the lazy dog. Blah blah blah blah blah blah blah ...
When a user loads the page, they see the paragraph of rich text. If the user clicks the text, a Textarea widget containing the paragraph in plain text form appears. When the user changes the value and clicks away, the Textarea disappears and the Textarea's contents appear inline.
InlineEditBox can use any arbitrary widget that has a text value, or has the methods get/setDisplayedValue as an editor. DateTextBox is an example of such a widget. This code shows a DateTextBox as the editor:
1/1/2007
Note that the originally displayed text is generated by the server, and thus must be in the correct locale for the client machine. Since the server is generating the text, that burden of localizing the text falls on the server.
The InlineEditBox can wrap around any widget that implements the following interface:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #000066; font-weight: bold;} .geshifilter .kw2 {color: #003366; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #009900; font-style: italic;} .geshifilter .coMULTI {color: #009900; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #3366CC;} .geshifilter .nu0 {color: #CC0000;} .geshifilter .me1 {color: #006600;} .geshifilter .re0 {color: #0066FF;}The contained widget's setTextValue() method is called with the previously displayed text. When the Save button is pressed, the editing widget's getTextValue() method is called to retrieve the new text. After which, the editing widget is hidden, and the returned text is displayed. The focus method allows the editing widget to intelligently set focus to an appropriate node.
|
dijit.InlineEditBox
Edit behavior applied to a node
|
|||
|
Attributes
|
|||
| autoSave | Boolean true |
Changing the value automatically saves it; don't have to push save button (and save button isn't even displayed) | |
| buttonSave | String | Save button label | |
| buttonCancel | String | Cancel button label | |
| editing | Boolean false |
Is the node currently in edit mode? | |
| editor | String dijit.form.TextBox |
name of widget to use as editor | |
| editorParams | Object | Parameters to pass to editor (in addition to the value being edited. ex: "{constraints: {places:0} }" | |
| renderAsHTML | Boolean false |
true if the editor widget and takes HTML for setValue(), and returns HTML from getValue(). Ex: dijit.Editor | |
| value | String | Read-only value of box | |
|
Methods
|
|||
| cancel(/*Boolean*/ focus) | evert to display mode, discarding any changes made in the editor | ||
| save(/*Boolean*/ focus) | Focus on the display mode text | ||
|
Extension Points
|
|||
| onChange(/* String */value) | User should set this handler to be notified of changes to value | ||
Note that since InlineEditBoxes may be used on the page without a traditional label element, the developer should add a title attribute in order to provide a description that is available to screen reader users. The title will also be displayed by the browser when the user places the mouse over the element.
If the widget is closed.
| Action | Key |
|---|---|
| Navigate to the next widget in the tab order. | Tab |
| Navigate to the prior widget in the tab order. | Shift+Tab |
| Open the widget. | Enter or spacebar |
TextBox with autoSave specified and the TextBox is open:
| Action | Key | Comments |
|---|---|---|
| Navigate to the next widget in the tab order. | Tab | The data is saved and the widget closes. |
| Navigate to the prior widget in the tab order. | Shift+Tab | The data is saved and the widget closes. |
| Close the TextBox, saving changes. | Enter | Keyboard focus is on the closed InlineEditBox. |
| Revert the last entry. | Esc | If the user has not entered data, the TextBox is closed. |
| Close the Textarea, discarding changes. | Esc | If the user has entered data, the Esc must be pressed two times; the first time the data will be reverted; the second time the TextBox will close. |
Textarea with autoSave specified and the Textarea is open:
| Action | Key | Comments |
|---|---|---|
| Navigate to the next widget in the tab order. | Tab (press twice in Firefox - see the Known Issues below) | The data is saved and the widget closes. |
| Navigate to the prior widget in the tab order. | Shift+Tab | The data is saved and the widget closes. |
| Enter a newline into the text. | Enter | There is no equivalent to the Enter key behavior of TextBoxes. The user would have to use something like Tab and Shift + Tab. |
| Revert the last entry. | Esc | If the user has not entered data, the Textarea is closed. |
| Close the Textarea, discarding changes. | Esc | If the user has entered data, the Esc must be pressed two times; the first time the data will be reverted; the second time the Textarea will close. |
TextBox without autoSave specified, the TextBox is open, keyboard focus is in the edit field:
| Action | Key | Comments |
|---|---|---|
| Navigate to the Save or Cancel button. | Tab | Focus changes to the Save button if the data has been changed, otherwise it moves to the Cancel button. |
| Navigate to the prior widget in the tab order. | Shift+Tab | The TextBox remains open. |
| Close the TextBox, saving changes. | Tab to the Save button, then press the Enter key | Keyboard focus is on the closed InlineEditBox. |
| Revert the last entry. | Esc | If the user has not entered data, the Esc key is ignored. |
| Close the Text Box, discarding changes. | Tab to the Cancel button, then press the Enter key. | Keyboard focus is on the closed InlineEditBox. |
Textarea without autoSave specified, the Textarea is open, keyboard focus is in the edit field:
| Action | Key | Comments |
|---|---|---|
| Navigate to the Save or Cancel button. | Tab (press twice in Firefox - see the Known Issues below) | Focus changes to the Save button if the data has been changed, otherwise it moves to the Cancel button. |