Improve UX by using Knockout - show only functions that actually make sense  

published on
Use knockout.js

Especially in APEX we create many dialogs. These dialogs serve for input of application specific data. After we have assembled such a dialog in APEX in seconds by means of a wizard or manually by drag & drop, the real work begins. Especially when it comes to user experience.

One part of the user experience is that the end user is only allowed to execute the functions that make sense to him at that moment. So if I open a dialog to edit an existing record, it makes no sense to show him a cancel button. There is no point, he has not started anything yet. The same is true for the Save button. Why should the user see the Save button if he hasn't made any changes yet.

As soon as the user changes something in the dataset, we show him what he can now do with his changed dataset. In most cases it will be save or cancel.

How can we implement the functionality in our dialogs? Of course with Knockout.js ;-) Of course there are other ways to do it. But with Knockout it's a bit easier.

Include Knockout in your page

Since Knockout is part of Jet, and thus part of APEX, we reference the library with the following link: #JET_BASE_DIRECTORY#js/libs/knockout/knockout-3.5.1.js 

Define a ViewModel

Basically, we create an observable here for the changeable items. And initallize them with the corresponding values from the items themselves. Additionally we create a calculated property that checks if there was a change in at least one of these items.

For the whole thing to work, we have to create a dependency to the respective observable at this point. This happens in the declaration of the array with the dependencies. Thus, the function is automatically executed when at least one item changes and Knockout then automatically updates the corresponding bound elements.

Use the ViewModel

Then we have to pass this function to Knockout as a new object and bind it to our view / DOM.

This has to be placed in the “Execute when Page loads” - Section

Connect the View

What is still missing is the use of the ViewModel inside the view, i.e. in Html itself. At first we have to bind the textinput or value property of the editable items. Therefor we have to edit the "Custom Attribute" property of the corresponding elements. 

data-bind="textinput: cpg_name"

When using textinputs you can choose between textinput or value binding. When using selectlists you have to use value binding. So that the whole thing has an effect, we must of course set the binding to the itemsChanged property at the respective buttons.

data-bind="visible: itemsChanged, css: {pulse: itemsChanged}"

Thus, we bind the visible property of the SAVE button, to the function / property itemsChanged, of the ViewModel. In addition, we add the class pulse at this very moment, so that the appearance of the button gets the focus of the user, through a small animation.

data-bind="visible: !itemsChanged()"

Here it is to make clear that by the negation a JavaScript expression is used. In this case you have to reference the method with opening and closing brackets.

That's it. I hope you see the benefit we get with a small amount of coding.