cObject
---cWebObject
------cWebBaseUIObject
---------cWebBaseDEOServer
------------cWebBaseControl
---------------cWebList
------------------cWebGrid
------------------cWebHtmlList
------------------cWebMultiSelectList
------------------cWebPromptList
------------------cWebWidgetPalette
Web list controls provide the basis for creating multi-row, multi-column display. Each column in a list is represented by a column object. cWebList objects use the cWebColumn, cWebColumnButton, cWebColumnCheckbox, cWebColumnCombo, cWebColumnDate, cWebColumnImage and cWebColumnLink classes for its column objects.
Lists are ideal for displaying and browsing a list of data with support for searching, sorting and selecting of rows in the list.
A list can be used with or without a data binding. When used with a data binding, the list rows and columns are populated from the data provided by the list'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 need to support editing the list data, then you should use the cWebGrid control instead.
The cWebMultiSelectList class enhances the cWebList class with the ability to select entries from that list using either the mouse or keyboard.
If you need to show a list of data in a modal dialog, then return selected row information to the calling object, then you should use the cWebPromptList control, which has built-in support for these operations.
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).
List controls must be placed within a web container (e.g. cWebPanel, cWebView or cWebModalDialog).
List controls may not be nested inside other web controls. You may not mix web panels and web controls as sibling objects.
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 list control in a particular column of the parent container.
Set piColumnSpan to determine the width of the list 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 list control has a pre-determined minimum height according to the web application's CSS theme (psTheme). Set piHeight to set the list control to a fixed pixel height. You can also instruct a list 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.
pbAutoColumnSizing determines whether a list can scroll horizontally.
cWebContextMenu support is provided through the C_WebUIContextListRow Context, then the psContextValue
property will be filled with a comma separated list of Serialized RowIds.
cWeblist/cWebGrid supports two types of WebUIContext. See cWebContextMenu for usage information.
* C_WebUIContextListRow: Will show the menu when right-clicking in a row. psContextValue will contain the RowId, if any.
* C_WebUIContextListHead: Will show the menu when right-clicking in the cWebList header, the psCaption of the column headers. pbUseCustomHeaderMenu should be set to True for it to work as the default menu will be overwitten.
The ordering of the grid rows depends on how the data is served to the grid. This can be broken down into two categories: Data Aware Grids and Manually Loaded Grids.
List objects support datasets served by a data dictionary object structure. The list's Server property specifies the list's connection to a DDO. By default, the list's server data dictionary is delegated to the Main_DD setting of the host view or dialog.
When the list has a data server, then each list 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 automatically provides the control's data type, tooltip 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 list's psCurrentRowID property is set to the RowID of the list's currently selected row on the client. Use psCurrentRowID to retrieve the currently selected row.
The list 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 Lists" below.
If pbDataAware = True and peDbGridType <> gtManual, then the grid is "data-aware" and it is populated automatically by the attached Server DDO.
When working with data-aware lists, follow these guidelines for controlling index order:
1. Use piSortColumn to control index order
2. Always set an initial piSortColumn value
3. If you need to further control index order, augment the IndexOrder function
4. Do not set these properties:
See Indexes and Ordering with Data Aware cWebLists for a more complete description of this process.
This sample demonstrates a data aware list. A web view (cWebView) object contains a DataDictionary object (DDO) and a list (cWebList) whose rows and columns are populated automatically from the data dictionary.
Object oCustomers 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 cWebList 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 list 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 list to fill its rows with data from the customer table starting with the record found in the OnLoad event.
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.
Set pbDataAware to False or peDbGridType to gtManual if you want to populate a list object programmatically, i.e. without using DataDictionary objects or data-bound columns. In this case, you will need to implement the list'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 - aCells member is the array you will need to populate to represent the column values for each row. The 0th member of this array represents the leftmost column. The sRowId member is populated with a value that is unique for each row.
You must provide a unique RowId for each row in a manually loaded list, or numerous list features simply won't work or won't work right. When using a data-bound list, this is handled for you by the DataDictionary, with manual lists, it is the developer's responsibility to provide unique RowIds.
The OnManualLoadData event is not automatically fired. You will need to write code in your view to trigger it. Typically you would augment the list'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
Refer to the Sample section below for an example demonstrating how to manually populate a grid.
Once the grid data has been loaded and displayed on the client, you may need to make specific changes to some of its data. Use the DataSetAppendRow, DataSetInsertRowBefore, DataSetRemoveRow and DataSetUpdateRow helper methods to manipulate the data of a manually loaded grid.
When working with manually loaded lists, you may need access to the full set of list data. You can call ProcessDataSet to do so.
This sample demonstrates a list whose rows are 'manually' populated with data. We call this a non-data aware list, i.e. it is not connected to any data dictionary Server and its columns do not have any data binding.
Note that WebList Grouping is optional, so the grouping-related parameters of OnManualLoadData (aTheGroups ByRef tWebGroupHeader[][][] ByRef aTheGroupHeaders) are optional and can be omitted.
Use cWebView.pkg Use cWebPanel.pkg Use cWebForm.pkg Use cWebList.pkg Use cWebColumn.pkg Object oManualWebListView is a cWebView Set piWidth to 400 Set piHeight to 320 Set psCaption to "Planets List" // Your DDO structure will go here Object oWebMainPanel is a cWebPanel Set piColumnCount to 12 // place controls here. // Your view will grow as controls are added Object oPlanetsList is a cWebList Set pbFillHeight to True Set pbDataAware to False Object oPlanetColumn is a cWebColumn Set psCaption to "Planet" End_Object Object oDistanceColumn is a cWebColumn Set psCaption to "Distance from Sun" Set peAlign to alignRight Set peDataType to typeNumber Set psMask to "*.## AU" End_Object Procedure OnManualLoadData tWebRow[] ByRef aTheRows String ByRef sCurrentRowID aTheGroups ByRef tWebGroupHeader[][][] ByRef aTheGroupHeaders Integer iNum Forward Send OnManualLoadData (&aTheRows) (&sCurrentRowID) Move 0 to iNum Move iNum to aTheRows[iNum].sRowID Move "Planet" to aTheRows[iNum].sCssClassName Move "Mercury" to aTheRows[iNum].aCells[0].sValue Move (ConvertToClient(typeNumber, 0.387)) to aTheRows[iNum].aCells[1].sValue Increment iNum Move iNum to aTheRows[iNum].sRowID Move "Planet" to aTheRows[iNum].sCssClassName Move "Venus" to aTheRows[iNum].aCells[0].sValue Move (ConvertToClient(typeNumber, 0.722)) to aTheRows[iNum].aCells[1].sValue Increment iNum Move iNum to aTheRows[iNum].sRowID Move "Planet" to aTheRows[iNum].sCssClassName Move "Mars" to aTheRows[iNum].aCells[0].sValue Move (ConvertToClient(typeNumber, 1.52)) to aTheRows[iNum].aCells[1].sValue Increment iNum Move iNum to aTheRows[iNum].sRowID Move "Planet" to aTheRows[iNum].sCssClassName Move "Jupiter" to aTheRows[iNum].aCells[0].sValue Move (ConvertToClient(typeNumber, 5.2)) to aTheRows[iNum].aCells[1].sValue End_Procedure End_Object Procedure OnLoad Forward Send OnLoad Send GridRefresh to oPlanetsList End_Procedure End_Object End_Object
In this example, GridRefresh is sent during the cWebView object's OnLoad event. This means that just before the view is sent to the client, GridRefresh will be sent. Since pbDataAware is False, the GridRefresh will trigger the OnManualLoadData event where the logic for populating the row data is implemented.
Within OnManualLoadData: aTheRows is an array of tWebRow structs that is populated to give the grid its data. The sRowId member is populated with a value that is unique for each row. The actual data to display in the grid is stored in the aCells array member.
Special attention is needed when populating a column whose data type (peDataType) is typeNumber, typeDate or typeDateTime, to ensure the values are sent to the client in a standard format. This is performed by applying the ConvertToClient function to each value.
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.
For information about manually loading a data aware grid refer to the help section on Web Framework Lists & Grids.
The following code example shows how to implement simple manual grouping in a weblist. It will render a list with 5 rows divided into 2 groups, like this: -------------------------------------- Use the following interface to programmatically manipulate the currently selected row: The cWebList and cWebGrid classes allow for a configurable column layout, which includes moving and hiding columns. List objects support a search capability. If the list object has the focus then simply begin typing the row value you are looking for. This pops-up a search window where you can continue typing the value that you are searching for. The search value is used to locate the closest matching row according to the current sort order of list rows. By default, the list class does not send the OnChangeCurrentRow event to the server each time the currently selected row is changed. This is to optimize the performance of row selection in the cWebList class. 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. This control can be used as a valid drop target by registering it as such in a cWebDragDropHelper object. 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. The colors used by a list (or 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.
To enable manual grouping mode, set the peGrouping property to grpCustom. In this mode, the developer is responsible for determining the groups by filling structs in OnManualLoadData. This requires the list to be manually filled with data, so first peDbGridType to gtManual.
Then, inside OnManualLoadData, the developer needs to fill two additional arrays of structs with information on the groups. Together, these two will set the text in the group headers like this: "
Take the following steps to implement manual grouping.
STEP 1
Set peGrouping of the weblist to grpCustom. Also set peDbGridType to gtManual.
STEP 2
Define the groupings by manually filling the tWebGroupConfig struct array. This array defines the grouping in the weblist and is also (implicitely) used in automatic grouping. For manual grouping only the member sLabel needs to be set. This is the label that will be shown at each group header. The iColumnId and bReverse members can be ignored (these are only relevant for automatic grouping).
If you are grouping the data on two levels, you'll need to provide two labels in the aTheGroups arrays. This means that you will have to define two items in the array, like this:Move "Brand" to aTheGroups[0].sLabel
Move "Pricing category" to aTheGroups[1].sLabel
STEP 3
The second array that should be filled is the tWebGroupHeader struct array. This defines the values that will be shown in the group headers. The following struct members need to be set:
- Integer iGroupIndex: Set it to 0 for the first grouping level, 1 for the second grouping level, etc.
- Integer iParentHeaderIndex: Set it to -1 for the first grouping level, 0 for the second grouping level, etc.
- String sItem: Set it to the group value
When there should be multiple group headers above a line, then iParentHeaderIndex of tWebGroupHeader should be set.
With these two additional struct arrays the grouping is defined, but there is no data yet. This will be done in step 4.
STEP 4
The first parameter of the OnManualLoadData procedure is a tWebRow struct, which is where the weblist data should go.
The data can be manually filled like this:Move iRow to aTheRows[0].sRowId // iRow can start at 0 and increment for each row
Move "value_col1" to aTheRows[0].aCells[0].sValue
Move "value_col2" to aTheRows[0].aCells[1].sValue
Then, each FIRST row that should be grouped under a particular grouping header must be bound to an item from the just defined tWebGroupHeader struct array:Move 0 to aTheRows[0].iGroupHeaderIndex // Bind to group header
The other rows that follow under the same grouping header must have iGroupHeaderIndex set to -1, like this:Increment iRow
Move iRow to aTheRows[1].sRowId // iRow can start at 0 and increment for each row
Move "nextrowvalue_col1" to aTheRows[1].aCells[0].sValue
Move "nextrowvalue_col2" to aTheRows[1].aCells[1].sValue
Move -1 to aTheRows[1].iGroupHeaderIndex // Bind to group header
Sample
Object oCarsPerBrandList is a cWebList
Set pbFillHeight to True
Set peGrouping to grpCustom
Set pbDataAware to False
Object oCarColumn is a cWebColumn
Set psCaption to "Car"
Set piWidth to 50
End_Object
Procedure OnManualLoadData tWebRow[] ByRef aTheRows String ByRef sCurrentRowID tWebGroupConfig[] ByRef aTheGroups tWebGroupHeader[] ByRef aTheGroupHeaders
// Define that we have one level of grouping
Move "Brand" to aTheGroups[0].sLabel
// Group Mercedes
Move "Mercedes" to aTheGroupHeaders[0].sItem
Move 0 to aTheGroupHeaders[0].iGroupIndex
Move -1 to aTheGroupHeaders[0].iParentHeaderIndex
// Rows for group Mercedes
Move 0 to aTheRows[0].sRowId
Move "540K" to aTheRows[0].aCells[0].sValue
Move 0 to aTheRows[0].iGroupHeaderIndex // Bind to group header
Move 1 to aTheRows[1].sRowId
Move "300d" to aTheRows[1].aCells[0].sValue
Move -1 to aTheRows[1].iGroupHeaderIndex
Move 2 to aTheRows[2].sRowId
Move "230SL" to aTheRows[2].aCells[0].sValue
Move -1 to aTheRows[2].iGroupHeaderIndex
// Group BMW
Move "BMW" to aTheGroupHeaders[1].sItem
Move 0 to aTheGroupHeaders[1].iGroupIndex
Move -1 to aTheGroupHeaders[1].iParentHeaderIndex
// Rows for group BMW
Move 3 to aTheRows[3].sRowId
Move "Isetta" to aTheRows[3].aCells[0].sValue
Move 1 to aTheRows[3].iGroupHeaderIndex // Bind to group header
Move 2 to aTheRows[4].sRowId
Move "M3 E30" to aTheRows[4].aCells[0].sValue
Move -1 to aTheRows[4].iGroupHeaderIndex
End_Procedure
Procedure OnLoad
Send GridRefresh
End_Procedure
End_Object
Manual Grouping with Automatic Filling
Manual grouping does not require that filling of the weblist should also be done manually. The following code example shows how the rows can be filled from the database while manually creating grouping.Procedure OnManualLoadData tWebRow[] ByRef aTheRows String ByRef sCurrentRowID tWebGroupConfig[] ByRef aTheGroups tWebGroupHeader[] ByRef aTheGroupHeaders
Integer iRow iOrder iGroupHead
Move "Order" to aTheGroups[0].sLabel
Move -1 to iGroupHead
Clear OrderDetail
Find GT OrderDetail by 1
While (Found)
If (OrderDetail.Order_Number <> iOrder) Begin
Relate OrderDetail
Get LoadGridRow to aTheRows[iRow]
Move OrderDetail.Order_Number to iOrder
Increment iGroupHead
Move (SFormat("%1 (%2)", OrderHeader.Order_Number, Trim(Customer.Name))) to aTheGroupHeaders[iGroupHead].sItem
Move (SFormat("%1", FormatCurrency(OrderHeader.Order_Total, 2))) to aTheGroupHeaders[iGroupHead].sTotal
Move -1 to aTheGroupHeaders[iGroupHead].iParentHeaderIndex
Move 0 to aTheGroupHeaders[iGroupHead].iGroupIndex
Move iGroupHead to aTheRows[iRow].iGroupHeaderIndex
End
Else Begin
Get LoadGridRow to aTheRows[iRow]
End
Increment iRow
Find GT OrderDetail by 1
Loop
Clear OrderDetail
// Select the first row
If (SizeOfArray(aTheRows) > 0) ;
Move aTheRows[0].sRowId to sCurrentRowID
End_Procedure
Changing Rows
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.Configurable Column Layout
pbAllowColumnReordering determines whether columns can be reordered by dragging them to a different position. Dragging is done by picking up the column by its header.
pbAllowColumnHiding determines whether columns can be hidden. Hiding can be done using a context menu on the header or by dragging them outside of the grid.
pbStoreColumnLayout indicates whether the column layout is automatically stored locally on the client using local storage. When the application / view is loaded, it will check and automatically apply a stored layout.
ApplyColumnLayout applies a column layout.
ResetColumnLayout resets the column layout to the original design time layout.
OnColumnLayoutChanged is called when the user changes the layout (resizes / drags or hides a column).
pbHidden indicates whether a cWebList column is currently hidden or not.Searching
Set pbAutoSearch to false to disable the automatic search capability.
Send Search to programmatically pop-up the search dialog to initiate a search.OnChangeCurrentRow Event
Set pbOfflineEditing to true to enable OnChangeCurrentRow events.Drag and Drop Support
Drag Support
Supported drag actions for this control are:
- C_WebDragListRowDrop Support
The supported drop actions for this control are:
- C_WebDropOnControl, C_WebDropListRowFile Drop Support
Appearance
Set psCSSClass to the CSS class you would like to be applied to the overall list control.
Implement the OnDefineRowCssClass even to apply individual CSS styles to each row.
Each column class defines additional properties and events for applying special CSS styles to the column.