IBM Business Automation Workflow, Working with Deferred Sections
Deferred Sections are a highly valuable tool available to ensure parts of the UI are only loaded when needed.
Authors: Leonard Blunt , Greg Ekaprana, Okka Sudaryanto, Diorella Mari Tom
Code Repository
Client Side Human Service : Deferred Section Simple Example in tips-for-baw-tk
Introduction
When working in IBM Business Automation Workflow it can occur that Client-Side Human Service and/or Coach Views can become complex and embed many other coach views, such as modals, tabs and hidden sections all of which are rendered when the page loads. In complex coach views this typically result in many load functions being called and even superfluous data being retrieved. The loading of many complex views can slow the page rendering and create a perceived performance issue. Deferred Sections as their name indicates allows us to control when sections of the UI are loaded. By managing how the different parts of the UI are loaded we can make sure that only required views and data are loaded, which means a user only waits for what is needed improving initial load times. Deferred sections are also beneficial when managing dependencies between parts of the coach view
Architecturally we promote simple targeted UI with less data. But when this is not possible good design and use of a deferred sections can significantly improve real and perceived load times for a user.
Deferred sections stop the views within them from being loaded until the lazyLoad() function on the Deferred Section component is invoked. The lazyLoad() function can be directly invoked, for example called as a part of a user event such as a button click event, or such as when a service call completes successfully. This function an also be auto triggered by setting the auto load configuration property of the deferred section.
Here are some tips for good use cases for using Deferred Sections:
- When using Tabs or Stacks embed the content of each Tab in a deferred section. Set the first tab to auto load and use the on click event to load subsequent tabs
- Deferred Section also could be used inside the modal, especially for a modal that has a function on load. As many modals are situational it is common that a modal view may not be displayed, so the use of deferred sections reduces the loading of unneeded views.
- When sections are hidden should be built inside a deferred section and triggered to load only as needed.
Using Auto-Load Configuration
This is the simpler of the two options and can serve to help prioritize loading of different parts of a view by delaying a different part of the view. We shall mock-up a simple example that illustrates the auto load and the delay. This example in in the sample toolkit in git.
Let’s look at the anatomy of the example client side human service.
- Incorporates a Stack with Two buttons for triggering change to the stack tab that is displayed (Will elaborate this on the event driven load).
- The deferred section. By placing the deferred section at the client-side human service, we make it easier to control the loading of embedded views.
- A simple coach view that has a label and when it loads it sets an output text displaying the load time. This is a very simple way to illustrate the deferred section in action.
You will need to make a choice when using tabs or stack as to whether you want a deferred section on the "default" tab. If it is possible for the default to change or likely to change it will simplify changes later if included in initial construction.
In Figure 2, the Load automatically configuration is shown illustrating that the section will load 5000 milliseconds after the deferred section is loaded. The result of running this simple example is illustrated in Figure 3.
If you have a deferred section in place but decide a delay is not required can set the delay to 0 rather than change code.
Manually Triggering the Deferred Section Load
When using deferred sections, it is much more common to use an external event to trigger the loading of the section. Triggering the lazyLoad() is as simple as calling the function on the deferred section. The method takes two parameters the time to delay before the load and a boolean that indicates if the “on lazy-loaded event” should trigger once the section is loaded.
The "on lazy-loaded event" can be both useful and important if the embedded views need to refresh or load data. It is important to understand the deferred section defers initial loading of the components inside. But once loaded additional calls to the lazyload() function DOES NOT RELOAD the components. But it will throw the "on lazy-loaded event" each time. This event can be used to trigger updating or loading of data.
Continuing the example for the second tab of the stack we shall manually trigger the loading of the deferred section by using the “on Click Event” “Category 2” Button which will load the deferred section. When the deferred section load is complete, we set the current pane using the “setCurrentPane” function on the stack. So, in fact we only show the pane once the section is loaded.
Step 1: Deferred Section Configuration Auto is Off
Step 2: Call the lazyLoad from the Buttons on Click
${Deferred_Section2}.lazyLoad(0, true);
On the onClick event of the Category 2 button we call the lazyLoad function. The first parameter 0 indicates do not delay and true indicates that the on lazy-loaded event should be thrown once the section is loaded.
Step 3: Change the current pane when the deferred section is loaded
${CategoryStack}.setCurrentPane(1);
Even though the deferred section only loads once each time the pane changes back and forth the event will trigger because we set true in the lazyLoad function call.
Deferred_Section2 and CategoryStack are the "Control ID" for the deferred section and the stack respectively.
Data Change and Reload Trigger
As noted above once a section is loaded it will not auto trigger the reload of embedded views. In most cases this is perfect as you only want to load the embedded views once but there are times when the embedded view may require updating based on some external context. We will create a simple example here to show one way you can handle this.
The scenario is from the main view the user selects a dataset to display. Once displayed the user chooses data from the data set on a modal, and the selected data is updated in a table. The Modal will include an initial deferred section but once loaded on subsequent calls the product group selected needs to be passed and refreshed.
Step 1 Add a new tab to the stack setting up the events and deferred section as with Category 2 discussed above.
Step 2 Set up data selection
The data selection will include a selection list (we will make this a static list of “product groups”.
When using a selected list any bound variables are not automatically updated, this occurs on the boundary event at our last check.
So, we use the onChange event of the single select to push the select item to a hidden Data coach view. In this example, this data will be used to influence which group of products is shown on the modal.
${Data1}.setValue(me.getSelectedItem());
${Data2}.setValue(me.getSelectedItem());${Modal_Section1}.show();
In the modal we have a coach view that takes the input group and makes a service call to get the data list for the input product group. The modal then allows the user to select the products they want and click add, added items are updated back into the selected product table.
What is significant related to the deferred section is that in the modal we placed a deferred section and if all we do is show and hide the modal the deferred section completes the initial load what you will quickly note is that despite changes to the selected group only the initially selected group data gets shown see Figure 8, we can see that having selected the product group 2 originally when product group 3 is selected the data still shows the Group 2 data. To reliably refresh the data, we use the “on lazy-loaded event” to trigger a refresh.
We are highlighting this to remind you that the deferred section loads the view components once. Data changes do not change the load state unless you explicitly reload or refresh the view.
In the embedded coach view ProductSelector there exists a JavaScript function called refresh that invokes the service call to load the data.
var _this = this;
this.refresh = function() { // productList2 is the Control ID for the Table
_this.ui.get("productList2").clear(); // Service_Call1 is the Control ID for the Service Call
var param = _this.context.options.groupId.get("value");
_this.ui.get("Service_Call1").execute(param);
}
We change the on lazy-loaded event to call this function
${ProductSelector1}.refresh();
Step 3 to complete add selected records to the table in the main view
This is done by getting the selected records from the ProductSelector coach view using the getSelectedRecords() function.
this.getSelectedRecords = function() { // productList2 is the Control ID for the Table
return _this.ui.get("productList2").getSelectedRecords(true);}
In the “On Click” event of the the “Add” button for the modal, in addition to closing the modal the the records are added to the main table on the view.
${Modal_Section1}.hide();
var selected = ${ProductSelector1}.getSelectedRecords();
${productList1}.appendElements(selected);
This is a simple example of course, so no validation of de-duplication or sorting regarding the overall table is completed here. We are focused on illustrating the use of the deferred section to initially delay the loading of the view components contained within the modal. Then secondly to highlight the need to refresh changing dependent data on subsequent calls to the modal. This refresh and change is not specific to deferred sections, but a misunderstanding of what "on lazy-loaded event" means has been known for developers to think their embedded views will have been reloaded and they are not.