Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

As a Flow Studio designer, you would want the user to fill an HTML form, or ask for the user to log - in , or send a carousel while executing the Flow studio. In such cases, you can use the Custom Control in the Flow Studio to literally come out of the Flow Studio flow and execute your business logic using a function node in the Experience Designer.

...

  1. In Experience Designer, design a flow as shown below


    or you can use a built-in example flow.

    1. In the Experience Designer, create a new flow.

    2. Click on the hamburger menu on the top right corner and navigate to Import > Built-in > Orbita Flows-(BETA) > Flow Manager.

    3. Place the flow on the canvas and Deploy the flow

    The Hook-Data function node contains the below code to enable the hook to fire the custom logic based on the Custom Control Name.

    Code Block
    try {
        const _ = global.get('lodash');
            controlId = msg.payload.session.attributes.orbitaSession.flowInfo.controlId,
            controlName = msg.payload.session.attributes.orbitaSession.flowInfo.controlName,
            hookName = controlName.indexOf(":") > - 1 ? controlName.substr(0, controlName.indexOf(":")) : controlName,
            args = controlName.indexOf(":") > -1 ?
                [msg,
                 ...controlName.substr(controlName.indexOf(":") + 1).split("|")
                    .map(arg => arg.trim())
                    .filter(arg => !!arg)
                    .map(arg => arg === "null" ? null : arg)] :
                [msg];
        msg.payload.externalHook = {
            data: hookName
        }
        if (hookName) {
            const hook = global.get("hooks")[hookName];
    
            msg.hookResult = {
                hookFound: !!hook
            };
            
            
            if (hook) {
                hook.apply(null, args);
            } else {
                msg.hookResult.executionSuccess = false;
                msg.hookResult.error = `Could not find hook '${hookName}'`;
            
                node.warn(`Could not find hook '${hookName}'`);
            
                return msg;
            }
        }
        
    } catch (error) {
        msg.hookResult.executionSuccess = false;
        msg.hookResult.error = error;
        
        node.warn(`Error executing hook`);
        node.error(error);
        
        return msg;
    }

  2. To set up the Hook Events, you need to initialize the hooks. The Settings / Hooks Initialize function node is used to register the hook condition so that the Hook-Data function knows what to do with it.

    Code Block
    const settings = global.get("settings") || {};
    settings.emptyString = '';
    global.set("settings", settings);
    
    const hooks = global.get("hooks");
    global.set("hooks", hooks || {});
    
    return msg;

  3. You will register your Hook Event with an Inject node. All the Inject nodes in this flow have the same configuration.

  4. When the Custom control named HTMLDirective gets called in Flow studio, the function node named HTML form Hook will be called.

    Code Block
    global.get("hooks").HTMLDirective = msg => {
        node.send(msg);
    };

  5. The next function node calls the HTML form and it is subsequently connected back to the Flow Manager node to continue the conversation flow.

Custom Control usage with bmiCalculator flow

When you drag the Custom control to the Flow Studio canvas, you can see a name field and the control's ID. In Experience Designer, developers can write code that executes when the Custom control is reached.

...

In the Custom Control, note the Custom control Name. In this case “bmiCalculator”

By default, the “Hook-Data” function node is attached to the flow Manager as part of the base project

The “Settings / Hooks initialize” is needed if not already integrated into a global setting.

Note: If you don't have the Hook Data or the corresponding nodes,

  1. In the Experience Designer, create a new flow.

  2. Click on the hamburger menu on the top right corner and navigate to Import > Built-in > Orbita Flows-(BETA) > Flow Manager.

    Image Added
  3. Place the flow on the canvas and Deploy the flow

...


Settings/Hooks Initialize function ( may not be needed if already set in settings function)

Code Block
const settings = global.get("settings") || {};
settings.emptyString = '';
global.set("settings", settings);
const hooks = global.get("hooks");
global.set("hooks", hooks || {});
return msg;

bmiCalculator hook function

Code Block
global.get("hooks").bmiCalculator = msg => {
    node.send(msg);
};

BMI Calculation function

Code Block
var _ = global.get('lodash');
var answers = msg.orbita.session.flowInfo.answerArray;
var weight = _.result(_.find(answers, function(obj) {return obj.name === 'Weight';}), 'value');
var height = _.result(_.find(answers, function(obj) {return obj.name === 'Height';}), 'value');
var bmi = calcBMI(weight, height);
msg.payload.externalHook.data = bmi; 
return msg

function calcBMI(weight, height) {
  return parseInt((weight * 703) / (height * height));
} 

The BMI calculation, sets

msg.payload.externalHook.data with results of the bmi, with the return msg, the msg object is passed back to the flow manager. Although you can pass data back anywhere on the msg object, returning it to msg.payload.externalHook.data , will cause this data to be logged in the answers array as a control result.

Hook Data Function ( only for reference - should already be included in your project)

Code Block
try {
    const _ = global.get('lodash');
        controlId = msg.payload.session.attributes.orbitaSession.flowInfo.controlId,
        controlName = msg.payload.session.attributes.orbitaSession.flowInfo.controlName,
        hookName = controlName.indexOf(":") > - 1 ? controlName.substr(0, controlName.indexOf(":")) : controlName,
        args = controlName.indexOf(":") > -1 ?
            [msg,
             ...controlName.substr(controlName.indexOf(":") + 1).split("|")
                .map(arg => arg.trim())
                .filter(arg => !!arg)
                .map(arg => arg === "null" ? null : arg)] :
            [msg];
    msg.payload.externalHook = {
        data: hookName
    }
    if (hookName) {
        const hook = global.get("hooks")[hookName];

        msg.hookResult = {
            hookFound: !!hook
        };
        
        
        if (hook) {
            hook.apply(null, args);
        } else {
            msg.hookResult.executionSuccess = false;
            msg.hookResult.error = `Could not find hook '${hookName}'`;
        
            node.warn(`Could not find hook '${hookName}'`);
        
            return msg;
        }
    }
    
} catch (error) {
    msg.hookResult.executionSuccess = false;
    msg.hookResult.error = error;
    
    node.warn(`Error executing hook`);
    node.error(error);
    
    return msg;
}

Related Articles

Filter by label (Content by label)
showLabelsfalse
max5
showSpacefalse
cqllabel in ( "flow-studio" , "experience-designer" )

...