Skip to content

Dashboards Quick Start

In a Nutshell: Steps to Take

  1. Add the cWebWidgetContainer to a view.
  2. Create one or more Widgets by making a custom Composite Implementation using cWebWidget as a base.
  3. Register Widgets within your container.
  4. Optionally implement custom configuration saving/loading.
  5. 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).
  • LoadConfiguration is called somewhere (for example, in the view’s OnLoad).

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.

Web Dashboard Create New

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:

  1. Optionally add new WebProperties to your widget to be used for configuration.
  2. Mark which properties are configurable:
  3. Use OnGetConfigurableProps for this in the widget. Add your tWidgetConfigProp to the Byref Array.
  4. Use CreateConfigurableProp function 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.
  5. Attach a cWebWidgetConfigurationWizard to your widget:
  6. Set phoConfigWizard to a cWebWidgetConfigurationWizard implementation.
  7. Build your own custom wizard, or use the provided cWebWidgetConfigurationWizardStandard.
  8. Optionally, manipulate a widget’s configurable state through pbAllowConfiguration and the augmentable OnDetermineConfigurableState event.

To build a custom cWebWidgetConfigurationWizard:

  1. Create an object (or class if you want to create multiple instances) that’s a subclass of cWebWidgetConfigurationWizard.
  2. The wizard is basically a Dialog with some interface logic in there. Place any Data Dictionaries, Controls, etc. that you need inside.
  3. Implement the following:
  4. OnPopulateWizard: Comes with a tWidgetConfigPropValue array. Use this to populate your wizard’s controls with the widget’s current configurable property values.
    • You can use ParkPropValue to temporarily store a value for later use. Make sure you remember the sObjName and sPropName as these are used as the unique identifiers for retrieving via RetrieveParkedPropValue.
    • Use convenience function GetPropValue for easier sifting through the array.
  5. 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 ByRef tWidgetConfigPropValue array to be filled with the new values.
    • Use convenience function SetPropValue for easier adding of a value to the array.
    • Make sure the sObjName and the sPropName of the new values match with the existing ones, as this is used to map to the widget’s configurable property.