X

The Visual Builder Cloud Service Blog

  • July 3, 2019

Visual Builder - Prompting for User Input in an Action Chain

Duncan Mills
Architect
This is a syndicated post, view the original post here

From time to time you may find it necessary to prompt for user input during the course of a Visual Builder Action Chain execution.  For example, as shown here, you might want to confirm that the user really wants to navigate somewhere, or check to see if they want to really delete that row, that kind of thing. Of course you can use the Oracle JET dialog component to provide the user interface for this, but how do you incorporate that into the flow of an Action Chain? 

Well there are two approaches:

  1. You break the logical action chain into multiple chains, the first opens the required dialog using the Call Component Method Action, and then the various buttons on the dialog kick off separate action chains of their own.
  2. You effectively do everything from a single action chain and simply wait for the user input before carrying out the logic. 

The first approach works well, but because the before-user-input and post-user-input actions are split into separate chains it can be hard to manage the code, so let's look at the second approach. 

As an example I've implemented a vbBeforeExit Action Chain to always prompt the user before they navigate, so no matter how navigation is triggered this will always pop up. 

You can see here that the chain is very simple, we call a page module function (checkWithUser) which will display the dialog followed by an If action which branches on the user decision to either continue with the navigation operation or will cancel it.  So the question is - how does this wait for the user to make the selection? The answer is using a Promise. If a module function returns a Promise then action chain processing will wait until that Promise is resolved before continuing to the next step and we'll be taking advantage of that here.  

So let's look at the implementation of the Page Module function being called:

  PageModule.prototype.checkWithUser = function() {
    var self = this;
    var checkPromise = new Promise(function(resolve) {
      // save away the reference to the promise resolvling function
      self.userInputComplete = resolve;
      // Show the dialog
     document.getElementById('confirmDialog').open();
    });
    return checkPromise;
  };

In this function a couple of things are happening. First of all you can see that a Promise is created and the reference to it's resolve function is stashed into the Page Module (via self.userInputComplete), we'll call this from another function later.  Next the dialog is opened.  I've manually created the dialog in the page source view (remembering to add the import for ojs/ojdialog to the page JSON (See: Adding New Oracle JET UI Component to Visual Builder Cloud Service). Here's the code for this simple example:


<div>
  <oj-dialog style="display:none" id="confirmDialog" dialog-title="Navigate to the Next Page" cancel-behavior="none">
    <div slot="body">
      <p>Are you sure you want to navigate?</p>
    </div>
    <div slot="footer">
      <oj-button id="confirmYes" on-oj-action="[[$listeners.confirmYesOjAction]]">Yes</oj-button>
      <oj-button id="confirmNo" on-oj-action="[[$listeners.confirmNoOjAction]]">No</oj-button>
    </div>
  </oj-dialog>
</div>

And each of the on-oj-action listeners just calls the same action chain with different parameters:


"confirmYesOjAction": {
     "chains": [
         {
             "chainId": "dialogResponseChain",
             "parameters": {
                 "detail": "{{ $event.detail }}",
                 "response":"YES"
             }
         }
     ]
 },
 "confirmNoOjAction": {
     "chains": [
         {
             "chainId": "dialogResponseChain",
             "parameters": {
                 "detail": "{{ $event.detail }}",
                 "response":"NO"
             }
         }
     ]
 } 

The dialogResponseChain action chain that they both call is very simple, all it does is call another Page Module method:

And here's the implementation of that function:

  PageModule.prototype.userResponse = function(response) {
    var self = this;
    // close the dialog
    var dialog = document.getElementById('confirmDialog');
    if (dialog.isOpen()) {
      dialog.close();
    }
    if (self.userInputComplete) {
      self.userInputComplete(response);
      delete self.userInputComplete;
    }
  };

So this function first of all closes the dialog and then calls the saved promise resolver function (self.userInputComplete) passing it the requested response which, in this case, will either be the string YES or NO depending on which button the user pressed. This response will then be taken as the response of the original Module Method call that we made in the first chain and as soon as the resolve function is called that chain will free up and this response used by the if statement that follows as the next action.

And that's it.  Of course this is a very simple example.  You could pop up a dialog to make simple yes/no decisions like I have here, or you could even gather user input, you can pass that back to the main action chain using the resolve function in the same way that we passed the Yes/No value. 

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.