Package com.smartgwt.client.docs

# Interface Editing

public interface Editing

### Grid Editing

Data being displayed by a grid may be edited within the grid, by showing editing interfaces embedded inside the cells of the grid.

Enabling editing

Editing is enabled when `canEdit` is `true`. When enabled, the user can begin editing via the `editEvent`, typically click or double-click. Editing can also be triggered programmatically by a call to `startEditing()` or `startEditingNew()`.

New record creation

By default, editing is restricted to existing records. Setting `ListGrid.listEndEditAction` to "next" allows the user to create new records by simply navigating off the end of the dataset with the keyboard. Editing of new records can also be initiated with `ListGrid.startEditingNew()`, for example, from a button outside the grid. See the `Unsaved Records Overview` for special concerns when dealing with unsaved records.

Saving changes

Saving of changes is triggered automatically when the user navigates out of the row or cell being edited (based on `ListGrid.saveByCell`) or when the user ends editing. For a "mass update" interface, automatic saving of changes can be disabled entirely via `autoSaveEdits:false`, in which case a manual call to `saveEdits()` or `saveAllEdits()` is required to trigger saving.

If a grid has no DataSource, saving means that the properties of the `ListGridRecord`s in `grid.data` are directly changed.

For a grid with a DataSource, saving will be accomplished by using DataSource "update" operations for existing records, and DataSource "add" operations for new records. If multiple records have been edited and `saveAllEdits()` is called, `request queuing` will be automatically used to enable all edits to be saved in one HTTP turnaround (if using the Smart GWT Server).

By default, a grid will send only updated fields and primaryKey fields as part of `DSRequest.data` so that the server can discern which fields the user actually changed. However, the grid always includes the original field values in the dsRequest as `DSRequest.oldValues`.

Note that although it is possible to load DataSource data without actually declaring a `primaryKey field`, a primaryKey must be declared for editing and saving. The values of primaryKey fields is how Smart GWT identifies the changed record to the server.

Saving edits in a sorted data set: When a user updates or adds a record in a sorted listGrid, the data set may be automatically `unsorted`. When this happens, the sort indicator will be removed from sort field headers, and all rows will stay in their current positions, including edited records where the sort field value has been changed.
Note that for a databound grid with a partial data set, a "true unsort" isn't possible without droppping the cache, as both client and server need to agree on the positions of rows. In this case the grid is marked as unsorted, and all visible rows stay in place until the next fetch occurs, at which point the cache is dropped and a truly unsorted data set retrieved from the server. Typically the next fetch would be caused by the user scrolling to a new position in the grid. Once that fetch occurs the positions of rows within the grid will be updated to match the positions of rows in the unsorted server-side data set, meaning if the user scrolled back to their previous position they may see a different set of records. (See also `ResultSet.updatePartialCache`).

Validation

Any time saving is attempted, validation is automatically triggered. Values entered by the user will be checked against the `ListGridField.validators` and the `DataSourceField.validators`. Any invalid values abort an attempted save.

Similar to editing and saving, validation can be done on row transitions or on cell transitions by setting `validateByCell`, or can be disabled entirely via `neverValidate:true`.

Editability of cells

Editors will either be shown for the complete row or for a single cell based on `editByCell,editByCell`. Whether a cell can be edited can be controlled on a per field basis by setting `field.canEdit`, or on a per-record basis by setting `recordEditProperty` on a `record`, or can be controlled on an arbitrary, programmatic basis via an override of `ListGrid.canEditCell()`.

Cells which are not editable just display the cell's current value.

Keyboard Navigation

Full keyboard navigation is supported by default, including Tab and Shift-Tab to navigate between cells in a row, and Up Arrow and Down Arrow to traverse rows. Several properties on both grids and fields, all named *EditAction, control navigation behavior of certain keys (eg Enter).

You can use `startEditing(rowNum, colNum)` to programmatically move editing to a particular cell, for example, during a `field.changed()` event.

editValues (unsaved changes)

The term "editValues" means changes that the user has made to the dataset which have not been saved. The grid manages and stores editValues separately from the data itself in order to allow the user to revert to original values, and in order to enable to grid to send only updated fields to the server.

Because editValues are stored separately, if you directly access the dataset (eg via `grid.getData().get()`) you will see the records without the user's unsaved changes. Many APIs exist for retrieving and managing editValues (search for editValue). For the common case of needing to access the record-as-edited, you can call `grid.getEditedRecord(rowNum)`.

When accessing and manipulating edited data, you should think carefully about whether you want to be working with the original data or with the edited version. Values entered by the user may not have been validated yet, or may have failed validation, hence you may find a String value in a field of type "date" or "int", which could cause naive formatters or totaling functions to crash.

Setting editValues via APIs such as `ListGrid.setEditValue()` is fully equivalent to the user making changes to data via the editing UI. If you also allow editing external to the grid, setting editValues is one way to combine changes from external editors into the grid's edits, so that you can do a single save.

Customizing Cell Editors

When a cell is being edited, the editor displayed in the cell will be a `FormItem`. The editor type for the cell will be determined by `ListGrid.getEditorType()` based on the specified `ListGridField.editorType` or `data type` for the field in question.

You can customize the editor by setting `ListGridField.editorProperties` to a set of properties that is valid for that FormItem type. Custom FormItem classes are also allowed, for example, you may use `FormItem.icons` to create an icon that launches a separate `Dialog` in order to provide an arbitrary interface that allows the user to select the value for a field.

Events

Editing triggers several events which you can provide handlers for in order to customize editing behavior. Some of the most popular are `field.change()`, `field.changed()` for detecting changes made by the user, `ListGrid.cellSaved()` for detecting changes that have been successfully saved, and `editorEnter` and `editorExit()` for detecting user navigation during editing.

`ListGridField.setEditorType()` can be used to customize the editors shown for each field, including providing FormItem-specific event handlers. However, ListGrid-provided event APIs should be used wherever possible (for example, use `EditorEnterEvent` rather than `FocusEvent`). If, in a FormItem event handler, you need access to the ListGrid, you can either declare the event handler as a Java "inner class" in a scope where the ListGrid is available as a final variable, or you can use `event.getItem().getContainerWidget()`. Note the ListGrid APIs `getEditRow()` and `getEditCol()` indicate what cell is being edited.

For more dynamic editor customization, include changing the type of editor used on a per-row basis, use listGrid.setEditorCustomizer().

NOTE: with both APIs, in effect several FormItems are generated from the customized FormItem you provide - see the docs for `DataSourceField.editorType` for special coding patterns that apply in this case.

Binary Fields

The ListGrid will automatically show "view" and "download" icon buttons for binary field types (see `ListGridFieldType`). However, you cannot use an upload control embedded within a ListGrid row to upload files (regardless of whether you use FileItem or UploadItem). This is because, in the browser's security model, native HTML upload controls cannot be re-created and populated with a chosen file, and the ListGrid needs to be able to re-create editors at any time in order to handle loading data on scroll, scrolling editors in and out of view, adding new rows, changing sort direction, and other use cases.

However you can create an editor with a `FormItem icon` that pops up a separate Window containing a FileItem in a DynamicForm, so long as the form in the Window saves the uploaded file immediately rather than trying to have the grid perform the save.

See Also:
  - `InlineEditEvent`
  - `SearchEditorMode`
  - `RowEndEditAction`
  - `EnterKeyEditAction`
  - `EscapeKeyEditAction`
  - `ArrowKeyEditAction`
  - `EditCompletionEvent`
  - `ListGridEditEvent`
  - `CubeGrid.setEditValue(int, int, java.lang.Object)`
  - `CubeGrid.getEditValue(int, int)`
  - `CubeGrid.getEditedRecord(int, int)`
  - `CubeGrid.getEditedCell(int, int)`
  - `ListGrid.getEditValues(int)`
  - `ListGrid.clearEditValue(int, java.lang.String)`
  - `ListGrid.saveEdits()`
  - `com.smartgwt.client.widgets.cube.CubeGrid#getAllEditCells`
  - `ListGrid.discardAllEdits()`
  - `CubeGrid.recordHasChanges(int, int)`
  - `CubeGrid.hasChanges()`
  - `ListGrid.saveAllEdits()`
  - `com.smartgwt.client.widgets.form.DynamicForm#getEditorType`
  - `DynamicForm.fieldIsEditable(com.smartgwt.client.widgets.form.fields.FormItem)`
  - `com.smartgwt.client.widgets.grid.ListGridField#defaultDynamicValue`
  - `EditorEnterEvent`
  - `EditorExitEvent`
  - `com.smartgwt.client.widgets.grid.ListGridField#cellChanged`
  - `com.smartgwt.client.widgets.grid.ListGridField#formatEditorValue`
  - `com.smartgwt.client.widgets.grid.ListGridField#parseEditorValue`
  - `ChangeEvent`
  - `ChangedEvent`
  - `ListGrid.markRecordRemoved(int)`
  - `ListGrid.markRecordsRemoved(com.smartgwt.client.widgets.grid.ListGridRecord...)`
  - `ListGrid.recordMarkedAsRemoved(int)`
  - `ListGrid.unmarkRecordRemoved(int)`
  - `ListGrid.markSelectionRemoved()`
  - `ListGrid.canEditCell(int, int)`
  - `ListGrid.fieldIsEditable(com.smartgwt.client.widgets.grid.ListGridField)`
  - `ListGrid.startEditing()`
  - `ListGrid.editExistingRecord()`
  - `com.smartgwt.client.widgets.grid.ListGrid#getEditorValueMap`
  - `ListGrid.setEditorValueMap(java.lang.String, java.util.LinkedHashMap)`
  - `com.smartgwt.client.widgets.grid.ListGrid#getEditorType`
  - `ListGrid.startEditingNew()`
  - `ListGrid.getAllEditRows()`
  - `ListGrid.getEditValues(int)`
  - `ListGrid.getEditedRecord(int)`
  - `ListGrid.getEditedCell(int, int)`
  - `ListGrid.setEditValue(int, int, java.lang.Object)`
  - `ListGrid.getEditValue(int, int)`
  - `ListGrid.clearEditValue(int, java.lang.String)`
  - `ListGrid.getEditRow()`
  - `ListGrid.getEditCol()`
  - `com.smartgwt.client.widgets.grid.ListGrid#getEditField`
  - `ListGrid.cancelEditing()`
  - `ListGrid.endEditing()`
  - `ListGrid.findNextEditCell(int, int, boolean, boolean, boolean)`
  - `ListGrid.discardAllEdits()`
  - `ListGrid.discardEdits(int, int)`
  - `ListGrid.saveEdits()`
  - `ListGrid.rowHasChanges(int)`
  - `ListGrid.hasChanges()`
  - `ListGrid.cellHasChanges(int, int)`
  - `ListGrid.saveAllEdits()`
  - `CellSavedEvent`
  - `EditCompleteEvent`
  - `EditFailedEvent`
  - `EditorEnterEvent`
  - `RowEditorEnterEvent`
  - `EditorExitEvent`
  - `RowEditorExitEvent`
  - `com.smartgwt.client.widgets.grid.ListGrid#formatEditorValue`
  - `com.smartgwt.client.widgets.grid.ListGrid#parseEditorValue`
  - `TreeGrid.startEditingNew()`
  - `Calendar.getEventSnapGap()`
  - `Calendar.getShowQuickEventDialog()`
  - `com.smartgwt.client.widgets.calendar.Calendar#getEventEditorFields`
  - `Calendar.getEventEditorDateFieldTitle()`
  - `com.smartgwt.client.widgets.calendar.Calendar#getEventDialogFields`
  - `ListGrid.getRecordCanRemoveProperty()`
  - `ListGridRecord.get_canRemove()`
  - `ListGrid.getSaveRequestProperties()`
  - `ListGridField.getEditorImageURLPrefix()`
  - `ListGridField.getEditorImageURLSuffix()`
  - `com.smartgwt.client.widgets.grid.ListGridField#getIcons`
  - `ListGridField.getEditorIconWidth()`
  - `ListGridField.getEditorIconHeight()`
  - `ListGridField.getDefaultIconSrc()`
  - `ListGridField.getIconVAlign()`
  - `ListGridField.getCanEdit()`
  - `com.smartgwt.client.widgets.grid.ListGridField#getDefaultValue`
  - `ListGridField.getEnterKeyEditAction()`
  - `ListGridField.getEscapeKeyEditAction()`
  - `ListGridField.getArrowKeyEditAction()`
  - `com.smartgwt.client.widgets.grid.ListGridField#getEditorType`
  - `com.smartgwt.client.widgets.grid.ListGridField#getEditorProperties`
  - `ListGridField.getInitialValue()`
  - `ListGrid.getModalEditing()`
  - `ListGridField.getMultiple()`
  - `com.smartgwt.client.widgets.grid.ListGridField#getEditorValueMap`
  - `ListGrid.getCanEdit()`
  - `ListGrid.getRecordEditProperty()`
  - `ListGridRecord.get_canEdit()`
  - `ListGrid.getAlwaysShowEditors()`
  - `ListGrid.getEditByCell()`
  - `ListGrid.getSaveByCell()`
  - `ListGrid.getCanRemoveRecords()`
  - `ListGrid.getDeferRemoval()`
  - `ListGrid.getWaitForSave()`
  - `ListGrid.getStopOnErrors()`
  - `ListGrid.getAutoSaveEdits()`
  - `ListGrid.getConfirmCancelEditing()`
  - `ListGrid.getCancelEditingConfirmationMessage()`
  - `ListGrid.getConfirmDiscardEdits()`
  - `ListGrid.getAutoConfirmSaveEdits()`
  - `ListGrid.getConfirmDiscardEditsMessage()`
  - `ListGrid.getDiscardEditsSaveButtonTitle()`
  - `ListGrid.getRowEndEditAction()`
  - `ListGrid.getListEndEditAction()`
  - `ListGrid.getNewRecordRowMessage()`
  - `ListGrid.getEnterKeyEditAction()`
  - `ListGrid.getEscapeKeyEditAction()`
  - `ListGrid.getArrowKeyEditAction()`
  - `ListGrid.getEditEvent()`
  - `ListGrid.getEditOnFocus()`
  - `ListGrid.getEditOnF2Keypress()`
  - `ListGrid.getSelectOnEdit()`
  - `ListGridField.getCanToggle()`
  - `ListGrid.getEnumCriteriaAsInitialValues()`
  - `ListGrid.getLongTextEditorThreshold()`
  - `ListGrid.getLongTextEditorType()`