Skip to content

Visual Report Writer and The Web (I)

At the recently concluded Synergy 2013 conference held in Nashville, Tennessee, we demonstrated how easy it is to create Web-Based Applications using the DataFlex Web Application Framework. Reporting is a crucial part of a Web Application, and Data Access recommends two reporting solutions: Dynamic AI and Visual Report Writer. During the Synergy sessions (symposium and training), we showcased how relatively easy it is to integrate these two reporting solutions into a Web Application built with the DataFlex Web Application Framework. To illustrate this, we created two demonstration websites that showcase the capabilities of Dynamic AI and Visual Report Writer in real-time. You can experience the speed and output solutions, and in this blog and the following ones, I will explain what is behind the website and how it is constructed.

Before continuing with this blog, I recommend visiting the demonstration websites. You can explore the Dynamic AI demo website to experience its power. Additionally, you can access the Visual Report Writer websites hosted on either a USA-based server or a European-based server.

The Start Page

The links provided above lead to a start page named "The Solution." Accessing this page is controlled by setting the phoDefaultView property to this cWebView object. This page is a cWebView class-based component containing two cWebPanel objects. The left panel has a fixed width and can be resized by the visitor using the splitter between the two panels. The splitter is enabled by setting the pbResizable property of the left panel to true. The right panel does not have a fixed width; its size is determined by the browser size. The left panel contains a treeview control (cWebTreeView) for navigation purposes. The contents are read from a DataFlex embedded database table, allowing us to modify the contents without recompiling the application. The first level of the tree is automatically expanded. Clicking on a node sends a find request to the server, resulting in the documentation text being displayed in the right panel, which contains a cWebHTMLBox control. The text is stored as HTML in a TEXT-based column in the documentation table and includes special instructions that allow the server to open an integration web view when the user clicks on a link.

While the Dynamic AI and Visual Report Writer demo websites are similar, they are not identical, as they represent two different reporting solutions. The next part of this blog and the subsequent blogs will focus on what you see on the Visual Report Writer live demo website.

Now, let's examine some code used to populate the page.

In the OnLoad event of the cWebTreeView control, the data is loaded automatically, and the event sends a message OnLoadChildNodes to retrieve its data. In the treeview coded here, the data is read from a table named Documentation. The code for this is:

Function OnLoadChildNodes String sId String sValue Integer iLevel Returns tWebTreeItem[]
    tWebTreeItem[] TreeItems

    Get CollectTreeData sId to TreeItems

    Function_Return TreeItems
End_Function

Function AppendTreeData tWebTreeItem[] ByRef DestinationTreeItems tWebTreeItem[] ByRef SourceTreeItems Returns Integer
    Integer iElements iElement iDestinationElement

    Move (SizeOfArray (DestinationTreeItems)) to iDestinationElement
    Move (SizeOfArray (SourceTreeItems)) to iElements
    For iElement from 0 to (iElements - 1)
        Move SourceTreeItems[iElement] to DestinationTreeItems[iDestinationElement]
        Increment iDestinationElement
    Loop

    Function_Return iElements
End_Function

Function CollectTreeData String sId Returns tWebTreeItem[]
    tWebTreeItem[] TreeItems ChildTreeItems
    Integer iElement iAddedItems iSet
    RowID riDocumentation

    Move (sId + 1) to iSet
    Constraint_Set iSet Clear
    Constrain Documentation.ParentID eq sId
    Constrained_Find First Documentation by 1
    While (Found)
        Move Documentation.ID to TreeItems[iElement].sId
        Move Documentation.ParentID to TreeItems[iElement].sParentId
        Move (Trim (Documentation.Name)) to TreeItems[iElement].sName
        Move Documentation.LoadChildren to TreeItems[iElement].bLoadChildren
        Move Documentation.Folder to TreeItems[iElement].bFolder
        Move Documentation.Expanded to TreeItems[iElement].bExpanded
        Move Documentation.Icon to TreeItems[iElement].sIcon
        Move (Trim (Documentation.CSSClass)) to TreeItems[iElement].sCSSClass
        Move (Trim (Documentation.AltText)) to TreeItems[iElement].sAltText
        Increment iElement
        If (Documentation.Expanded) Begin
            Move (GetRowID (Documentation.File_Number)) to riDocumentation
            Get CollectTreeData Documentation.ID to ChildTreeItems
            Get AppendTreeData (&TreeItems) (&ChildTreeItems) to iAddedItems
            Move (iElement + iAddedItems) to iElement
            Move (FindByRowID (Documentation.File_Number, riDocumentation)) to Found
        End
        Constraint_Set iSet
        Constrained_Find Next
    Loop

    Constraint_Set iSet Delete

    Function_Return TreeItems
End_Function

The OnLoadChildNodes event sends a message to read the data from the table. If none of the rows has the Expanded column set to true, the routine will only load the data at the first level, requiring the user to expand each tree item.

To ensure the first item is selected, the OnLoad event is enhanced to select the item corresponding to the first row in the table.

Procedure OnLoad
    Forward Send OnLoad

    Clear Documentation
    Find Gt Documentation by 1
    Send Select Documentation.ID
End_Procedure

The table layout is simple yet complex, as it uses a self-referential relationship through an ALIAS table and allows NULL parent support. The table structure is:

NUM  FIELD NAME       TYPE SIZE  OFFST IX
---  ---------------  ---- ----- ----- --
  1  ID               NUM    4.0     1  1
  2  ParentID         NUM    4.0     3   
  3  Name             ASC    255     5   
  4  LoadChildren     NUM    2.0   260   
  5  Folder           NUM    2.0   261   
  6  Icon             ASC    255   262   
  7  CSSClass         ASC    100   517   
  8  AltText          ASC    150   617   
  9  Value            TEX  14752   767   
 10  Expanded         NUM    2.0 15519   
 11  ViewName         ASC    250 15520  2

The column ParentID links to the ALIAS table for Documentation from within the DataDictionary object used when entering or altering the documentation. As noted, the DataDictionary object is not utilized for reading data into the treeview. While it could have been used, there is no necessity for it. The DataDictionary class used for DDOs when entering documentation is as follows:

Use DataDict.pkg
Open Documentation
Open DocumentationParent

Register_Object oDocumentationWebLookup

Class cDocumentationDataDictionary is a DataDictionary    
    Procedure Construct_Object
        Forward Send Construct_Object

        Set Main_File to Documentation.File_Number
        Set Add_Server_File to DocumentationParent.File_Number
        Set ParentNullAllowed DocumentationParent.File_Number to True

        Set Foreign_Field_Option DD_KEYFIELD DD_NOPUT to True
        Set Foreign_Field_Option DD_KEYFIELD DD_FINDREQ to True
        Set Foreign_Field_Option DD_INDEXFIELD DD_NOPUT to True
        Set Foreign_Field_Option DD_DEFAULT DD_DISPLAYONLY to True

        Set Field_WebPrompt_Object Field Documentation.ID to oDocumentationWebLookup
        Set Field_Option Field Documentation.ID DD_AUTOFIND to True
        Set Field_Class_Name Field Documentation.LoadChildren to "Checkbox"
        Set Field_Class_Name Field Documentation.Folder to "Checkbox"

        Set pbUseDDRelates to True
        Set Field_Related_FileField Field Documentation.ParentID to File_Field DocumentationParent.ID
    End_Procedure
End_Class

#IFDEF Is$WebApp
Use Lookups\DocumentationWebLookup.wo
#ELSE
#ENDIF

Clicking a node in the treeview sends the OnSelect event to the server. In the OnSelect, the row linked to the tree item is found, and its documentation data is sent to the cWebHtmlBox control via an UpdateHtml message.

Procedure OnSelect String sId String sValue Integer iLevel
    Forward Send OnSelect sId sValue iLevel

    Clear Documentation
    Move sId to Documentation.ID
    Find Eq Documentation.ID

    Move (Trim (Documentation.Value)) to sValue

    If (sValue = "") Begin
        Move " " to sValue
    End

    Send UpdateHtml of oWebDocumentationBox sValue
End_Procedure

The right panel contains a cWebHTMLBox object used to display the contents.

Object oExplanationPanel is a cWebPanel
    Object oWebDocumentationBox is a cWebHtmlBox
        Set psHtmlId to "SolutionText"
        Set pbServerOnClick to True
        Set pbFillHeight to True

        Procedure OnClick String sId String sParam
            Handle hoView

            Case Begin
                Case (sId = "openview")
                    Get WebObjectByName sParam to hoView
                    Send Show of hoView
                    Case Break
                Case (sId = "navigate")
                    Send NavigateToPage of oWebApp sParam btNewTab
                    Case Break
            Case End
        End_Procedure
    End_Object
End_Object

Notably, in the oWebDocumentationBox object, the psHtmlId setting and the OnClick event implementation are significant. The psHtmlId is set to allow web designers to style the content of the HTML text stored in the Documentation table. The OnClick event is triggered when the user clicks an anchor element in the HTML text that contains a data-serveronclick attribute. Refer to the documentation for this setting within the DataFlex Web Application Framework documentation.

Finally, this solution page includes two buttons below the treeview that direct the user to the websites for Visual Report Writer and Visual DataFlex.