Dashboards Quick Start
In a Nutshell: Steps to Take
- Add the
cWebWidgetContainerto a view. - Create one or more Widgets by making a custom Composite Implementation using
cWebWidgetas a base. - Register Widgets within your container.
- Optionally implement custom configuration saving/loading.
- Implement logic to visibly add widgets to the dashboard.
Adding the Container
The most important thing is to make sure your view contains a cWebWidgetContainer somewhere. This is the main component that unlocks Dynamic Dashboards functionality and is your main API to communicate with. You also need to make sure that:
- You’ve registered some widgets within the container.
- Widgets can be added somehow (see “Adding Widgets” below).
LoadConfigurationis called somewhere (for example, in the view’sOnLoad).
An easy way to deal with all of this in one swoop is to use the newly provided template. Simply have your web application selected as the current project and go to File > New > Web Object and select the Web Dashboard View option. This will provide you with a clean view that includes the container, the cWebWidgetPalette (see “Adding Widgets” below for explanation), and a LoadConfiguration instruction in the view’s OnLoad.

Creating Widgets
It is recommended to put each widget in its own separate file; otherwise, the designer will not work. The Studio's Workspace Explorer has a separate new category for Web Widgets.
In your file, create a new class using the Composite keyword, and inherit from cWebWidget. For example:
Composite cMyCustomWidget is a cWebWidget
Inside your composite, you can directly place new (web) properties, child objects with method overrides, DDO structures, etc.
Widgets can contain Data Dictionaries, and both the widget itself and all child objects can be data aware.
Widgets can also perform navigations. Simply use the WebRegisterPath command to register a new navigation path, and then use the standard NavigatePath somewhere in your widget to perform the navigation.
Widgets can also be configurable. See “Configurable Widgets” for this.
Registering Widgets
Once you have created your own custom widget, it needs to be registered with a cWebWidgetContainer. For this, use the RegisterWidget procedure, passing the widget (ref) class as a parameter. This lets the container know that it can dynamically create instances of this widget at runtime using the logic contained within the Dashboards framework.
Adding Widgets
To add widgets, you have several possible approaches that you can take. Whatever you do, the bottom line is to make sure that somewhere you call either AddWidget or AppendWidget to visibly add one of your registered widgets to the container.
The easiest approach is to make use of the cWebWidgetPalette. This is a custom cWebList subclass specifically designed to work with widgets. It comes pre-styled and attaches itself to a cWebWidgetContainer through the phoWidgetContainer property handle. Through this, it reads all of the container’s registered widgets and uses this to fill the list. The palette comes with built-in Drag & Drop support from the list to the container, allowing you to drag widgets from the list straight onto the dashboard to add them.
You can also make custom implementations. For example, you could make a cWebCombo that contains your registered widgets as options. Whenever you select something from the combo, it would execute an AppendWidget based on the selected option. This approach requires custom coding.
Loading & Saving Configurations
By default, configurations are loaded from and saved to the browser’s local storage. This works out of the box and requires no extra effort. The configuration is basically one big tContainerDef struct, which is stored as JSON at the client.
Local Storage is convenient, but a big problem is that it is not user-safe by default. If your application supports multiple users (aka logins), then if another user were to log on to the same machine, that user would be presented with the configuration from the other user as they use the same Local Storage.
You can define custom logic for loading and saving configurations, which allows you to read from and write to a database, for example. First, set pbUseCustomConfigurationStorage to true. Then, implement both OnLoadConfiguration and OnSaveCustomConfiguration.
OnSaveCustomConfiguration comes with a tContainerDef parameter, which represents the current configuration from the client. You can define custom logic to store this somewhere. One approach would be to convert the struct to a JSON string and store it in a database field connected to the user. OnLoadConfiguration gets a tContainerDef passed as a parameter and expects you to fill it.
Using the previously outlined approach, you could read the JSON string from the database field and convert it back to a tContainerDef struct, which would then get used to load the stored configuration.
Configurable Widgets
Widgets can be configurable. This means that a portion of your widget can be changed at runtime through configuration, allowing it to, for example, use different data, look slightly different, or perform a different navigation.
An example would be a widget containing a list of your 10 latest orders. Through configuration, you could add a property that filters this list based on the order total to only show orders with an order total greater than $1,000.
The idea is that through configuration you can have a single widget class with slightly different data or behavior, without having to completely create a new widget for this. You can have multiple instances of this widget in a container and, by using configuration, they will look or behave slightly different.
The steps to make a widget configurable are as follows:
- Optionally add new WebProperties to your widget to be used for configuration.
- Mark which properties are configurable:
- Use
OnGetConfigurablePropsfor this in the widget. Add yourtWidgetConfigPropto the Byref Array. - Use
CreateConfigurablePropfunction for convenience to get you started, passing the Object handle and Property to make it configurable. Use the(widget(Self))instruction if your property exists in the widget root. - Attach a
cWebWidgetConfigurationWizardto your widget: - Set
phoConfigWizardto acWebWidgetConfigurationWizardimplementation. - Build your own custom wizard, or use the provided
cWebWidgetConfigurationWizardStandard. - Optionally, manipulate a widget’s configurable state through
pbAllowConfigurationand the augmentableOnDetermineConfigurableStateevent.
To build a custom cWebWidgetConfigurationWizard:
- Create an object (or class if you want to create multiple instances) that’s a subclass of
cWebWidgetConfigurationWizard. - The wizard is basically a Dialog with some interface logic in there. Place any Data Dictionaries, Controls, etc. that you need inside.
- Implement the following:
OnPopulateWizard: Comes with atWidgetConfigPropValuearray. Use this to populate your wizard’s controls with the widget’s current configurable property values.- You can use
ParkPropValueto temporarily store a value for later use. Make sure you remember thesObjNameandsPropNameas these are used as the unique identifiers for retrieving viaRetrieveParkedPropValue. - Use convenience function
GetPropValuefor easier sifting through the array.
- You can use
OnGetConfigValues: Used when closing the wizard. Use this to get the new values from your Wizard’s controls so they can be fed back into the corresponding widget. Comes with a ByReftWidgetConfigPropValuearray to be filled with the new values.- Use convenience function
SetPropValuefor easier adding of a value to the array. - Make sure the
sObjNameand thesPropNameof the new values match with the existing ones, as this is used to map to the widget’s configurable property.
- Use convenience function