Loading document parsing libraries...
# GraffitiGrid
Class Inherits GraffitiWebUIControl
## About
GraffitiGrid is a fully-custom listbox control complete with custom cell types and events for drawing the most complex list of data you can dream up. Supports embedding controls and containers, custom row and header rendering, frozen columns, and much more.
## Compatibility
### Framework API Version
| 1.0 | 2.0 |
| :---: | :---: |
| True | True |
### Web
| 32-Bit | 64-Bit |
| :---: | :---: |
| True | True |
## Enumerations
| Name | Value | Description |
| --- | :---: | --- |
| EditTypes | None <br > Text <br > LongText <br > Integer <br > YesNoSelect <br > Checkbox <br > Percent <br > Date <br > Password <br > Currency <br > Double <br > TimeWithSeconds <br > TimeWithoutSeconds <br > PopupMenu <br > Multiselect <br > Color <br > TextWithButton <br > NativeCheckbox <br > DateTime | Supported cell editing types. |
| FormatTypes | Text <br > LongText <br > Currency <br > YesNo <br > Checkbox <br > Percent <br > ProgressBar <br > FontAwesome <br > Date <br > Color <br > Picture <br > HTML <br > Password <br > Integer <br > Double <br > TimeWithoutSeconds <br > TimeWithSeconds <br > PopupMenu <br > Multiselect <br > Tree <br > Chart <br > Button <br > ButtonGroup <br > Badge <br > StarRating <br > Hyperlink <br > JavaScript <br > NativeCheckbox <br > DateTime <br > AvatarGroup <br > Container | Supported cell value formatting types. |
| SelectionTypes | Row <br > Cell | Supported selection models. |
| SortDirections | Ascending <br > Descending <br > None | Supported sorting directions. |
## Event Definitions
| Name | Parameters | Return Type | Description |
| --- | :---: | :---: | --- |
| ButtonGroupItemPressed | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> Group as GraffitiGridButtonGroup <br> Item as GraffitiGridButtonGroupItem | (None) | Raised when a ButtonGroup item is pressed. |
| CellChange | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> NewValue as Variant | (None) | Fired when the value of a cell has been edited by the user. |
| CellClick | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> pageX as Integer <br> pageY as Integer <br> cellLeft as Integer <br> cellTop as Integer <br> cellWidth as Integer <br> cellHeight as Integer | (None) | Fired when the user clicks a cell. |
| CellDoubleClick | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> pageX as Integer <br> pageY as Integer <br> cellLeft as Integer <br> cellTop as Integer <br> cellWidth as Integer <br> cellHeight as Integer | (None) | Raised when a cell is double-clicked. |
| CellMouseEnter | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Raised when the mouse enters a grid cell. |
| CellMouseExit | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Raised when the mouse exits a grid cell. |
| ColumnResized | Column as GraffitiGridColumn | (None) | Fired when a column is resized in the display by the user. |
| ColumnsReordered | (None) | (None) | Fired when the columns are reordered by the end-user. Use methods to determine new order. |
| ContextClick | Row as GraffitiGridRow <br> Cell as GraffitiGridColumn <br> X as Integer <br> Y as Integer <br> cellLeft as Integer <br> cellTop as Integer <br> cellWidth as Integer <br> cellHeight as Integer | (None) | Fired when the user right-clicks on a cell. |
| EditBegin | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> cellLeft as Integer <br> cellTop as Integer <br> cellWidth as Integer <br> cellHeight as Integer | (None) | Raised when an edit operation has begun. |
| EditEnd | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Raised when an edit operation has ended either by saving or canceling. |
| EditorButtonPressed | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> Value as String | (None) | Raised when the user clicks the button in a cell editor of type TextWithButton. |
| FooterClick | Column as GraffitiGridColumn | (None) | Raised when the user clicks on a cell in the footer. |
| FooterContextClick | Column as GraffitiGridColumn | (None) | Raised when the user right-clicks on a cell in the footer. |
| HeaderButtonPressed | Column as GraffitiGridColumn | (None) | Raised when the user clicks a button that is embedded within a column header using the GraffitiGridColumn.HeaderButton* properties. |
| HeaderClicked | Column as GraffitiGridColumn | (None) | Raised when user clicks on a GraffitiGridColumn in the display. Only operational if Grid.Sortable = False. |
| KeyPress | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> KeyCode as Integer <br> AltKey as Boolean <br> CtrlKey as Boolean <br> ShiftKey as Boolean | (None) | Raised when the user presses a keyboard key on the grid but not when editing. |
| Open | (None) | (None) | (None) |
| RowCollapsed | Row as GraffitiGridRow | (None) | Fired when a tree row is collapsed. Children should be removed at this point. |
| RowExpanded | Row as GraffitiGridRow | (None) | Fired when a tree row is expanded. Children should be added at this point. |
| RowFromDatabase | byref row as GraffitiGridRow | (None) | Raised when a row is being processed for addition during an AddRowSet call. This event allows you to modify field data before it reaches the Grid. |
| RowsReordered | (None) | (None) | Fired when the user drag reorders rows. |
| RowToDatabase | column as GraffitiGridColumn <br> row as GraffitiGridRow | Boolean | Raised when a row is being saved back to its originating database. |
| ScrollPositionChanged | X as Integer <br> Y as Integer | (None) | The user has scrolled the display. |
| SelectionChanged | (None) | (None) | Fired when the user changes the row selection. Use methods to determine new selection. |
| Shown | (None) | (None) | (None) |
| Sorted | ByColumn as GraffitiGridColumn | (None) | When the user changes the sort order of the display after the rows have been sorted by the new sort order. |
## Methods
| Name | Parameters | Return Type | Description |
| --- | :---: | :---: | --- |
| AddColumn | newHeader as GraffitiGridColumn | (None) | Add a header to the grid. |
| AddRow | newRow as GraffitiGridRow | (None) | Adds a new row to the grid's data. |
| AddRows | Rows() as GraffitiGridRow | (None) | Adds the array of rows as specified to the grid. |
| AddRowSet | rs as RowSet <br> idField as String = "id" | (None) | Adds the rows contained within the RowSet to the grid. Only those values which match a grid column will be added. The idField parameter must match a PRIMARY KEY column in your database and you must return that column's values in the RowSet. |
| Column | atIndex as Integer | GraffitiGridColumn | Retrieve a Column object by the specified criteria, check for Nil after. |
| Column | ID as String | GraffitiGridColumn | Retrieve a Column object by the specified criteria, check for Nil after. |
| ColumnIndex | Column as GraffitiGridColumn | Integer | Returns the index of the column, useful for interation. |
| ColumnIndex | ID as String | Integer | Returns the index of the column, useful for interation. |
| Columns | (None) | GraffitiGridColumn | Returns an array of all currently added columns. |
| Debug | (None) | (None) | (None) |
| DeleteAllRows | (None) | (None) | Remove all rows from the grid. |
| DeselectAllRows | (None) | (None) | |
| EditActiveCell | (None) | (None) | Edit the cell that is currently selected. |
| EditCancel | (None) | (None) | Cancels the current edit operation. |
| EditCell | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Edit the defined cell. |
| EditCell | Row as Integer <br> Column as Integer | (None) | Edit the defined cell. |
| EditCommit | (None) | (None) | Commits the current edit operation. |
| EditorText | Assigns newValue as String | (None) | When editing, will update the text of the active editor. |
| InsertRow | Row as GraffitiGridRow <br> intIndex as Integer | (None) | Insert a row in the display. |
| LastColumnIndex | (None) | Integer | Index of the final column in the Grid. |
| LastRowIndex | (None) | Integer | Index of the final row in the Grid. |
| NextCell | (None) | (None) | Navigate selection to the next cell. |
| NextRow | (None) | (None) | Navigate selection to the next row. |
| PreviousCell | (None) | (None) | Navigate selection to the previous cell. |
| PreviousRow | (None) | (None) | Navigate selection to the previous row. |
| RemoveCellStyle | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Remove a GraffitiStyle from a cell. |
| RemoveColumn | Column as GraffitiGridColumn | (None) | Remove the specified column from the display. |
| RemoveColumn | columnIndex as Integer | (None) | Remove the specified column from the display. |
| RemoveRow | Row as GraffitiGridRow | (None) | Remove the specified row. |
| RemoveRow | intIndex as Integer | (None) | Remove the specified row. |
| ResetActiveCell | (None) | (None) | Resets the active cell to an empty value. |
| ResetGrid | (None) | (None) | Removes all Rows and Columns from the Grid. Do not execute when LockUpdate = True, execute before. |
| Row | RowIndex as Integer | GraffitiGridRow | Finds the row matching the criteria, check for Nil after. |
| Row | RowID as String | GraffitiGridRow | Finds the row matching the criteria, check for Nil after. |
| RowIndex | Row as GraffitiGridRow | Integer | Returns the current index of the row in the display. |
| Rows | (None) | GraffitiGridRow | Returns an array of all currently added rows. |
| ScrollTo | PositionX as Integer <br> PositionY as Integer | (None) | Scrolls the display to the specified coordinates. |
| ScrollToCell | Row as GraffitiGridRow <br> Column as GraffitiGridColumn | (None) | Scrolls the specified Row/Cell in to view. |
| ScrollToCell | Row as Integer <br> Column as Integer | (None) | Scrolls the specified Row/Cell in to view. |
| ScrollToRow | Row as GraffitiGridRow | (None) | Scrolls the display along the Y-axis to the specified row. |
| ScrollToRow | Row as Integer | (None) | Scrolls the display along the Y-axis to the specified row. |
| SearchRows | column as GraffitiGridColumn <br> value as Variant <br> limit as Integer = -1 | GraffitiGridRow | Returns the rows matching the specified criteria. |
| SearchRows | RowSetID as Integer | GraffitiGridRow | Returns the rows matching the specified criteria. |
| SelectedRows | (None) | GraffitiGridRow | Returns an array containing the currently selected rows. |
| SetActiveCell | Row as Integer <br> Cell as Integer = 0 <br> ForceEdit as Boolean = False | (None) | Sets the grid selection to the Row and Cell specified. If ForceEdit = True and the Grid is editable, the cell be put in edit mode. |
| SetCellStyle | Row as GraffitiGridRow <br> Column as GraffitiGridColumn <br> newStyle as GraffitiStyle | (None) | Add a GraffitiStyle to a cell. |
| SetFocus | (None) | (None) | (None) |
| SortBy | column as GraffitiGridColumn <br> direction as SortDirections | (None) | Sort the specified column. |
| toCSV | columnSeparator as String = "," <br> rowSeparator as String = "" | String | Returns a CSV string of the current grid contents. If rowSeparator is blank, EndOfLine.UNIX will be used. |
| UpdateBrowser | (None) | (None) | (None) |
| UpdateDisplay | InvalidateAllRows as Boolean = False | (None) | Force an update of the grid display. |
| UpdateFooter | (None) | (None) | Signals to update the footer row. |
## Properties
| Name | Type | Default Value | Description |
| --- | :---: | :---: | --- |
| AutoEdit | Boolean | (None) | When True and Editable = True, navigating/clicking the cells in the grid will automatically put them in edit mode. |
| CommitOnFocusLost | Boolean | (None) | Set to True to save editor changes when the user switches focus. |
| DatabaseAutoUpdate | Boolean | True | When True, rows that were loaded via AddRowSet and later modified will attempt to update their associated DatabaseRecords. |
| Editable | Boolean | (None) | When True, cells can be made editable using the EditActiveCell and EditCell methods. |
| Editing | Boolean | (None) | Returns True when the user is currently editing a cell. |
| EnableColumnGrouping | Boolean | (None) | Controls whether the grouped column header will be displayed and columns will be grouped according to their Group property. |
| EnableColumnReorder | Boolean | (None) | Allow users to drag reorder columns in the display. |
| Enabled | Boolean | (None) | (None) |
| EnableRowReorder | Boolean | (None) | Allow users to drag reorder rows. |
| FooterRow | GraffitiGridRow | (None) | Row data to display in the Grid's footer. |
| FooterRowFunction | String | (None) | JavaScript function used to validate or format footer row data. |
| FooterRowHeight | Integer | (None) | Height in pixels of the footer row. Cell values are top-left aligned. |
| FooterRowVisible | Boolean | (None) | When True, displays the footer row at the bottom of the Grid's data display area. |
| ForceFitColumns | Boolean | (None) | When True, columns are forced to stay inside the viewable area. Resizing one column will resize other proportionally to maintain visibility. |
| HeaderRowHeight | Integer | (None) | |
| HeaderRowVisible | Boolean | (None) | Determines if the columns header row is displayed. |
| ListIndex | Integer | (None) | |
| LockUpdate | Boolean | (None) | When True, certain actions are buffered until value is set to False again. This is used to increase the speed at which grids render as lengthy operations (like adding large numbers of rows) are deferred until all of the relevant data for the update is available. |
| MultiSelectRows | Boolean | (None) | When True, more than one row may be selected at a time in the display. |
| NextRowOnEnter | Boolean | (None) | Set to True to move to the next row when user presses Enter while editing. |
| RenderedBottomRow | Integer | (None) | The bottom-most row that is currently rendered in the display. This may be a row that is outside the display, but is rendered ahead for scrolling continuity. |
| RenderedTopRow | Integer | (None) | The top-most row that is currently rendered in the display. This may be a row that is outside the display, but is rendered ahead for scrolling continuity. |
| RowHeight | Integer | (None) | Height of all rows. |
| SearchCaseText | String | (None) | Sets the text of the label for the case sensitivity checkbox within the search panel. |
| SearchColumnHeaderText | String | (None) | Text displayed in the Column selector |
| SearchFieldPlaceholder | String | (None) | Text displayed in the search field when it has no value. |
| SearchFieldText | String | (None) | Text value of the search field. |
| SearchLabelText | String | (None) | Text displayed to the left of the search field. |
| SearchPanelVisible | Boolean | (None) | When True, the search panel will be displayed at the top of the control, below the column headers. |
| SelectedCell | Integer | (None) | The column index of the currently selected cell in the display. |
| SelectionType | SelectionTypes | (None) | Determines how focus on the grid is displayed, either by Row or Cell. |
| Sortable | Boolean | (None) | When True, users may sort the grid by clicking column headers. This also disable Tree functionality. |
| StyleCellBorder | GraffitiStyle | (None) | GraffitiStyle applied to row cells' border. If Nil, uses default Bootstrap style. |
| StyleFooterRow | GraffitiStyle | (None) | GraffitiStyle applied to the footer row. |
| StyleHeader | GraffitiStyle | (None) | GraffitiStyle applied to column headers. If Nil, uses default Bootstrap style. |
| StyleRowEven | GraffitiStyle | (None) | GraffitiStyle applied to even rows. If Nil, uses default Bootstrap style. |
| StyleRowOdd | GraffitiStyle | (None) | GraffitiStyle applied to odd rows. If Nil, uses default Bootstrap style. |
| StyleRowSelected | GraffitiStyle | (None) | GraffitiStyle applied to selected rows/cells. If Nil, uses default Bootstrap style. |
| StyleTextEditor | GraffitiStyle | (None) | GraffitiStyle applied to editor for columns using EditTypes.Text. |
| TreeView | Boolean | (None) | When True, the Grid can contain tree rows. Setting to True disables column sorting. |
## Notes
### Cell Editing
To enable cell editing on the Grid, the following must be done:
* The Grid instance’s Editable property must be True
* The Column’s Editor property must be defined to an appropriate type for the data within
* Either set the AutoEdit property to True — OR — call the EditActiveCell or EditCell methods to begin editing.
### Column Data Types
Cell value data types should not be mixed for cells in the same column. This is unsupported and may cause JavaScript exceptions and erratic behavior. The data types supplied for cell values should match the definite column FormatTypes and Editors. DateTime for Date, Strings for Text, Booleans for Checkbox, etc.
### Column Direct Modification
For GraffitiWebGrid 2.0, much of the functionality for manipulating Column properties has been moved from the GraffitiWebGrid class to GraffitiGridColumns. This allows you to do things like:
```xojo
dim colorColumn as GraffitiGrid
Column = gridInstance.Column( "colorval" )
cololColumn.Visible = False
```
### Column Grouping
If you wish to use the Column Grouping feature, each column must have a GraffitiColumnGroup assigned with unique text. Columns are grouped left-to-right and attempting to set a group to a subset of columns may result in incorrect positioning of groups and/or undesired column reordering.
### Edit Validation
GraffitiGrid supports committing cell edits by switching focus on the page using the CommitOnLostFocus property. Beware that other events, like button presses, that cause the focus to shift, may be received by the server before the updated cell data. Always check the Editing property when your Grid is editable to ensure that no current edit operation is ongoing or data may not be updated properly.
### Formatting Double or Currency values when using JavaScript functions
It may be necessary to use JavaScript’s [toFixed](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) function on these values to get the desired number of decimal places in your Grid display.
### Header and Cell Dimensions
When applying GraffitiStyles to your grid elements, you must remember that header style dimensions must match cell style dimensions. For example, if you are using a GraffitiStyle for your grid’s cells that has a border-left value of 1px, your header cell GraffitiStyle must match this. Failure to do this will result in headers and columns not lining up correctly in the display. Remember that borders may be a transparent color if you do not wish to display a border on one of these two elements.
This also applies to other dimension-altering properties like margins and padding.
### Hidden Columns and Resizing
If you use hidden columns in the grid, you must set their Resizeable property to False. Failure to do so will result in header-column resizing that doesn’t match row-column resizing.
### Implementing TreeView
When implementing a tree view, you must use the LockUpdate property to sync addition and removal of child rows by setting that property’s value to True before making changes and False when complete.
### Reserved Column Names
Make sure that none of your column or row definitions uses `id` as the column ID. This is used internally to track data, and will cause problems. Alternatively, use something like `myID` or `rowID`. Other strings to avoid in column IDs are:
* name
* field
* editor
* formatter
* sorter
* focusable
* minWidth
* resizable
* selectable
* sortable
* cssClass
* headerCssClass
* toolTip
* originalIndex
* RowTag
* groupName
* groupClass
* header
Additionally, IDs with a leading underscore are reserved for internal use.
### Row Direct Modification
As with Column Direct Modification above, Rows are implemented in the same fashion, allowing:
```xojo
dim colorColumn as GraffitiGridColumn = gridInstance.Column( "colorval" )
dim rowZero as GraffitiGridRow = gridInstance.Row( 0 )
rowZero.Cell( colorColumn ) = RGB( 0, 0, 0 )
```
### Search
The built-in SearchPanel doesn’t allow for much customization and only supports a limited number of column types to make it as fast as possible. If you wish to customize the search, especially on very large datasets, it’s recommended that you build search functionality which searches your data sever-side then displays the results.
The currently supported column Editor types for search are:
* Double
* Integer
* LongText
* Percent
* Text
* TextWithButton
* YesNoSelect
* Password
### Sorting and Tree Rows
Tree children are independent rows, and will be sorted as such. At the time of this writing (R27) sorting should, in most scenarios, be disabled on Tree grids.
## Examples
### Adding a PopupMenu Column
PopupMenu columns require the Editor property of the GraffitiGridColumn be set to GraffitiGrid.EditTypes.PopupMenu, and an array of strings be supplied to the column’s PopupMenuValues property. You can use a different Formatter, but the PopupMenu FormatType is strongly encouraged. Row values for this column should be the index of the PopupMenuValues string to display as the selection.
```xojo
var popupHeader as new GraffitiGridColumn( "popup", "Popup" )
popupHeader.Formatter = GraffitiGrid.FormatTypes.PopupMenu
popupHeader.Editor = GraffitiGrid.EditTypes.PopupMenu
popupHeader.PopupMenuValues = Array( "One", "Two", "Three" )
me.AddColumn( popupHeader )
```
### Assigning Values the FooterRow
The FooterRow is read only as it is populated with a GraffitiGridRow by default that is setup specifically for the role. If you wish to assign values to the footer row, you may interact with the FooterRow as you would any other GraffitiGridRow. As an example, if you wish to set the cell of the FooterRow that corresponds to the “title” column of your GraffitiGrid instance, you may use the following:
```xojo
var footerRow as GraffitiGridRow = gridInstance.FooterRow
var titleColumn as GraffitiGridColumn = gridInstance.Column( "title" )
footerRow.Cell( titleColumn ) = "Test"
```
### Creating a Basic Column
A basic column definition would look like this, as seen in the grid object Open events in pgeGrid of the demo:
```
var titleHeader as new GraffitiGridColumn( "title", "Title" )
titleHeader.Editor = GraffitiGrid.EditTypes.Text
titleHeader.Formatter = GraffitiGrid.FormatTypes.Text
me.AddColumn( titleHeader )
```
We’re creating a column with the id `title`, which any added rows must match.
### Creating a Basic Row
Here’s a basic row to match the column above, which can be seen in the Open events of the grid components on pgeGrid of the demo project:
```xojo
var dict as new Dictionary( "title" : "Row" )
var newRow as new GraffitiGridRow( dict )
me.AddRow( newRow )
```
### Disable Column Sorting
Column sorting is controlled per-column. To disable column sorting you must set the Sortable property of your GraffitiGridColumn instance to False:
```xojo
dim newColumn as new GraffitiGridColumn( "columnID", "Column Text", "columnField" )
newColumn.Sortable = False
me.AddHeader( newColumn )
```
### Dynamically Adding Rows When User Presses Enter
The below KeyPress event will create a new (mostly) empty row when the user highlights the last cell in the last row and presses the Enter key.
```xojo
Sub KeyPress(Row as GraffitiGridRow, Column as GraffitiGridColumn, KeyCode as Integer, AltKey as Boolean, CtrlKey as Boolean, ShiftKey as Boolean) Handles KeyPress
if KeyCode = 13 and row = me.Row( me.RowCount - 1 ) and Column = me.Column( me.ColumnCount - 1 ) then
var newRow as new GraffitiGridRow( new Dictionary( "title" : "Dynamic Row" ) )
me.AddRow( newRow )
me.EditCell( newRow, me.Column(0) )
end if
End Sub
```
### Edit Selected Cell
If you don’t want all cells to be editable, you should set the Editable property of the GraffitiWebGrid instance to True, the AutoEdit property to false, then use logic in the CellClick event (or elsewhere) to trigger the Edit.
For using column indices:
```xojo
Sub CellClick(Row as Integer, Column as Integer) Handles CellClick
If Column = 1 Then me.EditActiveCell
End Sub
```
For using column fields or other properties:
```xojo
Sub CellClick(Row as GraffitiGridRow, Column as GraffitiGridColumn, pageX as Integer, pageY as Integer) Handles CellClick
if Column.ID = "columnFieldValue" then me.EditActiveCell()
End Sub
```
### Example FooterRow Function
```xojo
function(row, column, allRows) {
if (column.id == "perc") {
var total = 0;
allRows.forEach(function(currentRow) {
total += currentRow.perc;
});
var totalSpan = $("<span />" ).text(toDouble(total) + " %");
totalSpan.css("color", ((total >= 0) ? "#0f0" : "#f00"));
return totalSpan.prop("outerHTML");
} else {
return row[column.id];
}
}
```
To express numbers in a localized format, you can use the `toDouble` function in your FooterRowFunction JavaScript. toDouble has a single parameter and will convert, for example, `1000.50` to `1000,50` for locales where the decimal character is a comma.
It is your responsibility to provide functioning JavaScript code and implement your own error checking. Make use of JavaScript’s [Try…Catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) blocks and [Debugger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) statement as necessary.
### Implementing Column-Based Contextual Menus
To implement a contextual menu, you will add a GraffitiMenu class to the page/container that houses the Grid. Then, when creating your columns, you will create and assign a GraffitiMenuItem to the GraffitiColumn.ContextMenu property. This can be seen in the Open event of gwgDemo on pgeGrid in the demo project:
```xojo
var TitleMenu as new GraffitiMenuItem( "TitleMenu" )
TitleMenu.Children.AddRow( new GraffitiMenuItem( "item1", "This menu is tied to" ) )
TitleMenu.Children.AddRow( new GraffitiMenuItem( True ) )
TitleMenu.Children.AddRow( new GraffitiMenuItem( "item2", "Right-Click for Title cells" ) )
GraffitiMenu1.AddMenu( TitleMenu )
dim titleHeader as new GraffitiGridColumn( "title", "Title" )
titleHeader.ContextMenu = TitleMenu
me.AddColumn( titleHeader )
```
You will respond to menu selections in the MenuAction event of the GraffitiMenu instance you’ve added to the page:
```xojo
select case InMenu.Name
case "TitleMenu"
var selRow as GraffitiGridRow = gwgDemo.SelectedRows(0)
MessageBox( ChildItem.Name + " ContextClick on " + selRow.Cell( gwgDemo.Column( "title" ) ) )
case "type"
var typeColumn as GraffitiGridColumn = gwgDemo.Column("type")
clickRow.Cell(typeColumn) = ChildItem.Caption
end select
```
### Implementing Event-Based Contextual Menus
As was shown previously, you will add a GraffitiMenu instance to the page/container, then create a GraffitiMenuItem and add that:
```xojo
var EditMenuItem as new GraffitiMenuItem( "EditMenu" )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "text", "Plain Text" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "undo", "Undo", "fa fa-undo", false, "u" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( True ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "cut", "Cut", "fa fa-cut", false, "t" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "copy", "Copy", "fa fa-copy", false, "c" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "paste", "Paste", "fa fa-paste", True, "p" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "delete", "Delete", "fa fa-times", false, "d" ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( True ) )
EditMenuItem.Children.AddRow( new GraffitiMenuItem( "selall", "Select All", "fa fa-i-cursor", false, "s" ) )
GraffitiMenu1.AddMenu( EditMenuItem )
```
Then, in the ContextClick event of your Grid, you will show the GraffitiMenuItem:
```xojo
var contextMenu as GraffitiMenuItem = GraffitiMenu1.MenuByName( "EditMenu" )
GraffitiMenu1.ShowMenu( contextMenu, cellLeft, cellTop + cellHeight )
```
And, finally, handle the result (if any) in the GraffitiMenu instance’s MenuAction event.
### Loading Database Records
GraffitiGrid has an AddRowSet method that accepts a RowSet object as its first parameter. Your database table design and GraffitiGridColumn IDs should not conflict with reserved column names listed at the bottom of this page. The GraffitiGridColumn object IDs should match your database field IDs and should be added before the call to AddRowSet (typically the Open event is the best place to populate columns), for example “first_name” would result in a GraffitiGridColumn definition that looks like this:
```xojo
var firstName as new GraffitiGridColumn( "first_name", "First Name" )
```
You would then execute your query to return a RowSet object and pass that to AddRowSet, specifying the unique key field name as the idField parameter.
From there, GraffitiGrid will populate the rows using the RowSet provided and, if implemented, raise the RowFromDatabase event so data can be modified. A typical use for this is populating the Grid’s custom cell types based on the data in the database row such as creating GraffitiGridBadges.
If the DatabaseAutoUpdate property is set to True, when a Grid row is edited by the user, the Grid will attempt to write that change to the database after raising the RowToDatabase event, allowing for a reverse transform to match any made in RowFromDatabase. This may fail if the database connection is lost. Users are encouraged to implement their own means of updating database rows under such conditions.
### Retrieving Value from Selected Row
```xojo
Sub SelectionChanged() Handles SelectionChanged
if me.SelectedRows.Ubound >= 0 then
dim selRow as GraffitiGridRow = me.SelectedRows(0)
dim firstColumn as GraffitiGridColumn = me.Column(0)
dim rowColumnValue as String = selRow.Cell( firstColumn )
'// Do something with rowColumnValue here. Note that GraffitiGridRow.Cell
' returns a variant which matches the data type of that column, so String
' may not be the correct data type depending on what you're project is
' doing.
end if
End Sub
```
### Sample Column of FormatTypes.JavaScript
```xojo
var jsHeader As New GraffitiGridColumn( "jsformatter", "jsformatter" )
jsHeader.Formatter = GraffitiGrid.FormatTypes.JavaScript
var jsFormatter() as String
jsFormatter.Add( "function (rowIndex, cellIndex, cellValue, column, row) {" )
jsFormatter.Add( " return '<strong>From JavaScript</strong>: ' + row['title'];" )
jsFormatter.Add( "}" )
jsHeader.FormatterJavaScript = string.FromArray( jsFormatter, "" )
jsHeader.Width = 130
Me.AddColumn( jsHeader )
```
It is your responsibility to provide functioning JavaScript code and implement your own error checking. Make use of JavaScript’s [Try…Catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) blocks and [Debugger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger)statement as necessary.
## Common Problems
### Encoding Errors
This is a common error when you’re loading non-UTF8 data from MySQL for use in Xojo Web projects. To address this issue, you should execute the following commands upon connecting:
```xojo
myDatabase.ExecuteSQL("set names utf8 collate utf8_general_ci")
myDatabase.ExecuteSQL("set character set utf8")
```
### Errors when copying a row from one Grid instance to another
This is unsupported. If you wish to move or reuse a GraffitiGridRow instance in multiple Grids, you must use the GraffitiGridRow.Clone (Release 44+) method to create a copy for each Grid instance where you wish to display the row. Even then updates to the data are not shared across Grid instances and each GraffitiGridRow instance must be updated individually.
### No Rows Rendered
Make sure that your row data matches up to your column IDs. Additionally, column names should not consist of only a numeric value, or begin with a number. As an example, `item0` is valid, while `0` or `0item` is not.
### Scrolling on iOS
There is an incompatibility between GraffitiListGroup and GraffitiGrid that causes scrolling to be nonfunctional of iOS devices. Unfortunately this means that GraffitiListGroup must be removed from your projects where you use GraffitiGrid. A remedy is being investigated, but may require rewriting one or more components.
### Selected Rows are out of order
Multiple row selection does not guarantee that the order of rows will be maintained upon selection either by the order in which they are selected or the order in which they are added to the Grid.