One of the most complicated controls within the framework are the List and Grid controls. In this new release they are extended and partly refactored to make them even more versatile.
A fundamental change in the framework is how controls can send complicated sets of data back and forth between the client and server. Controls now use their own structs allowing them to customize the data format to their needs. This means that the tWebRow struct is now specifically for the list & grid controls so they can be extended for its specific usage.
The old tWebRow struct format has proven to be too limiting and is now replaced with a new more versatile extendible format. More information is sent to the client for each row and cell specified in the new tWebRow and tWebCell structs.
Struct tWebCell
String sValue
String sTooltip
String[] aOptions
End_Struct
Struct tWebRow
String sRowID
String sCssClassName
tWebCell[] aCells
End_Struct
The code sample above shows the definition of the struct. Note that the tWebRow now has a separate member for the row ID. Also new is the possibility to assign a CSS class to each row in the grid. Then for each column there is now a tooltip member and an array of strings that allows special column types (like the new column types discussed below) to add in their data. The LoadGridRow function is now public and can be used to fill tWebRow structs for data aware and non data aware grids that are manually filled. For non data aware grids each column will have to implement OnSetCalculatedValue to provide its value.
Note that this means that existing applications that use manually filled lists / grids will have to be updated. We found that it is best to search for each .aValues usage within the application. Basically each usage of .aValues[0] can be replaced with .sRowID. Then all other usages of .aValues[…] should be replaced with .aValues[… - 1] where the -1 means that the index is now 0 based as we removed the rowid.
It is now possible to assign custom CSS classnames to individual rows. For this the OnDefineRowCssClass event can be implemented or the sCssClassname member of the tWebRow struct can be used. The psCssClass that is set on the column object is now also applied on every cell of that column (before it was just the edit cell). Combining these features means that every cell can be individually addressed within the CSS stylesheet.
Object oWebList1 is a cWebList
Object oCustomer_Balance is a cWebColumn
Entry_Item Customer.Balance
Set psCaption to "Balance"
Set piWidth to 50
Set psCSSClass to "DemoColumnBalance"
End_Object
Procedure OnDefineRowCssClass String ByRef sCSSClass
Forward Send OnDefineRowCssClass (&sCSSClass)
If (Customer.Balance < 1000) Begin
Move "DemoRowLow" to sCSSClass
End
Else If (Customer.Balance > 5000) Begin
Move "DemoRowHigh" to sCSSClass
End
Else Begin
Move "DemoRowMedium" to sCSSClass
End
End_Procedure
End_Object
The code example above assigns the custom “DemoColumnBalance” classname to the balance column. Then in OnDefineRowCssClass (executed for each row) it defines a special class based on the customer its balance (“DemoRowLow”, “DemoRowMedium” and “DemoRowHigh”).
#OWEBAPP .DemoRowLow .DemoColumnBalance{
background-color: red;
}
#OWEBAPP .DemoRowMedium .DemoColumnBalance{
background-color: orange;
}
#OWEBAPP .DemoRowHigh .DemoColumnBalance{
background-color: green;
}
The CSS code above is placed in the Application.css file and changes the background color of the balance column based on the CSS class that is applied to the row.
The list and grid has been extended with multiple new column types that allow it to be used in various new ways. The new pbShowSelected property allows the list to be used without a visually selected row making. Combining this with the new link or button column makes the list feel more like a HTML table.
This column type generates a link making the value of the column clickable. The value of the clicked column and the rowid of the clicked row are passed as parameters to the OnClick event that is triggered. In this OnClick event the develop can implement custom actions like drilling down to a details dialog or view.
Use this column to add buttons to the list or grid. By default a single button is shown but using the OnDefineButtons and AddButton API multiple buttons can be shown. The OnClick event gets the button name (for multiple buttons), rowid and column value as parameters when it is clicked.
The code sample below shows how multiple buttons can be added to a column by implementing the OnDefineButtons event on the column object. The AddButton procedure can be used add buttons for the current row. Note that the global buffer will contain the right record for this row in case of a data aware list.
Object oDynamicBtnCol is a cWebColumnButton
Set piWidth to 80
Set pbDynamic to True
Set pbRender to False
// Called for each row to define the buttons that need to be displayed.
Procedure OnDefineButtons
// Use AddButton to define a button (sID, sCaption, sCSSClass)
Send AddButton "E" "Edit" ""
// The Global buffer contains the right record for data aware lists
If (Customer.Status = "Y") Begin
Send AddButton "D" "Deactivate" ""
End
End_Procedure
Procedure OnClick String sButton String sRowId
Forward Send OnClick sButton sRowId
If (sButton = "E") Begin
Send ShowCustomer sRowId
End
Else If (sButton = "D") Begin
Send DeactivateCustomer sRowID
End
End_Procedure
End_Object
If a button is clicked the OnClick will be triggered with the ID of the button as a parameter indicating which button is clicked. This allows the developer to perform the right action.
Use this column show one or more images inside a list or grid column. The OnDefineImages and AddImage API can be used to for multiple images where it defaults to one image configured using the psImageUrl property.
The date picker column allows developers to use the cWebDateForm within the grid. It behaves like the regular cWebColumn but shows a prompt button that pops up the date picker.
Object oCustomerCreated is a cWebColumnDate
Entry_Item Customer.Created
Set psCaption to "Created"
Set piWidth to 10
End_Object
In the code sample above we see how the cWebColumnData class would be used. This code would be placed within a cWebList and works like any other column. The screenshot below shows the resulting date picker popup being available on this column.
The resource manager has been extended with the ability to handle file uploads. It works using the same principles as the file download system where a standardized upload ASP script comes with the framework and an abstract interface is available within DataFlex code. Two new controls are available that allow the developer to easily integrate file uploads into any WebApp. These controls provide two completely different user interfaces for file uploads. On modern browsers the controls feature drag & drop, multi file upload and a progress bar. On older browsers the controls fall back to the HTML4 file upload dropping these features.
The file upload button is a special button that shows the file selection dialog when clicked. Once files are selected it will start uploading the file(s).
The developer only has to provide the path where the files should be stored on the server by implementing the OnFileUpload event.
Object oFileUpload is a cWebFileUploadButton
Set piColumnSpan to 3
Set psCaption to "Upload File(s)"
Function OnFileUpload String sFileName Integer iBytes String sMime Returns String
String sPath
// Determine local path based on workspace setting
Get psDataPath of (phoWorkspace(ghoApplication)) to sPath
Move (sPath + "\Uploads\" + sFileName) to sPath
Function_Return sPath
End_Function
End_Object
A progress dialog will be shown that if browsers support this will even show the exact progress on a progress bar.
This control represents a single form that is displayed as a form. The prompt button will open the file selection dialog and allow the user to select a file.
Once the file is selected the control will start uploading the file (or wait until the DoStartFileUpload procedure is called). While uploading the control transforms into a progress bar showing the progress or a spinning wheel for older browsers.
After the upload is finished the control will display details of the uploaded file.
Modern browser support files to be dropped onto the browser window. The upload controls both support this and the drop zone is even configurable using the phoDropZone property. It defaults to the control itself but it can be set to panels, views or even the entire webapp to extend the dropzone.
A brand new control is now available that can be used to create search fields. It shows as a form and while typing suggestions are shown underneath the field in a floating container. The cWebSuggestionForm is a subclass of the regular cWebForm which means that it also inherits all of its features. The suggestion form is highly customizable supporting multiple columns and, incremental and full text search and multiple sources.
The logic for determining the suggestions shown in the list can be configured by setting the peSuggestionMode property. The default is smFind which searches for suggestions in the database table. It requires the field to be data aware. If pbFullText is set true it will perform a full text search which is optimized for SQL databases using the new data dictionary SQL filtering API. If peSuggestionMode is set to smValidationTable it will load the suggestions from the validation table making the control a good alternative for the cWebCombo that has too many options. Then if peSuggestionMode is set to smCustom the developer himself can provide the options by implementing the OnFindSuggestions event. Providing the suggestions is done by filling an array of tWebSuggestion structs.
Instead of having to use the card container to emulate a group control it can now be done with a single object using the cWebGroup class. This component is positioned as a control but can be used as a container to put controls in. It has a caption and a border (that can be hidden).
Object oCustomerContainer is a cWebGroup
Set psCaption to "All Customers:"
Set piColumnCount to 9
Set piColumnSpan to 5
Set Server to oCustomer_DD
Object oCustomer_Customer_Number is a cWebForm
Entry_Item Customer.Customer_Number
Set piColumnSpan to 0
Set psLabel to "Customer Number:"
Set peAlign to alignLeft
End_Object
// ....
End_Object
The example above shows how the group can be used. Not that it has both piColumnCount and piColumnSpan properties showing that it is both a control and a container.
It is now possible to assign custom key handlers to controls and containers. This is done by using the AddKeyHandler and RemoveKeyHandler procedures. These procedures are client actions and the administration of key handlers is kept on the client. This means these procedures should be used after the control is available on the client or when it is loaded to the client. Common practice will be to call these procedures during the OnLoad event.
The system relies on the HTML DOM Event bubbling system so key events inside controls can be handled on their wrapping containers. So a key handler on the view will catch key events on a form inside that view. If a key event is handled by a control or container it will stop bubbling and other handlers will not be triggered. This is also true for key handlers implemented in the client-side control. The default browser behavior will be canceled if possible.
The first parameter is the message handle of a published procedure that will be called when the key event occurs. The other parameters (iKeyCode, bShift, bAlt, and bCtrl) define which key event we’d like to handle and are passed back to the server when the key event occurs. JavaScript key codes need to be used to define which key we are handling. See http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes to learn these.
Procedure InfoKey Integer iKeyCode Boolean bShift Boolean bAlt Boolean bCtrl
Send ShowInfoBox "This is an information dialog!"
End_Procedure
WebPublishProcedure InfoKey
Procedure OnLoad
Send AddKeyHandler (RefProc(InfoKey)) 112 False False False
End_Procedure
The example above shows how to attach a procedure to the F1 key immediately when the application is loaded.
This advanced feature allows developers to configure a wait dialog for very server-action just as we know from the cWebButton combined with pbShowWaitDialog. Instead of adding properties for every server action a procedure is available that tells the JavaScript Engine to send an action in a specific mode. The SetActionMode procedure takes a message handle to the published procedure or function as a parameter.
Object oMenuItem is a cWebMenuItem
Set psCaption to "Long process"
Procedure OnLoad
Forward Send OnLoad
Send SetActionMode (RefProc(OnClick)) scModeProgress "Please wait while sleeping..."
End_Procedure
Procedure OnClick
// Do something long
Sleep 4
End_Procedure
End_Object
The example above shows how to show a wait dialog can be shown while processing the onclick of a menu item. Other action modes that are available are scModeWait which will lock the UI and show a wait cursor and scModeDefault which doesn’t lock the UI and doesn’t show a wait cursor.
When a server action triggers another server action (like ProcessDataSet on cWebList) then it will keep the wait dialog on the screen until the new server action is processed.
DataFlex functions are now available for reading and writing cookies. The GetCookie function reads a cookie key using its name directly from the HTTP Header. The SetCookie function can be used to update the cookie key by passing its name, value and expiration in hours. When the expiration time is set to 0 it will set the cookie as a session cookie. Note that SetCookie is implemented as a client-action which makes it asynchronous and GetCookie will not return the new value until the next call arrives.
Work has been done to improve the error handling of the framework. The error system is now more simplified making it better to control and more predictable.
Errors are now sent to the client as regular client-actions providing the advantage that they are executed in order with other client actions. So if an info box is shown before an error occurs it will also be displayed in that order. The example below demonstrates this with a user error.
Send ShowInfoBox "An error is about to happen!"
Send UserError "Something awful happened!"
The framework now allows field errors to be shown on non data bound fields using the ShowControlError and HideControlError procedure. Note that a WebSet of psValue and a successful OnValidate event clears all the errors. The HideAllControlErrors can be used to hide all errors as well. Combining this with the OnValidate event allows the developer to implement field validations that behave the same as on a data aware field.
Object oForm is a cWebForm
Set piColumnSpan to 6
Set psLabel to "5 characters:"
Set pbServerOnValidate to True
Function OnValidate Returns Boolean
Boolean bRetVal
String sVal
Forward Get OnValidate to bRetVal
WebGet psValue to sVal
If (Length(sVal) < 5) Begin
Move False to bRetVal
Send ShowControlError 1 "Please enter more than 5 characters!"
End
Function_Return bRetVal
End_Function
End_Object
The code example above shows how a custom validation can be implemented on a form. The screenshot below shows how the error is displayed when the user tabs out of the field
It is now possible to show information balloons next to a control using the ShowInfoBalloon procedure available on all controls. The HideInfoBalloon procedure can be used to hide the balloon. The balloon will be visible for a few seconds and show up again when the control is hovered with the mouse.
Object oWebButton1 is a cWebButton
Set piColumnSpan to 1
Set psCaption to "?"
Procedure OnClick
Send ShowInfoBalloon "" "Hello Users!<br><br>Clicking this button showed this balloon!"
End_Procedure
End_Object
The example above shows how to show an info box at a simple button resulting in the image below. Note that HTML can be used as the content of the balloon.
The framework now features a progress bar that can be used as a control within panels, views and dialogs. The cWebProgressBar class has piValue and piMaxValue web properties that control the current state. A Progress procedure is available that increments the value.
Object oWebProgressBar1 is a cWebProgressBar
Set psLabel to "cWebProgressBar:"
Set pbShowLabel to True
Set piValue to 33
Set piColumnSpan to 6
End_Object
Note that the progress bar is one of the controls where the label is disabled by default and can be enabled using pbShowLabel.
What's New in DataFlex 2014 - 18.0