Skip to content

Process user interface

Referencing views

The BPM UI API provides a number of ways to reference other controls (Views) depending on the context. The most simple example is to reference a control from itself:

Next when you want to reference another control inside an event of a control you use the ${\<controlId\>} notation:

You can use a shortcut notation of getSibling() to refer to a control at same level (i.e. inside the same view):

From inside a Table column you need to use ${../\<controlId\>} to navigate up to reference controls at the same level as the Table (this principle also applies from inside a view to reference things that are siblings of the view on the parent Coach):

(Note the above also shows an example of using internal Table shortcut references – in this case to reference a control from same row with ${txtSKU=} notation).

To reference controls that are on the Coach (the page) you use page.ui.get():

To reference controls inside a view’s logic use this.ui.get():

To reference view logic (functions) from a contained control inside a view use view.xxx:

Using formulas

The BPM UI API provides formulas where you reference other fields and when those fields change the formula is automatically recalculated. An example of that is in the Create Settlement Offer Coach where the Claim Settlement Amount is a calculated field that uses a formula to refer to other fields. Any time one of those referenced fields changes then the formula is re-evaluated:

However sometimes setting a formula does not meet the requirements and you have to adopt an alternative approach. Here is an example of trying to set a formula that references the selected rows in some tables:

The first issue is that it gives errors because the getSelectedRecord() at load returns null:

The second issue (and the critical one in this case) is that an automatic update does not seem to get triggered when you select the row in the table. To work around this we take a different approach were we will use a function to perform the calculation and set the target field and place this function in a reusable view that we then add to the Coach:

The view function is shown here:

Now then the table row is selected we can call the view’s function from the event:

View events examples

Events on a view (control) are the key to detecting a change and reacting to it (e.g. a data field is set or updated) with BPM UI API calls. A typical event is an on click of a button – here is an example of invoking a view’s function and passing in as an argument a reference to another control’s bound data property:

Here is an example of reacting to a data change event and it also shows you can put multiple statements in the implementation (you can even add arbitrary JS logic like if() {} else {}):

Her is an example of detecting a table row selection:

Table view API manipulation

The BPM UI Table view API has a number of methods, snippets of the ones that were used most regularly in the processing are shown here:

Editing table rows with Flyout

The BPM UI Samples recommend using a view inside a table column that edits a row (and uses Deferred Sections for lazy loading). The key to this is that the Modal section is placed within a table column and bound to the list’s currentItem:

While this allows for editing the table row, it makes direct edits to the underlying row and does not preserve the existing value. In our scenario we want to provide an enhanced user experience so they can Edit a row and then decide whether to commit those changes or cancel them. To support this we can not use the approach of binding to the list’s currentItem. Instead we create a separate local variable of type VehiclePart which represents the currently editable Part and bind that to the Modal that will include the Part editing fields:

When Edit is clicked the event then calls an editPart() method defined in a reusable view and passes in the SKU for the selected row:

Here is the editPart() method within Provide Repair Estimate Functions view that then sets the bound data on the mobile from the selected item in the Parts table plus it also sets a hidden field for the part index as we will need to reference this in the case of the user choosing the Save Changes option on the Modal:

The Save Changes boundary event is then used to transition to a client-side script where the partsList is updated at the saved index (and if the user selects to Cancel we just close the Modal and do not make any updates to the partsList):

Putting reusable functions in a view

Formulas etc on controls are great for one time actions but you often find that you want to do multiple things on an event and while you can add many statements separated by “;” in an event it becomes unwieldly and difficult to maintain. Also if you find yourself having to do a lot of chained behavior on different controls (e.g. a table updates so you have to check button visibility, plus popup a model, plus re-initialize a variable, etc) then it is hard to keep track. (Another example is for a Table with a requirement to switch Button visibility depending on row count – the Table’s on rows loaded event worked for most cases but it did not fire when you programmatically called table.add() to add a new row). So we considered it better to have a function that does the multiple things and call that function. However if you use Custom HTML on a Coach then you can’t reference that function in client-side scripts so you would end up with duplicating the logic (where you had to transition out of Coach and call the same behavioural logic). To get round this we created a view that has no content (well we put a hidden 100px Spacer on it so we could see it visually on the parent Coach canvas):

And an example of referencing the functions:

The downside is that the view with functions has to refer to control Id names that are volatile (if they change on Coach then the code inside the view functions will break):

However you would be in a similar situation if you used Custom HTML as again you would have to edit the code for every change to a Control ID.

Transitioning to client-side scripts

While the ability to encapsulate all UI logic in a view is desirable to allow for maximum reuse, sometimes it is not possible to self-contain everything on the Coach or in a view – you have to transition out to a client-side script to complete the necessary logic. The most common situation is where you need to refer to a variable that is not bound to anything on the coach so it does not have any DOM representation that you can make BPM UI API calls (e.g. page.ui.get(\<controlId\>)) against. Here is an example from the Tender For Estimates Coach where the vehicleList.repairerList does not have any binding to a visual control and so it cannot be referenced in BPM UI API calls:

Here is another example where there is a reference to duplicatePartWarning which has no binding on the Coach:

(Note: duplicatePartWarning is a String bound to the Help section of a Modal Alert view from UI Toolkit that is added on the Coach and there is no exposed API method on it that lets you set the Help value thus the need to manipulate the duplicatePartWarning variable):

Note in both of the above cases it may be possible to avoid these transitions if really necessary by putting hidden controls on the Coach that are bound to the variables that need to be manipulated. That way the BPM UI API can be used to access and update the bindings on those hidden controls.

An other example is where the event is not exposed – such as in a Modal with buttons encapsulated within it so you cannot get access to the button events:

You have to then react to the boundary event instead and transition to a client-side script:

You may also be able to avoid this situation in a number of (increasing complexity in terms of coding) ways. The easiest solution might be to not encapsulate the buttons inside the Modal but have them directly on the Coach / view that needs to react to their events. An alternative, and more complex, option would be to expose the inner button events to the interface of the containing view. This requires using BPM UI Coach Framework APIs to detect the button events programmatically and to fire an event option on the parent view.

Coach views loading order

The loading order of the tree of views contained in a coach is inside out – a section with controls loads after all the contained controls inside it have loaded and so on. We utilise a top level Vertical Layout container in each Coach and do initialization things that reference multiple controls in the onLoad() event of it – that way we can ensure all dependent controls are already loaded and can be referenced with page.ui.get(\<controlId\>) / ${\<controlId\>} etc. Here is an example with the outermost Vertical Layout shown and in there it calls an embedded view with the JS functions to perform checking whether to enable the Complete button or not:

Deferred section views and asynchronous loading

A common pattern when using a Modal popup is to defer the loading of it until needed (especially if it is complex and put within the column of a table) using the Deferred Section (DS) view. You have to be very careful about the loading order – you will get errors showing up in the browser debugger such as “page.ui.get(\<controlId>) not defined” if you are trying to reference DOM items that are not loaded yet. A way to avoid such issues is to encapsulate the actions in a function and ensure it is called only when the DS has loaded. Here is a view with a DS that inside has a Modal and a Table and other controls:

An initializing function (showModal() below) is called from parent Coach (say from a button click event) that checks whether the DS is loaded and if not it calls lazyLoad() on it otherwise it calls the function that prepares the view by setting visibility etc:

This same prepareView() function should be called only when the DS has lazy-loaded:

Forcing boundary event triggers

Sometimes you want to react to an event on a control by executing some client-side script logic but the control does not have its own boundary event that fits the need. So you add a Navigation Event control:

And in the source for the event (in this example the return from a Service Call) you call fire() on it:

Which then lets you transition out to the client-side script:

Map control reacting to binding changes

We use a BPM UI Map view in the Tender for Estimates Coach to show the location of a Vehicle. The BPM UI Map view has configuration options for the latitude / longitude settings:

While these work on first load of the Map inside the popup Modal on the Coach, subsequent changing of these values (for example when the selected Vehicle is changed) did not trigger an update of the location shown on the Map. To get around this we need to use a specific Map API method. First let’s look at the sequence of events, When a Vehicle is selected the ZIP is passed to a Service Call view (Get Coordinates) which invokes a service to translate the ZIP into Geo coordinates. On return from that Service Call we then need to force a transition and that is done by in turn calling the fire() method of a Navigation Event view:

The Navigation Event then provides us a boundary event which we can use to transition to the Show Map client-side script:

And in the script (among other things) we have to explicitly call the setCenter() method on the Map to ensure it refreshes:

Note that while this results in the Map correctly showing the new coordinates, however the Marker is not shown.

Access view configuration option complex BO

There is a defined way to navigate through the structure of a complex BO (Business Object) bound as a configuration option of a view. In this case you get the top level BO (searchableVehicleParts) and then a property that is a list (partsList):

Then a further call uses the index to get a specific entry from the list and then reference attributes of that entry (an instance of VehiclePart BO):