Web Framework 18.0

List & Grid Enhancements

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.

Extended tWebRow Structure

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.

Row, Column and Cell Styling

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.

New Column Types

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.

cWebColumnLink

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.

cWebColumnButton

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.

cWebColumnImage

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.

cWebColumnDate

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.

 

File Upload Control

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.

cWebFileUploadButton

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.

 

cWebFileUploadForm

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.

 

Drag & Drop

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.

 

Suggestion Form

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.

 

Group Control

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.

 

Custom Key Handlers

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.

 

Wait Dialogs & Action Modes

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.

 

Cookie API

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.

 

Error Handling

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 became client-actions

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!"

 

Field error API

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

 

Info Balloon

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.

 

Progress Bar

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.

 

 

 

 

See Also

What's New in DataFlex 2014 - 18.0