Class: cWebGrid

Properties  Events  Methods    Index of Classes

The Web Framework multi-row, multi-column grid control

Hierarchy

cObject
---cWebObject
------cWebBaseUIObject
---------cWebBaseDEOServer
------------cWebBaseControl
---------------cWebList
------------------cWebGrid

Library: Web Application Class Library

Package: cWebGrid.pkg

Description

The cWebGrid class provides the basis for creating multi-row, multi-column display and entry. Each column in a grid is represented by a column object. Web grids use the cWebColumn, cWebColumnButton, cWebColumnCheckbox, cWebColumnCombo, cWebColumnDate, cWebColumnImage and cWebColumnLink classes for its column objects.



A grid can be used with or without a data binding. When used with a data binding, the grid rows and columns are populated from the data provided by the grid's server data dictionary object. When used without a data binding, you will use the class interface to read or write the control value.

If you do not need to support editing the grid data (i.e., a read-only list), then you should use the cWebList control instead.

Topics




Object Name

The Web Framework uniquely identifies each web object via a combination of the object hierarchy (object nesting), and object name. This means that web object names must be unique within their parent (i.e. each sibling web object must have a unique name).

Object Placement

Grid controls must be placed within a web container (e.g. cWebPanel, cWebView or cWebModalDialog).

Grid controls may not be nested inside other web controls. You may not mix web panels and web controls as sibling objects.

Size and Location

Web controls are positioned by HTML flow layout (left to right, top to bottom). The relative position of the control in this flow is determined by the location of the object declaration in your code.

In addition to the flow layout, each web container is divided into a fixed number of equal-width layout columns (piColumnCount). Child controls are aligned to these layout columns to determine their horizontal position and width.

Set piColumnIndex to position a grid control in a particular column of the parent container.

Set piColumnSpan to determine the width of the grid control i.e., the number of layout columns occupied by the control. The actual width is determined by the number of columns and the width of the parent container.

For more information, see Positioning and Layout of Controls.

Each grid control has a pre-determined minimum height according to the web application's CSS theme ([PLinkcWebApp.:psTheme]). Set piHeight to set the grid control to a fixed pixel height. You can also instruct a grid control to occupy all available vertical height in its parent container by setting pbFillHeight to True.

The piHeight and pbFillHeight properties are mutually exclusive and should not be used together in the same object.


Sample

Object oCustomerView is a cWebView
    Object oCustomer_DD is a Customer_DataDictionary
    End_Object

    Set Main_DD to oCustomer_DD
    Set Server to oCustomer_DD
    
    Procedure OnLoad
        Send Find of oCustomer_DD FIRST_RECORD 1
    End_Procedure

    Object oCustomerList is a cWebGrid
        Set pbFillHeight to True
                      
        Object oCustomer_Name is a cWebColumn
            Entry_Item Customer.Name
            Set psCaption to "Customer Name"
            Set piWidth to 50
        End_Object
    
        Object oCustomer_City is a cWebColumn
            Entry_Item Customer.City
            Set psCaption to "City"
            Set piWidth to 50
        End_Object
    
        Object oCustomer_State is a cWebColumnCombo
            Entry_Item Customer.State
            Set psCaption to "State"
            Set piWidth to 40
        End_Object
    
        Object oCustomer_Status is a cWebColumnCheckBox
            Entry_Item Customer.Status
            Set psCaption to "Active"
            Set piWidth to 15
        End_Object
    End_Object
End_Object

The above sample demonstrates a web view (cWebView) containing a DataDictionary object (DDO) and a grid (cWebGrid) whose rows and columns are populated from the data dictionary.

The grid contains four column objects, each with a data binding to the Customer table. Two cWebColumn objects are used to display the customer name and city text values; a cWebColumnCombo object is used to display a list of combo items to display and select a state; a cWebColumnCheckbox object is used to display the customer active status in a column of checkboxes.

The OnLoad event is fired when the view is first loaded to the client. This has been augmented to 'seed' the Customer data dictionary with the first record in the table. This seeding will cause the grid to fill its rows with data from the customer table starting with the record found in the OnLoad event.

For an example of 'manually' loading grid data without data bindings (non-data aware), see cWebList.


Row IDs and Web Lists/Grids

When the grid or list is data-aware, then the RowID that is stored for each row is the same as the database record's RowID, i.e. the database record row ID is the value stored in the grid row ID.

If the grid or list is not data-aware, then the RowID that is stored for each row is simply a unique row id determined by the developer.


Retrieving Grid Data

When you have a manually loaded grid, there will be occasions where you will need to retrieve the current set of grid data from the client, i.e. the application user has edited the data and you wish to save it or process it in some way.

Send ProcessDataSet to retrieve the entire set of grid data (rows & columns). ProcessDataSet will send a message back to the client requesting that it sends back the grid data. Example:

Object oWebButton1 is a cWebButton
    Set psCaption to "Save Data!"

    Procedure OnClick
        Send ProcessDataSet of oMyGrid 100
    End_Procedure
End_Object

The ProcessDataSet method accepts an application-specific integer parameter (eOperation). The value that you pass in this parameter will be returned with the grid's data set. You can then use this value to determine what operation is intended to occur when the data is send back to the server (e.g. save the data, process it, write a log, etc).

When the grid data is returned, the grid's OnProcessDataSet event is fired. This event receives three parameters: The grid data, the eOperation value that was passed to ProcessDataSet (above) and the row number of the currently selected grid row. Each row in the returned grid data will contain the unique row ID that was assigned when the grid was loaded (see Manually Loaded Grids, above).

Implement an OnProcessDataSet event handler to perform the desired action on the returned grid data.


Data Aware Grids

Grid objects support datasets served by a data dictionary object structure. The grid's Server property specifies the grid's connection to a data dictionary object (DDO). By default, the grid's server data dictionary is delegated to the Main_DD setting of the host view or dialog.
When the grid has a data server then each grid column will support a data binding to a specific Table.Column from the data dictionary object structure. See cWebColumn for more information.

A data binding provides data-aware behaviors that include:

- Finding, clearing, saving, and deleting records
- Prompt-object support
- Change verification (save, delete, and data-loss verifications)

A data binding also automatically provides the control's data type, input mask, tooltip, control focus rules, control blur rules, display formats (capslock, noput, displayonly, etc.) and much more. These settings may also be controlled manually by setting properties.

Each time a request is processed by a view (or dialog) the grid's psCurrentRowID property is set to the RowID of the currently selected grid row on the client. Use psCurrentRowID to retrieve the currently selected row.

The grid object's pbDataAware property must be set to True in order for the control work with a data dictionary object structure. For more information see "Manually Loaded Grids".


Deleting the Current Row


OnDeleteRow - Use this event to manually handle delete row operations. This is triggered whenever the Request_Delete operation is performed (i.e. by clicking the standard Delete button on the application's toolbar).


Manually Loaded Grids

Set pbDataAware to False if you want to populate a grid object programmatically, i.e. without using data dictionary objects or data-bound columns. In this case you will need to implement the grid's OnManualLoadData event to populate the rows and columns with your desired data.

The OnManualLoadData event passes back an array of tWebRow structs where each array member represents a row of column data for the list. The order of array members will determine the order of rows.

The tWebRow - aValues member is the array you will need to populate to represent the column values for each row. The 0th member of this array represents a unique row identifier. You may set this to any value you wish but you must ensure that each row has a unique value. The remaining values in this member represent the values to be displayed in each column from left to right.

The OnManualLoadData event is not automatically fired. You will need to write code in your view to trigger it. Typically you would augment the grid's OnLoad event to do this by signaling the client to perform a GridRefresh, for example:

Procedure OnLoad
    Forward Send OnLoad    
    Send GridRefresh
End_Procedure

See below for information on saving a manually loaded grid.


Saving a Manually Loaded Grid

If your grid has been manually loaded and pbDataAware is set to False (i.e. the grid is not data aware / not using data dictionary objects), then you will need to write special code in order to save any changes that were entered by the application user.

There are two approaches to saving data in a manually loaded grid: Saving all of the grid data in one operation, or saving the current row each time the user moves to a different row.

Saving the Entire Grid

Set pbOfflineEditing to True if you wish to save the entire grid data in one operation (i.e. a Commit or Save Grid operation). This will prevent the grid from sending the OnSaveRow, OnNewRow and OnChangeCurrentRow events to the server. Normally you would only require these events if you wish to save the current row each time the user moves to a different row (see below).

Use the ProcessDataSet, OnProcessDataSet interface described in Retrieving Grid Data (above) to retrieve the entire set of grid data for saving.

Saving the Current Row

Set pbOfflineEditing to False if you wish to save manually loaded grid data row-by-row whenever the application user moves to a different row. This will ensure that the OnSaveRow, OnNewRow and OnChangeCurrentRow events are sent to the server.

Implement OnSaveRow to save changes to each row. This event is triggered when the currently selected row is about to change or whenever the Request_Save operation is performed (e.g. by clicking the standard Save button on the toolbar). The row id of the row to be saved is passed as a parameter. You can modify the row id value and this will be stored in the row data at the client. Query the individual column objects' psValue and pbChanged properties to retrieve the column values for the current row. If OnSaveRow's return value is False then the change row operation will be cancelled.

Manually Loaded Grid Events

The following event is triggered in a manually loaded grid when the pbDataAware property is False:

OnDeleteRow - Use this event to manually handle delete row operations. This is triggered whenever the Request_Delete operation is performed (i.e. by clicking the standard Delete button on the application's toolbar).


Grid Actions

Send AppendNewRow to instruct the client to begin editing a new row at the bottom of the grid. If pbOfflineEditing is False, then this will trigger the OnNewRow event to be sent back to the server.

Send InsertNewRow to instruct the client to insert a new row above the currently selected row and begin editing this new row. If pbOfflineEditing is False, then this will trigger the OnNewRow event to be sent back to the server.

Send UpdateRow to refresh the client's current row data. In a data-aware grid, the row data will be populated automatically using the data dictionaries. In a manually loaded grid, UpdateRow will trigger the OnSetCalculatedValue event for each column object in the grid.

Send ClearRow or RemoveRow to instruct the client to clear the current row at the client.


Edit Operations

The grid control supports different modes of operation that either restrict or allow various editing operations.

Use the pbAllowAppendRow, pbAllowDeleteRow, pbAllowInsertRow properties to allow add or remove row operations.

Use pbAutoSave to determine whether changes to the current grid row are automatically saved when the user moves to a different row.

If you need to make the grid data read only, you can set the pbEnabled property. The cWebList class is specifically designed as a read only control.


Sorting

When the grid data is populated by a data dictionary object structure (DDO server), then the grid rows can be sorted using any database index defined for the server DDO's Main_File. Which index is used is determined in the following way:
- If no preferred indexes are specified, then the grid is sorted by the main table's default index (for the embedded database this would be the recnum index).
- If the grid's piOrdering property is set (<> -1), then this value will be the index number used to sort the grid.
- Another way to set the sort order is to set the piSortColumn property to the column number of the column you wish to sort by. If this column has a default index setting (piDefaultIndex <> -1) then this will be the index used to sort the grid, overriding piOrdering. Set piSortColum to -1 in order not to sort the data.
- You can set the pbReverseOrdering property to True to reverse the sort order determined by the above properties.
- If the server data dictionary object's Ordering property is set (<> -1) then this value will be the index number used to sort the grid overriding all other sort property settings.

Comparing these various properties, only piSortColumn and pbReverseOrdering among them are web properties. This means piSortColumn and pbReverseOrdering are synchronized to the client so can be modified after the view has been loaded to the client. If you programmatically WebSet piSortColumn or pbReverseOrdering then you should also send GridRefresh to ensure the grid data is reloaded in the new order.

For each column that is 'sortable' (i.e., the column's piDefaultIndex <> -1), the column's header text is specially formatted to indicate a sortable column. Usually it is indicated by underlining the psCaption text. The user can click the caption of a sortable column to force the grid to be resorted according to the piDefaultIndex of that grid column. An arrow is also available in the caption that can determine if the selected sort order is reversed or not. This behavior is equivalent to programmatically changing piSortColumn or pbReverseOrdering then sending GridRefresh.


Changing Rows

Use the following interface to programmatically manipulate the currently selected row:

Send MoveToFirstRow to make the first row the selected row.
Send MoveToLastRow to make the last row the selected row.
Send MovePageUp to select the row one page up. The size of a page depends on the height of the list.
Send MovePageDown to select the row one page down. The size of a page depends on the height of the list.
Send MoveUpRow to select the previous row.
Send MoveDownRow to select the next row.
Send MoveToRow to select a specific row by its row index.
Send MoveToRowByID to selects a specific row by its RowId.

Appearance

Appearance

The colors used by a grid control are determined by the web application's CSS theme (psTheme). You can define additional or replacement CSS styles in your web application's application.css file. Set psCSSClass to the CSS class name you would like to be applied to a grid control.

Drag and Drop Support

Drag Support

This control allows parts of itself to be picked up and dragged to other places in your interface. To do this, register it as a drag source in a cWebDragDropHelper.

Supported drag actions for this control are:
- C_WebDragListRow

Drop Support

This control can be used as a valid drop target by registering it as such in a cWebDragDropHelper object.

The supported drop actions for this control are:
- C_WebDropOnControl, C_WebDropListRow

File Drop Support

This allows the control to accept data dragged from elsewhere in the control (if configured that way) and can also be used to accept files when registered within a cWebDragDropFileHelper.

See Also

Styling Web Applications