Conference App: complete the application¶
Add Rooms, Presentations, and Settings to the client documented in Synchronize presenters. This phase adds the missing data dictionaries and views, then expands the existing application, database, dashboard, and Presenter behavior.
Before you begin: Complete Synchronize presenters. Keep all files from that page. This is the phase that changes the local database filename to /dev/idbfs/ConferenceDataV10.db and introduces version-aware synchronization.
Step 1 — Add Room, Presentation, and Settings data¶
Add these files before adding views or changing synchronization. All three entities use the same { Connection=conf_data } logical connection ID, so their Data Dictionaries use the SQLite driver already registered by the template. Entities define the persistent models; Relations and Constraints explains how Presentation relates Room and Presenter. Settings stores DataVersion and LastSync as name/value records.
AppSrc/RoomDataDictionary.pkg¶
Room is the parent entity for room selection and Presentation navigation. Its required Name and indexes supply the room list used by later views.
Use Db\cDataDictionary.pkg
{ Connection=conf_data}
Entity Room
{ PrimaryKey=True AutoIncrement=True }
Integer RoomId
String Name
String Description
String Directions
Integer Capacity
Add_Index RoomId ASC
Add_Index Name ASC
End_Entity
{ Entity=Room }
Class cRoomDataDictionary is a cDataDictionary
Procedure Construct_Object
Forward Send Construct_Object
Set phEntity to (RefEntity(Room))
Set Field_Option (RefTable(Self.Name)) DD_Required to True
End_Procedure
End_Class
AppSrc/PresentationDataDictionary.pkg¶
Presentation references both Room and Presenter through its relations, so its Data Dictionary can bind parent DDOs and validate required title, room, date, and time fields.
Use Db\cDataDictionary.pkg
Use RoomDataDictionary.pkg
Use PresenterDataDictionary.pkg
{ Connection=conf_data }
Entity Presentation
{ PrimaryKey=True AutoIncrement=True }
Integer PresentationId
Integer RoomId
Integer PresenterId
String Title
String Description
Date Date
Time StartTime
Time EndTime
String Level
Integer MaxAttendees
Add_Index PresentationId ASC
Add_Index RoomId ASC PresentationId ASC
Add_Index Date ASC StartTime ASC Title ASC
Add_Index Title ASC
Add_Relation RoomId to Room.RoomId
Add_Relation PresenterId to Presenter.PresenterId
End_Entity
{ Entity=Presentation }
Class cPresentationDataDictionary is a cDataDictionary
Procedure Construct_Object
Forward Send Construct_Object
Set phEntity to (RefEntity(Presentation))
Set Field_Option (RefTable(Self.Title)) DD_Required to True
Set Field_Option (RefTable(Self.RoomId)) DD_Required to True
Set Field_Option (RefTable(Self.Date)) DD_Required to True
Set Field_Option (RefTable(Self.StartTime)) DD_Required to True
Set Field_Option (RefTable(Self.EndTime)) DD_Required to True
End_Procedure
End_Class
AppSrc/SettingsDataDictionary.pkg¶
Settings stores named values. The complete synchronization package uses DataVersion to compare local and remote data and LastSync to display the latest successful synchronization time.
Use Db\cDataDictionary.pkg
{ Connection=conf_data }
Entity Settings
{ PrimaryKey=True }
String Name
String Value
Add_Index Name ASC
End_Entity
{ Entity=Settings }
Class cSettingsDataDictionary is a cDataDictionary
Procedure Construct_Object
Forward Send Construct_Object
Set phEntity to (RefEntity(Settings))
Set Field_Option (RefTable(Self.Name)) DD_Required to True
End_Procedure
Function LoadSetting String sSetting String sDefault Returns String
Move sSetting to Self.Name
Send FindByField EQ (RefTable(Self.Name))
If (Found) ;
Function_Return Self.Value
Else ;
Function_Return sDefault
End_Function
Procedure StoreSetting String sSetting String sValue
Move sSetting to Self.Name
Send FindByField EQ (RefTable(Self.Name))
If (not(Found)) Begin
Send Clear
Move sSetting to Self.Name
End
Move sValue to Self.Value
Send Request_Save
End_Procedure
End_Class
Step 2 — Add Room and Presentation drill-down views¶
Add each complete file in this phase. Select views bind their list DDOs and register zoom navigation; Data Binding explains these local-buffer bindings, while Relations and Constraints covers the Room and Presenter parent DDOs used by Presentation views. Set Main_DD identifies the DDO that owns the current record, Set Server supplies records to data-aware controls, and each Entry_Item line binds a concrete DDO field to a control.
AppSrc/SelectRoom.wo¶
The Room list binds Main_DD and Server to oRoomDD, then forwards a selected row to oZoomRoom. Its Entry_Item oRoomDD.Name column reads the current Room DDO buffer; the list does not access SQLite or a global file buffer directly.
Use WebUI\cWebView.pkg
Use WebUI\cWebPanel.pkg
Use WebUI\cWebButton.pkg
Use WebUI\cWebList.pkg
Use WebUI\cWebColumn.pkg
Use WebUI\cWebMenuGroup.pkg
Use WebUI\cWebMenuItem.pkg
Use WebUI\cWebForm.pkg
Use WebUI\cWebColumnButton.pkg
Use RoomDataDictionary.pkg
Object oSelectRoom is a cWebView
// Your DDO structure will go here
Object oRoomDD is a cRoomDataDictionary
End_Object
Set Main_DD to oRoomDD
Set Server to oRoomDD
Set peWebViewStyle to wvsDrillDown
Set peViewType to vtSelect
Set psCaption to "Rooms"
Set piMaxWidth to 1024
Set piColumnCount to 6
Set pbShowCaption to False
Set psStateViewName to "Rooms"
WebSetResponsive piColumnCount rmTabletPortrait to 3
Object oList is a cWebList
Set pbFillHeight to True
Set piColumnSpan to 0
Set pbServerOnRowClick to True
Set psCSSClass to "MobileList"
Set piSortColumn to 0 // set this to allow for searching
Set pbShowHeader to False
WebRegisterPath ntNavigateForward oSelectPresentation
// place web column controls controls here.
Object oRoomDD_Name is a cWebColumn
Set psCaption to "Name"
Set psCSSClass to "RowCaption"
Set peAlign to alignLeft
Entry_Item oRoomDD.Name
End_Object
// sample of a right-aligned info column button
Object oDetailButton is a cWebColumnButton
Set piWidth to 45
Set pbFixedWidth to True
Set psCaption to "btn"
Set pbResizable to False
Set psBtnCssClass to "WebButtonIcon WebIcon_Info"
Set peAlign to alignRight
Set piListRowSpan to 2
WebRegisterPath ntNavigateForward oZoomRoom
Procedure OnClick
Send NavigatePath
End_Procedure
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
Move True to NavigateData.bReadOnly
End_Procedure
End_Object
Object oRoomDD_Description is a cWebColumn
Set psCaption to "Description"
Set pbNewLine to True
Set psCSSClass to "RowDetail"
Entry_Item oRoomDD.Description
End_Object
// What to do when the row is selected.
//
// Depending on how you are using this view, you may wish to
// 1. Close the view, which will update the invoking view:
// Send NavigateClose Self
// 2. Navigate forward to another view (either a from-main Zoom or a from-parent select):
// Send NavigateForward of oZoomMainView Self
// Send NavigateForward of oSelectChildView Self
// Note: Do not forget to register the forward navigation paths using WebRegisterPath
Procedure OnRowClick String sRowID
// If this view is being used in multiple contexts, you may need a block of code
// like this to handle different types of navigation
tWebNavigateData NavigateData
Get GetNavigateData to NavigateData
Case Begin
Case (NavigateData.eNavigateType=nfFromParent)
Send NavigatePath
Case Break
Case (NavigateData.eNavigateType=nfFromChild)
// If from child, this is a probably a parent lookup from a Zoom,
// so you just want to close (See 1 above)
Send NavigateClose Self
Case Break
Case (NavigateData.eNavigateType=nfFromMain)
// If from main, this is a propbably a main file lookup from a Zoom,
// so you just want to close (see 1 above).
// This is not used often with the drilldown style
Send NavigateClose Self
Case Break
Case Else // must be nfUndefined
Send NavigatePath
Case End
End_Procedure
// this makes the zoom view read-only or new or some other customization
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
End_Procedure
End_Object
// add action menu items here
Object oActionGroup is a cWebMenuGroup
Set psGroupName to "MainActions"
Object oSearch is a cWebMenuItem
Set psCaption to C_$Search
Set psCSSClass to "WebPromptMenuItem"
Procedure OnClick
Send Search of oList
End_Procedure
End_Object
Object oNewButton is a cWebMenuItem
Set psCaption to C_$New
Set psCSSClass to "WebClearMenuItem"
WebRegisterPath ntNavigateForward oZoomRoom
Procedure OnClick
Send NavigatePath
End_Procedure
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
Move True to NavigateData.bNewRecord
End_Procedure
End_Object
// // Sample Change sort order button
// Object oSearchOrderNumber is a cWebMenuItem
// Set psCaption to "View by ????"
// Set peActionDisplay to adMenu
//
// Procedure OnClick
// Integer eType
// WebSet piSortColumn of oList to 0 // set a column number
// Send GridRefresh of oList
// End_Procedure
//
// End_Object
// Sample top/bottom button
Object oFindTop is a cWebMenuItem
Set psCaption to C_$Top
Set peActionDisplay to adMenu
Set pbBeginGroup to True
Procedure OnClick
Send MoveToFirstRow of oList
End_Procedure
End_Object
Object oFindLast is a cWebMenuItem
Set psCaption to C_$Bottom
Set peActionDisplay to adMenu
Set pbServerOnClick to True
Procedure OnClick
Send MoveToLastRow of oList
Send NavigatePath
End_Procedure
End_Object
End_Object
// Add code to customize your Select View based on how it was invoked.
// Use NavigateData to determine the context this view will be used in.
Procedure OnNavigateForward tWebNavigateData NavigateData Integer hoInvokingView Integer hoInvokingObject
// if this view is being used in multiple contexts, you may need a block of code
// like this to handle customizations. This would include hiding rows and buttons
// (WebSet pbRender) and changing the values of various captions.
Case Begin
Case (NavigateData.eNavigateType=nfFromParent)
// If from parent, this is a constrained drill down.
// If needed you could check NavigateData.iTable to determine the constraining parent.
Case Break
Case (NavigateData.eNavigateType=nfFromChild)
// If from child, this is a probably a parent lookup from a Zoom
Case Break
Case (NavigateData.eNavigateType=nfFromMain)
// If from main, this is a propbably a main file lookup from a Zoom.
// This is not used often with the drilldown style
Case Break
Case Else // must be nfUndefined
// This may be the start of a drilldown query or some kind ofcustom query.
// You may want to check NavigateData.NamedValues.
Case End
End_Procedure
End_Object
AppSrc/ZoomRoom.wo¶
The Room zoom binds editable room fields to oRoomDD and provides save, edit, delete, and cancel actions. Each Entry_Item line binds one oRoomDD field to a control; Data Dictionary actions validate and persist that DDO buffer through the configured SQLite driver.
Use WebUI\cWebView.pkg
Use WebUI\cWebPanel.pkg
Use WebUI\cWebForm.pkg
Use WebUI\cWebGroup.pkg
Use WebUI\cWebMenuGroup.pkg
Use WebUI\cWebMenuItem.pkg
Use WebUI\cWebEdit.pkg
Object oZoomRoom is a cWebView
// Your DDO structure will go here
Object oRoomDD is a cRoomDataDictionary
End_Object
Set Main_DD to oRoomDD
Set Server to oRoomDD
Set peWebViewStyle to wvsDrillDown
Set peViewType to vtZoom
Set pbShowCaption to False
Set Verify_Save_msg to 0 // don't confirm saves
Set psCaption to "ZoomRoom"
Set piMaxWidth to 1024
Set piColumnCount to 12
Object oWebMainPanel is a cWebPanel
Set piColumnCount to 12
Object oRoomDD_Name is a cWebForm
Set piColumnSpan to 0
Set psLabel to "Name"
Entry_Item oRoomDD.Name
End_Object
Object oRoomDD_Description is a cWebForm
Set piColumnSpan to 0
Set psLabel to "Description"
Entry_Item oRoomDD.Description
End_Object
Object oRoomDD_Directions is a cWebEdit
Set piColumnSpan to 0
Set psLabel to "Directions"
Entry_Item oRoomDD.Directions
End_Object
WebSetResponsive piColumnCount rmMobile to 6
// place controls here
// Your view will grow as controls are added
// This shows how using groups can be an effective to create a responsive view.
End_Object
// add action menu items here
// we've included some common buttons
Object oActionGroup is a cWebMenuGroup
Set psGroupName to "MainActions"
Object oSaveBtn is a cWebMenuItem
Set psCaption to C_$Save
Set psCSSClass to "WebSaveMenuItem"
Procedure OnClick
Send Request_Save
End_Procedure
End_Object
Object oEditBtn is a cWebMenuItem
Set psCaption to C_$CategoryEdit
Set psCSSClass to "WebEditMenuItem"
Procedure OnClick
Send ChangeEditMode True
Send SetActionButtons
End_Procedure
End_Object
Object oDeleteBtn is a cWebMenuItem
Set psCaption to C_$Delete
Set psCSSClass to "WebDeleteMenuItem"
Set peActionDisplay to adMenu
Procedure OnClick
Send Request_Delete
End_Procedure
End_Object
Object oCancelChangesBtn is a cWebMenuItem
Set psCaption to C_$ToolTipClear
Set peActionDisplay to adMenu
Procedure OnClick
// this will undo any unchanged saves and show the latest
Send RefreshRecord
End_Procedure
End_Object
End_Object
// This can be used to show and hide buttons based on context.
// This can be called any time the view is active.
Procedure SetActionButtons
tWebNavigateData NavigateData
Boolean bHasRecord
Handle hoDD
Get Server to hoDD
Get GetNavigateData to NavigateData
If (hoDD) Begin
Get HasRecord of hoDD to bHasRecord
End
Else Begin
Move False to bHasRecord
End
// let's hide all buttons and then show the ones we want
WebSet pbRender of oEditBtn to False
WebSet pbRender of oSaveBtn to False
WebSet pbRender of oCancelChangesBtn to False
WebSet pbRender of oDeleteBtn to False
If (NavigateData.bReadOnly) Begin
WebSet pbRender of oEditBtn to True
End
Else Begin
WebSet pbRender of oSaveBtn to True
WebSet pbRender of oCancelChangesBtn to True
WebSet pbRender of oDeleteBtn to bHasRecord
End
End_Procedure
// this will close the view after a save
Procedure OnViewSaved Handle hoServer Boolean bChanged
Send NavigateClose Self
End_Procedure
// this will close the view after a delete
Procedure OnViewDeleted Handle hoDDO
Send NavigateClose Self
End_Procedure
// Add code to customize your Zoom View based on how it was invoked.
// Use NavigateData to determine the context this view will be used in.
Procedure OnNavigateForward tWebNavigateData NavigateData Integer hoInvokingView Integer hoInvokingObject
// if this view is being used in multiple contexts, you may need a block of code
// like this to handle customizations. This would include hiding rows and buttons
// (WebSet pbRender) and changing the values of various captions.
Case Begin
Case (NavigateData.eNavigateType = nfFromMain)
// If from main, this is a probably a main file Select to Zoom.
// This is the most typical way to navigate to a zoom.
Case Break
Case (NavigateData.eNavigateType = nfFromParent)
// If from parent, this is a constrained drill down.
// If needed, you could check NavigateData.iTable to determine the constraining parent.
// This would be unusual - normally you drill down from a parent to a list (Select view).
Case Break
Case (NavigateData.eNavigateType = nfFromChild)
// If from child, this is a probably a parent Zoom from a Zoom.
// This is unusual, but it might be used for adding a new child record.
Case Break
Case Else // must be nfUndefined
// This may be the start of a query or this may be used for some kind of custom operation.
// You may want to check NavigateData.NamedValues.
Case End
// Action buttons can be changed dynamically during a Zoom's display lifetime.
// It's best to set these buttons in their own procedure so you can change later.
Send SetActionButtons
End_Procedure
End_Object
AppSrc/SelectPresentation.wo¶
The Presentation list uses oPresentationDD as its main/server DDO and adds oRoomDD and oPresenterDD as related DDOs. Its row navigation reaches oZoomPresentation. Direct Entry_Item oPresentationDD.Title and Entry_Item oRoomDD.Name bindings read fields from those DDOs.
The presenter column shows the expression form of Entry_Item: Entry_Item @SQL"CONCAT(Presenter.FirstName, ' ', Presenter.LastName)" from oPresenterDD. This is not a standalone SELECT statement and does not bind to a nonexistent combined field. It sends a native expression for the oPresenterDD source to the backend, where the configured SQLite adapter evaluates it as a display-only value; native-expression syntax is backend-specific. See Data Binding for the distinction between DD-field and expression bindings.
Use WebUI\cWebView.pkg
Use WebUI\cWebPanel.pkg
Use WebUI\cWebButton.pkg
Use WebUI\cWebList.pkg
Use WebUI\cWebColumn.pkg
Use WebUI\cWebMenuGroup.pkg
Use WebUI\cWebMenuItem.pkg
Use WebUI\cWebForm.pkg
Use WebUI\cWebColumnButton.pkg
Use WebUI\cWebColumnHighlight.pkg
Use PresentationDataDictionary.pkg
Use RoomDataDictionary.pkg
Use PresenterDataDictionary.pkg
Object oSelectPresentation is a cWebView
Object oPresenterDD is a cPresenterDataDictionary
End_Object
Object oRoomDD is a cRoomDataDictionary
End_Object
Object oPresentationDD is a cPresentationDataDictionary
Set DDO_Server to oPresenterDD
Set DDO_Server to oRoomDD
End_Object
Set Main_DD to oPresentationDD
Set Server to oPresentationDD
Set peWebViewStyle to wvsDrillDown
Set peViewType to vtSelect
Set psCaption to "Presentations"
Set piMaxWidth to 1024
Set piColumnCount to 6
Set pbShowCaption to False
Set psStateViewName to "Presentations"
WebSetResponsive piColumnCount rmTabletPortrait to 3
Object oList is a cWebList
Set pbFillHeight to True
Set piColumnSpan to 0
Set pbServerOnRowClick to True
Set psCSSClass to "MobileList"
Set pbShowHeader to False
Set peGrouping to grpAutomatic
Set peDbGridType to gtAllData
Object oPresentationDD_Title is a cWebColumnHighlight
Set psCaption to "Title"
Set psCSSClass to "RowCaption"
Set peAlign to alignLeft
Set piListColSpan to 4
Entry_Item oPresentationDD.Title
End_Object
Object oDetailButton is a cWebColumnButton
Set piWidth to 45
Set pbFixedWidth to True
Set psCaption to "btn"
Set pbResizable to False
Set psBtnCssClass to "WebButtonIcon WebIcon_Info"
Set peAlign to alignRight
Set piListRowSpan to 3
WebRegisterPath ntNavigateForward oZoomPresentation
Procedure OnClick
Send NavigatePath
End_Procedure
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
Move True to NavigateData.bReadOnly
End_Procedure
End_Object
Object oPresenterDD_Name is a cWebColumn
Set psCaption to "Presenter"
Entry_Item @SQL"CONCAT(Presenter.FirstName, ' ', Presenter.LastName)" from oPresenterDD
Set pbNewLine to True
Set piListColSpan to 4
End_Object
Object oPresentationDD_Date is a cWebColumn
Set psCaption to "Day"
Set pbNewLine to True
Set psCSSClass to "RowDetail"
Entry_Item oPresentationDD.Date
Set psMask to "Ddd d Mmmm yyyy"
Set pbFixedWidth to True
Set piWidth to 120
End_Object
Object oPresentationDD_StartTime is a cWebColumn
Set psCaption to "Start"
Set psCSSClass to "RowDetail"
Entry_Item oPresentationDD.StartTime
Set pbFixedWidth to True
Set piWidth to 80
End_Object
Object oPresentationDD_EndTime is a cWebColumn
Set psCaption to "End"
Set psCSSClass to "RowDetail"
Entry_Item oPresentationDD.EndTime
Set pbFixedWidth to True
Set piWidth to 80
End_Object
Object oRoom_Name is a cWebColumn
Set psCaption to "Room"
Set psCSSClass to "RowDetail"
Entry_Item oRoomDD.Name
End_Object
WebRegisterPath ntNavigateForward oZoomPresentation
Procedure OnRowClick String sRowID
tWebNavigateData NavigateData
Get GetNavigateData to NavigateData
Case Begin
Case (NavigateData.eNavigateType=nfFromParent)
Send NavigatePath
Case Break
Case (NavigateData.eNavigateType=nfFromChild)
Send NavigateClose Self
Case Break
Case (NavigateData.eNavigateType=nfFromMain)
Send NavigateClose Self
Case Break
Case Else // must be nfUndefined
Send NavigatePath
Case End
End_Procedure
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
End_Procedure
Procedure OnLoad
tWebGroupConfig[] aGroups
Get piColumnId of oPresentationDD_Date to aGroups[0].iColumnId
Get psCaption of oPresentationDD_Date to aGroups[0].sLabel
Move False to aGroups[0].bReverse
Send ApplyGroupConfig aGroups True
End_Procedure
Set piSortColumn to (piColumnId(oPresentationDD_StartTime))
End_Object
Object oActionGroup is a cWebMenuGroup
Set psGroupName to "MainActions"
Object oSearch is a cWebMenuItem
Set psCaption to C_$Search
Set psCSSClass to "WebPromptMenuItem"
Procedure OnClick
Send Search of oList
End_Procedure
End_Object
Object oNewButton is a cWebMenuItem
Set psCaption to C_$New
Set psCSSClass to "WebClearMenuItem"
WebRegisterPath ntNavigateForward oZoomPresentation
Procedure OnClick
Send NavigatePath
End_Procedure
Procedure OnGetNavigateForwardData tWebNavigateData ByRef NavigateData Handle hoToView
Move True to NavigateData.bNewRecord
End_Procedure
End_Object
Object oFindTop is a cWebMenuItem
Set psCaption to C_$Top
Set peActionDisplay to adMenu
Set pbBeginGroup to True
Procedure OnClick
Send MoveToFirstRow of oList
End_Procedure
End_Object
Object oFindLast is a cWebMenuItem
Set psCaption to C_$Bottom
Set peActionDisplay to adMenu
Procedure OnClick
Send MoveToLastRow of oList
End_Procedure
End_Object
End_Object
Procedure OnNavigateForward tWebNavigateData NavigateData Integer hoInvokingView Integer hoInvokingObject
Case Begin
Case (NavigateData.eNavigateType=nfFromParent)
If (NavigateData.iTable = RefEntity(Presenter)) Begin
Send SetBreadcrumbCaption (SFormat("Presentations from %1", oPresenterDD.FirstName * oPresenterDD.LastName))
End
Else If (NavigateData.iTable = RefEntity(Room)) Begin
Send SetBreadcrumbCaption (SFormat("Presentations in %1", oRoomDD.Name))
End
Case Break
Case (NavigateData.eNavigateType=nfFromChild)
Case Break
Case (NavigateData.eNavigateType=nfFromMain)
Case Break
Case Else // must be nfUndefined
Case End
End_Procedure
End_Object
AppSrc/ZoomPresentation.wo¶
The Presentation zoom binds oPresentationDD to Room and Presenter parent DDOs, exposing related room/presenter fields alongside editable presentation data and navigation actions. oPresentationDD owns the current row; Set DDO_Server connects its RoomId and PresenterId relations to the parent DDOs so Entry_Item oRoom_DD.Name, Entry_Item oPresenter_DD.FirstName, and Entry_Item oPresenter_DD.LastName can resolve related values. Entry_Item oPresentation_DD.Title and the other presentation-field controls edit the presentation DDO, whose save actions validate and persist through the same relationship-aware graph.
Use WebUI\cWebView.pkg
Use WebUI\cWebPanel.pkg
Use WebUI\cWebForm.pkg
Use WebUI\cWebGroup.pkg
Use WebUI\cWebMenuGroup.pkg
Use WebUI\cWebMenuItem.pkg
Use WebUI\cWebEdit.pkg
Use WebUI\cWebDateForm.pkg
Use WebUI\cWebCombo.pkg
Use PresentationDataDictionary.pkg
Use PresenterDataDictionary.pkg
Use RoomDataDictionary.pkg
Object oZoomPresentation is a cWebView
Set peWebViewStyle to wvsDrillDown
Set peViewType to vtZoom
Set pbShowCaption to False
Set Verify_Save_msg to 0 // don't confirm saves
Set psCaption to "Details of Presentation"
Set psStateViewName to "Presentation"
Set piMaxWidth to 1024
Set piColumnCount to 12
Set peLayoutType to ltFlow
Object oRoom_DD is a cRoomDataDictionary
End_Object
Object oPresenter_DD is a cPresenterDataDictionary
End_Object
Object oPresentation_DD is a cPresentationDataDictionary
Set DDO_Server to oRoom_DD
Set DDO_Server to oPresenter_DD
End_Object
Set Main_DD to oPresentation_DD
Set Server to oPresentation_DD
Object oWebMainPanel is a cWebPanel
Set piColumnCount to 12
Object oPresentation_Title is a cWebForm
Entry_Item oPresentation_DD.Title
Set psLabel to "Title"
Set peLabelPosition to lpTop
Set piColumnSpan to 13
End_Object
Object oPresentation_Description is a cWebEdit
Entry_Item oPresentation_DD.Description
Set psLabel to "Description"
Set peLabelPosition to lpTop
Set piColumnSpan to 13
Set piMinHeight to 200
Set piHeight to 200
End_Object
Object oPresentation_Date is a cWebDateForm
Entry_Item oPresentation_DD.Date
Set psLabel to "Date"
Set peLabelPosition to lpTop
Set piColumnSpan to 2
End_Object
Object oPresentation_StartTime is a cWebForm
Entry_Item oPresentation_DD.StartTime
Set psLabel to "StartTime"
Set peLabelPosition to lpTop
Set piColumnSpan to 2
Set peDataType to typeTime
Set piColumnIndex to 2
End_Object
Object oPresentation_EndTime is a cWebForm
Entry_Item oPresentation_DD.EndTime
Set psLabel to "EndTime"
Set peLabelPosition to lpTop
Set piColumnSpan to 2
Set peDataType to typeTime
Set piColumnIndex to 4
End_Object
Object oPresentation_Level is a cWebForm
Entry_Item oPresentation_DD.Level
Set psLabel to "Level"
Set peLabelPosition to lpTop
Set piColumnSpan to 4
End_Object
Object oPresentation_MaxAttendees is a cWebForm
Entry_Item oPresentation_DD.MaxAttendees
Set psLabel to "MaxAttendees"
Set peLabelPosition to lpTop
Set piColumnSpan to 2
Set piColumnIndex to 4
End_Object
Object oRoom_Name is a cWebForm
Entry_Item oRoom_DD.Name
Set psLabel to "Room"
Set peLabelPosition to lpTop
Set piColumnSpan to 6
Set piColumnIndex to 6
End_Object
Object oPresenter_FirstName is a cWebForm
Entry_Item oPresenter_DD.FirstName
Set psLabel to "Presenter (firstname):"
Set peLabelPosition to lpTop
Set piColumnSpan to 3
Set pbServerOnPrompt to True
WebRegisterPath ntNavigateForward oSelectPresenter
Set pbPromptButton to True
Procedure OnPrompt
Send NavigatePath
End_Procedure
End_Object
Object oPresenter_LastName is a cWebForm
Entry_Item oPresenter_DD.LastName
Set psLabel to "Presenter (lastname):"
Set peLabelPosition to lpTop
Set piColumnSpan to 3
Set pbServerOnPrompt to True
Set piColumnIndex to 3
WebRegisterPath ntNavigateForward oSelectPresenter
Set pbPromptButton to True
Procedure OnPrompt
Send NavigatePath
End_Procedure
End_Object
WebSetResponsive piColumnCount rmMobile to 6
End_Object
// add action menu items here
// we've included some common buttons
Object oActionGroup is a cWebMenuGroup
Set psGroupName to "MainActions"
Object oSaveBtn is a cWebMenuItem
Set psCaption to "Save"
Set psCSSClass to "WebSaveMenuItem"
Procedure OnClick
Send Request_Save
End_Procedure
End_Object
Object oEditBtn is a cWebMenuItem
Set psCaption to "Edit"
Set psCSSClass to "WebEditMenuItem"
Procedure OnClick
Send ChangeEditMode True
Send SetActionButtons
End_Procedure
End_Object
Object oDeleteBtn is a cWebMenuItem
Set psCaption to "Delete"
Set psCSSClass to "WebDeleteMenuItem"
Set peActionDisplay to adMenu
Procedure OnClick
Send Request_Delete
End_Procedure
End_Object
Object oCancelChangesBtn is a cWebMenuItem
Set psCaption to "Clear Changes"
Set psCSSClass to "WebIcon_Refresh"
Set peActionDisplay to adMenu
Set pbServerOnClick to True
Procedure OnClick
// this will undo any unchanged saves and show the latest
Send RefreshRecord
Send NavigatePath
End_Procedure
End_Object
End_Object
// This can be used to show and hide buttons based on context.
// This can be called any time the view is active.
Procedure SetActionButtons
tWebNavigateData NavigateData
Boolean bHasRecord
Handle hoDD
Get Server to hoDD
Get GetNavigateData to NavigateData
If (hoDD) Begin
Get HasRecord of hoDD to bHasRecord
End
Else Begin
Move False to bHasRecord
End
// let's hide all buttons and then show the ones we want
WebSet pbRender of oEditBtn to False
WebSet pbRender of oSaveBtn to False
WebSet pbRender of oCancelChangesBtn to False
WebSet pbRender of oDeleteBtn to False
If (NavigateData.bReadOnly) Begin
WebSet pbRender of oEditBtn to True
End
Else Begin
WebSet pbRender of oSaveBtn to True
WebSet pbRender of oCancelChangesBtn to True
WebSet pbRender of oDeleteBtn to bHasRecord
End
End_Procedure
// this will close the view after a save
Procedure OnViewSaved Handle hoServer Boolean bChanged
Send NavigateClose Self
End_Procedure
// this will close the view after a delete
Procedure OnViewDeleted Handle hoDDO
Send NavigateClose Self
End_Procedure
// Add code to customize your Zoom View based on how it was invoked.
// Use NavigateData to determine the context this view will be used in.
Procedure OnNavigateForward tWebNavigateData NavigateData Handle hoInvokingView Handle hoInvokingObject
If (HasRecord(oPresentation_DD)) Begin
Send SetBreadcrumbCaption oPresentation_DD.Title
End
Else Begin
Send SetBreadcrumbCaption "New presentation"
End
// if this view is being used in multiple contexts, you may need a block of code
// like this to handle customizations. This would include hiding rows and buttons
// (WebSet pbRender) and changing the values of various captions.
Case Begin
Case (NavigateData.eNavigateType = nfFromMain)
// If from main, this is a probably a main file Select to Zoom.
// This is the most typical way to navigate to a zoom.
Case Break
Case (NavigateData.eNavigateType = nfFromParent)
// If from parent, this is a constrained drill down.
// If needed, you could check NavigateData.iTable to determine the constraining parent.
// This would be unusual - normally you drill down from a parent to a list (Select view).
Case Break
Case (NavigateData.eNavigateType = nfFromChild)
// If from child, this is a probably a parent Zoom from a Zoom.
// This is unusual, but it might be used for adding a new child record.
Case Break
Case Else // must be nfUndefined
// This may be the start of a query or this may be used for some kind of custom operation.
// You may want to check NavigateData.NamedValues.
Case End
// Action buttons can be changed dynamically during a Zoom's display lifetime.
// It's best to set these buttons in their own procedure so you can change later.
Send SetActionButtons
End_Procedure
Procedure MyDeleteConfirmation Handle hmCallBack
Send ShowYesNo (Self) hmCallBack "Delete Presentation?" "Confirm"
End_Procedure
Set Verify_Delete_msg to (RefProc(MyDeleteConfirmation))
End_Object
Step 3 — Expand the existing application¶
Keep the generated code around these focused edits. Add only the behavior needed for the complete application: the ConferenceData database path, API constants, application routes, force-aware initialization, version-first synchronization, relationship navigation, and one automatic dashboard synchronization.
Change the local database path and add the API constants near the existing database definitions. The new path starts a separate complete-application database while the API constants are shared by the database package. The logical conf_data connection ID remains unchanged; the generated SQLite connection now resolves it to this new path.
Define C_SQLiteDb for "/dev/idbfs/ConferenceDataV10.db"
Define C_API_Path for "/ConferenceData/API/v1/"
Define C_API_Endpoint for "https://abs01.daelab.net/"
Change the generated client title:
Set psApplicationTitle to "Conference App"
Add these menu routes in the existing menu objects. Add the Dashboard item under the main menu button, and add Rooms, Presenters, and Presentations under oViewMenu. Each item gives the application a named route and navigates to its select view.
Object oDashboard_itm is a cWebMenuItem
Set psCaption to C_$Dashboard
WebRegisterPath ntNavigateBegin oDashboard
Procedure OnClick
Send NavigatePath
End_Procedure
End_Object
Object oSelectRoomItem1 is a cWebMenuItem
Set psCaption to "SelectRoom"
WebRegisterPath ntNavigateBegin oSelectRoom
Procedure OnClick
Forward Send OnClick
Send NavigatePath
End_Procedure
End_Object
Object oSelectPresenterItem is a cWebMenuItem
Set psCaption to "Presenters"
WebRegisterPath ntNavigateBegin oSelectPresenter
Procedure OnClick
Forward Send OnClick
Send NavigatePath
End_Procedure
End_Object
Object oSelectPresentationItem is a cWebMenuItem
Set psCaption to "Presentations"
WebRegisterPath ntNavigateBegin oSelectPresentation
Procedure OnClick
Forward Send OnClick
Send NavigatePath
End_Procedure
End_Object
Change initialization to allow a forced database recreation, then include every view added by this phase:
Use CreateAndSyncDB.pkg
Send InitializeDB of oCreateAndSyncDB False
Use Dashboard.wo
Use SelectRoom.wo
Use ZoomRoom.wo
Use SelectPresenter.wo
Use ZoomPresenter.wo
Use SelectPresentation.wo
Use ZoomPresentation.wo
Keep the generated source-level Dashboard default view.
AppSrc/CreateAndSyncDB.pkg¶
Add the Room, Presentation, and Settings Data Dictionaries to oCreateAndSyncDB. oPresentationDD is the main DDO for Presentation records; its Set DDO_Server lines connect the Room and Presenter parent DDOs required by the entity relations. pbSynchronized records whether the current client session has completed a successful synchronization.
Use RoomDataDictionary.pkg
Use PresentationDataDictionary.pkg
Use PresenterDataDictionary.pkg
Use SettingsDataDictionary.pkg
Object oRoomDD is a cRoomDataDictionary
End_Object
Object oPresenterDD is a cPresenterDataDictionary
End_Object
Object oPresentationDD is a cPresentationDataDictionary
Set DDO_Server to oRoomDD
Set DDO_Server to oPresenterDD
End_Object
Object oSettingsDD is a cSettingsDataDictionary
End_Object
Property Integer pbSynchronized False
Change InitializeDB to accept a force flag. ExistsInDb opens the configured SQLite file and checks whether the schema exists; a forced call or a missing schema invokes CreateDatabase for the Presentation and Settings tables.
Procedure InitializeDB Boolean bForceRecreate
Boolean bExists
Get ExistsInDb of oPresentationDD True True to bExists
If (bForceRecreate or not(bExists)) Begin
Send CreateDatabase of oPresentationDD True True True
Send CreateDatabase of oSettingsDD False False True
End
End_Procedure
Change the existing HTTP client to use the shared endpoint constant:
Object oHttpReq is a cHttpClient
Set psEndpoint to C_API_Endpoint
End_Object
Change SynchronizeData to accept bForce and use cHttpClient to fetch the version before downloading entity data. If the local version matches and the call is not forced, leave local data unchanged. Keep every existing non-200 return before the transaction so an HTTP failure cannot set pbSynchronized.
Procedure SynchronizeData Boolean bForce
Integer iLocalDataVersion iRemoteDataVersion iItem iItemTo
HttpStatus eStatus
Room[] aRooms
Presenter[] aPresenters
Presentation[] aPresentations
Boolean bErr
Get LoadSetting of oSettingsDD "DataVersion" "0" to iLocalDataVersion
Get HttpGet of oHttpReq (C_API_Path + "Version") to eStatus
If (eStatus <> 200) Begin
Send UserError (SFormat("Could not connect to server (HTTP status %1)", eStatus))
Procedure_Return
End
Get HttpResponseToDataType of oHttpReq True "Version" to iRemoteDataVersion
If (iLocalDataVersion <> iRemoteDataVersion or bForce) Begin
Push_locale
Set_Attribute DF_LOCALE to DF_LOCALE_ISO8601
Get HttpGet of oHttpReq (C_API_Path + "Room") to eStatus
If (eStatus <> 200) Begin
Send UserError (SFormat("Could not connect to server (HTTP status %1)", eStatus))
Pop_locale
Procedure_Return
End
Get HttpResponseToDataType of oHttpReq False "" to aRooms
Get HttpGet of oHttpReq (C_API_Path + "Presenter") to eStatus
If (eStatus <> 200) Begin
Send UserError (SFormat("Could not connect to server (HTTP status %1)", eStatus))
Pop_locale
Procedure_Return
End
Get HttpResponseToDataType of oHttpReq False "" to aPresenters
Get HttpGet of oHttpReq (C_API_Path + "Presentation") to eStatus
If (eStatus <> 200) Begin
Send UserError (SFormat("Could not connect to server (HTTP status %1)", eStatus))
Pop_locale
Procedure_Return
End
Get HttpResponseToDataType of oHttpReq False "" to aPresentations
Pop_locale
Begin_Transaction
ZeroFile oRoomDD
Move (SizeOfArray(aRooms) - 1) to iItemTo
For iItem from 0 to iItemTo
Clear oRoomDD
Send UpdateAllFields of oRoomDD aRooms[iItem]
Get Request_Validate of oRoomDD to bErr
If (not(bErr)) Begin
Send Request_Save of oRoomDD
End
Loop
ZeroFile oPresenterDD
Move (SizeOfArray(aPresenters) - 1) to iItemTo
For iItem from 0 to iItemTo
Clear oPresenterDD
Send UpdateAllFields of oPresenterDD aPresenters[iItem]
Get Request_Validate of oPresenterDD to bErr
If (not(bErr)) Begin
Send Request_Save of oPresenterDD
End
Loop
ZeroFile oPresentationDD
Move (SizeOfArray(aPresentations) - 1) to iItemTo
For iItem from 0 to iItemTo
Clear oPresentationDD
Send UpdateAllFields of oPresentationDD aPresentations[iItem]
If (oRoomDD.RoomId <> aPresentations[iItem].RoomId) Begin
Move aPresentations[iItem].RoomId to oRoomDD.RoomId
Find EQ oRoomDD.RoomId
If (not(Found)) Begin
Error DFERR_PROGRAM "Received invalid data from the server"
End
End
If (oPresenterDD.PresenterId <> aPresentations[iItem].PresenterId) Begin
Move aPresentations[iItem].PresenterId to oPresenterDD.PresenterId
Find EQ oPresenterDD.PresenterId
If (not(Found)) Begin
Error DFERR_PROGRAM "Received invalid data from the server"
End
End
Get Request_Validate of oPresentationDD to bErr
If (not(bErr)) Begin
Send Request_Save of oPresentationDD
End
Loop
Send StoreSetting of oSettingsDD "DataVersion" iRemoteDataVersion
Send StoreSetting of oSettingsDD "LastSync" (CurrentDateTime())
End_Transaction
End
If (not(Err)) ;
Set pbSynchronized to True
End_Procedure
The three entity downloads occur before one transaction. UpdateAllFields copies each typed response item into a DDO buffer; Request_Validate checks entity and relation rules; Request_Save sends valid records through the Data Dictionary adapter to the SQLite driver. Room and Presenter records are available as parent records before Presentation rows are saved. Invalid foreign IDs raise an error inside the transaction, and DataVersion/LastSync are stored only with the downloaded data. pbSynchronized is set only after the procedure has completed without an error.
Add the status accessor used by the Dashboard:
Function LastSync Returns String
String sResult
Get LoadSetting of oSettingsDD "LastSync" "--" to sResult
Function_Return sResult
End_Function
AppSrc/Dashboard.wo¶
Add server-side show handling:
Set pbServerOnShow to True
Keep the existing synchronization tile object name. Add status rendering and a forced refresh action to that tile. The Dashboard calls DoSync False for its one-time automatic synchronization and DoSync True when the user clicks Synchronize.
Object oWelcomeTile is a cWebHtmlBox
Set pbServerOnClick to True
Set psHtml to '<div Class="WebCon_Sizer" data-ServerOnClick="doSync"><div class="Tile_Icon WebIcon_Refresh"></div><div Class="Tile_Subtitle">Initializing..</div></div>'
Procedure DisplayStatus String sStatus
Send UpdateHtml (SFormat('<div Class="WebCon_Sizer" data-ServerOnClick="doSync"><div class="Tile_Icon WebIcon_Refresh"></div><div Class="Tile_Subtitle">%1</div></div>', sStatus))
Send UpdateWebUI of (Host(Self))
End_Procedure
Procedure DisplayLatest
String sLastSync
Get LastSync of oCreateAndSyncDB to sLastSync
Send DisplayStatus sLastSync
End_Procedure
Procedure DoSync Boolean bForce
Send DisplayStatus "Synchronizing.."
Send SynchronizeData of oCreateAndSyncDB bForce
Send DisplayLatest
End_Procedure
Procedure OnClick String sId String sParam
Send DoSync True
End_Procedure
End_Object
Add the one-time synchronization guard:
Procedure OnShow
If (not(pbSynchronized(oCreateAndSyncDB))) Begin
Send DoSync of oWelcomeTile False
End
Else Begin
Send DisplayLatest of oWelcomeTile
End
End_Procedure
Change the remaining dashboard tiles to route to the new select views:
Object oTile2 is a cWebHtmlBox
Set psHtml to '<div class="WebCon_Sizer" data-ServerOnClick="openview"><div Class="Tile_Title">Rooms</div><div class="Tile_Subtitle"></div></div>'
WebRegisterPath ntNavigateForwardCustom oSelectRoom
End_Object
Object oTile3 is a cWebHtmlBox
Set psHtml to '<div class="WebCon_Sizer" data-ServerOnClick="openview"><div Class="Tile_Title">Presenters</div><div class="Tile_Subtitle"></div></div>'
WebRegisterPath ntNavigateForwardCustom oSelectPresenter
End_Object
Object oTile4 is a cWebHtmlBox
Set psHtml to '<div class="WebCon_Sizer" data-ServerOnClick="openview"><div Class="Tile_Title">Presentations</div><div class="Tile_Subtitle"></div></div>'
WebRegisterPath ntNavigateForwardCustom oSelectPresentation
End_Object
Keep each tile's generated OnClick procedure that sends NavigatePath.
AppHtml/CssStyle/application.css¶
Add the application's custom stylesheet for the synchronization tile. The generated WebAssembly template provides the WebIcon_Refresh icon; this rule supplies the sample-specific tile icon sizing and position.
.Tile .Tile_Icon {
font-size: 40px;
text-align: center;
position: relative;
top: 30px;
}
AppSrc/SelectPresenter.wo¶
Add Presentation navigation to the Presenter list and change its visible identity to Presenters:
Set psCaption to "Presenters"
Set pbShowCaption to False
Set psStateViewName to "Presenters"
WebRegisterPath ntNavigateForward oSelectPresentation
Change the list columns to show last name, first name, and company while retaining the existing zoom button:
Object oPresenterDD_LastName is a cWebColumn
Set psCaption to "Last Name"
Set psCSSClass to "RowCaption"
Set peAlign to alignLeft
Entry_Item oPresenterDD.LastName
Set piListColSpan to 2
End_Object
Object oPresenterDD_FirstName is a cWebColumn
Set psCaption to "First Name"
Set pbNewLine to True
Entry_Item oPresenterDD.FirstName
End_Object
Object oPresenterDD_Company is a cWebColumn
Set psCaption to "Company"
Set psCSSClass to "RowDetail"
Entry_Item oPresenterDD.Company
End_Object
Keep the existing oDetailButton route to oZoomPresenter. Change OnRowClick so a child or main lookup closes, a parent drill-down navigates forward, and the list keeps its existing context behavior:
Procedure OnRowClick String sRowID
tWebNavigateData NavigateData
Get GetNavigateData to NavigateData
Case Begin
Case (NavigateData.eNavigateType=nfFromParent)
Send NavigatePath
Case Break
Case (NavigateData.eNavigateType=nfFromChild)
Send NavigateClose Self
Case Break
Case (NavigateData.eNavigateType=nfFromMain)
Send NavigateClose Self
Case Break
Case Else
Case Break
Case End
End_Procedure
AppSrc/ZoomPresenter.wo¶
Change the existing Presenter field controls to the complete application's binding names and captions. The controls still bind to oPresenterDD; only the view integration changes.
Object oPresenterDD_FirstName is a cWebForm
Set piColumnSpan to 6
Set psLabel to "First Name"
Entry_Item oPresenterDD.FirstName
End_Object
Object oPresenterDD_LastName is a cWebForm
Set piColumnSpan to 6
Set psLabel to "Last Name"
Entry_Item oPresenterDD.LastName
End_Object
Object oPresenterDD_Company is a cWebForm
Set piColumnSpan to 0
Set psLabel to "Company"
Entry_Item oPresenterDD.Company
End_Object
Object oPresenterDD_Bio is a cWebEdit
Set piColumnSpan to 0
Set psLabel to "Bio"
Entry_Item oPresenterDD.Bio
End_Object
Keep the existing save, edit, delete, cancel, OnViewSaved, and OnViewDeleted procedures. They preserve Presenter editing while navigation from the select view exposes the Presentation relationship.
Checkpoint: Press F5. The dashboard performs one automatic synchronization, then Rooms → Presentations → Presenter drill-down follows the relationship bindings.