article by Frank Nimphius, June 2019

 

ES 6, known as ECMA Script 2015 or JavaScript 6, introduced the concept of destructuring for creating variables and assigning values to them. Destructuring, as an expression, reads values ​​from arrays and objects and assigns them to variables. Custom components in Oracle Digital Assistant support JavaScript destructuring and custom component developers may use this syntax to assign component input parameter values to variables. This article explains destructuring variable-assignments in custom components and points out the benefits.

Using Destructuring  in Custom Components

Destructuring in JavaScript works with arrays and objects. Input parameters defined on a custom component are passed as an object returned by the custom component SDK's  conversation.properties() function. Using the default component template*) of the Oracle Bots Node SDK, you see the following content generated for your new custom component. 

const { human } = conversation.properties();

What this code does is, it uses destructuring to create a new constant variable with the name human and populates it  with the value of the "human" property in the object response of a call to the conversation.properties() function. Another way of writing above assignment would be using the traditional way:

const human = conversation.properties().human;

But if the above works, why changing it? Well, destructuring  comes with some benefits:

  • Less code to write
  • Easier to read
  • Ability to set default values (!) for input parameters
  • Ease of assigning variable names different from the input parameter name

*) You can customize the default component template used by the Oracle Bots Node SDK, following this Oracle TechExchange .

Using Destructuring to Set Default Values

Input parameters are defined in the custom component metadata() function as shown below. 

metadata: () => ({

    name: 'oda.sample.DestructuringAssignments',
    properties: {
      variable: {required: true, type: 'string'},
      name: {required: false, type: 'string'},
      age: {required: false, type: 'int'},
      mail: {required: false, type: 'string'}      
    },
    supportedActions: []
  })

The metadata section does not allow you to define default values for parameters. So despite that all except one parameter are marked as optional, there is no way to define a default value. Here destructuring becomes very handy. If, for example, the age property should be defaulted to 18, then you could use the following assignment. 

const { age = 18 } = conversation.properties();

Or, if you wanted to default the mail input to no-reply@acme.com

 const { mail = 'no-reply@acme.com' } = conversation.properties();

The "traditional" equivalent of this code would be

const mail = conversation.properties().mail ? conversation.properties().mail : 'no-reply@acme.com' ;

Still you may be a fan of the "traditional" style and don't bother the extra characters to write. But, lets then have a look how destructuring can populate two variables at once

const { age = 18, mail = 'no-reply@acme.com' } = conversation.properties();

See the differences it makes? And in the example metadata() function I showed 4 input parameters. This clearly is where destructuring wins over the traditional way of assigning values to variables.

Handling the "Zero Input-Parameters" Case

Now that – hopefully – you are convinced of destructuring for variable assignments, you need to be made aware of a special situation, which is when no input parameters are passed by the bot designers (and I am not talking about passing null values for an input parameter).  For example, the following custom component definition 

module.exports = {
  metadata: () => ({
    name: 'oda.sample.DestructuringAssignments',
    properties: {
      variable: {required: true, type: 'string'},
      name: {required: false, type: 'string'},
      age: {required: false, type: 'int'},
      mail: {required: false, type: 'string'}      
    },
    supportedActions: []
  })

Allows the custom component to be referenced in BotML as 

But wait. The variable property is flagged as "required", so how can no input parameter be passed? Well, the "required" setting matters to the validator in the BotML designer. So pressing the validate button in the dialog flow builder shows the following error:

Still, bot designers may decide to ignore the problem and release the skill. At runtime, the "required" statement does not cause an error unless the custom component developer checks if required parameters got a value and if not throws an error.

But, let's get back to the use case in which no input parameter is provided for a component. In this case the properties() function is not getting exposed on the conversation object in the custom component code and destructuring cannot be performed. To handle this case, you need to add some code that checks the existence of the properties() function. The code below defines a _default object that holds the values of the default values. Later, the assignment uses conversation.properties() || _defaults to either assign the value of the conversation.properties() object or the default object. 

module.exports = {

  metadata: () => ({
    name: 'oda.sample.DestructuringAssignments',
    properties: {
      variable: { required: true, type: 'string' },
      name: { required: false, type: 'string' },
      age: { required: false, type: 'int' },
      mail: { required: false, type: 'string' }
    },
    supportedActions: []
  }),
  invoke: (conversation, done) => {
    /* ... defining the default settings ... */
    var _defaults = { name: "Jim Ben", age: 28, mail: 'jim@acme.com' };    

   /* ... using destructuring to create and populate variables ... */
    var { variable = _defaults.variable , name = _defaults.name, age = _defaults.age, mail = _defaults.mail } = conversation.properties() || {};

    conversation.reply('The input: name =  ' + name + ' ... age = ' + age);
    conversation.transition();
    conversation.keepTurn(true);
    done();
  }
};

 

Note: The code above defined a variable "_defaults" that holds an object with the default values. You could also have the variable assignment defined as:
var { variable, name = 'Jim Ben', age = 28, mail = 'jim@acme.com' } = conversation.properties() || {}; 

 

With the above code, the following BotML configuration produces the following results:

  1. No parameter set



    Produces the following output containing the default values set for name and age


     
  2. The "name" value set



    With this setting, the default value will be used for "age" and the input parameter value for "name"

  3. Both values are set in BotML



    This time, both values are read from the input parameters

Anything More To Know?

Yes. Lets assume you want to split the variable declaration and the value assignment (for whatever reason).

So you want to put it this way:

//defining the variables
var variable, name, age, mail;
// ... do other stuff
//assign values to variables use destructuring
{ variable = _defaults.variable , name = _defaults.name, age = _defaults.age, mail = _defaults.mail } = conversation.properties() || {};

This doesn't work – and does not even allow you to import the custom component to the local skill container – because the destructuring code line is neither an assignment nor a valid expression.

So what you need to do, to make this work, is to wrap the destructuring directive in brackets: "(" and ")"

//defining the variables
var variable, name, age, mail;
// ... do other stuff
//assign values to variables use destructuring
({ variable, name = 'Jim Ben', age = 28, mail = 'jim@acme.com' }) = conversation.properties() || {};

Notice the two changes:

  1. The destructuring assignment is enclosed in brackets. 
  2. The default values could not be read from the "_defaults" object as this is out of scope for the expression as it is now enclosed by brackets. As you can see in the code above, the default values are set directly in the destructuring definition. 

Related Content

MDN Webdocs – Destructuring assignment

TechExchange: How-to Build Card Layout Responses from Custom Components

TechExchange – Real World Insight into KeepTurn and Transition in Intelligent Bots

Custom Component Development with Oracle Bots Node.js SDK

TechExchange – Debugging Custom Components

 

 

 

Author