Tag: Custom Control

Stunning Infographics with Oracle Policy Automation and Easelly #2

Stunning Infographics with Oracle Policy Automation and Easelly #2

So, in this part of the series we will look at how to integrate Easelly with Oracle Policy Automation. For this integration demonstration we chose to use the older Custom Control concept. In today’s Oracle Policy Automation, most of the customization of the user experience is driven through the JavaScript Extensions – which we regularly demonstrate on this site. But there are situations where the Custom Control concept from pre-August 2016 versions is still a good choice. In this case, we need a Custom Label, with a link. But the link is to be displayed once the server-side has generated a PDF file. So it is a good choice. For the language, PHP is easy to use, has thousands of examples, and can handle both XML and JSON.

Let’s look at the code then walk through it step by step. The code is also in the shop, for free, because this code viewer does not do a very good job of handling all the characters in the file.

// Copyright The OPA Hub Website 2019
// For entertainment and education purposes only
// Example step by step PHP Custom Control and integration with Easelly Infographic
// Requires Easelly API Key 
// Thanks to Johanna and Vernon at Easelly easel.ly

//Set up a few key variables
$url = "https://www.easel.ly/pages/generatePDF";
// This is your API Key
$api_key = "XXXXXXX";
// This is the URL of your base infographic in Easelly
$canvas_id = "https://XXXX/easel.ly/all_easels/XXX/XXX";

// OPA data is passed into the PHP file as a  urlencoded XML post header. Decode it
$myOPAData = $_POST["opa-session"];
$decodedOPA =  urldecode ($myOPAData);

// Now we can manipulate it as XML
$final = new SimpleXMLElement($decodedOPA);

// Get the XML Nodes that represent our OPA Attributes using XPath queries

$account_name = $final->xpath("//*[@id='account_name']");
$product_one_name = $final->xpath("//*[@id='product_one_name']");
$product_one_avail = $final->xpath("//*[@id='product_one_avail']");
$product_one_margin = $final->xpath("//*[@id='product_one_margin']");
$product_one_trans_lost = $final->xpath("//*[@id='product_one_trans_lost']");

// Get Text of each OPA Attribute 

$account_name  = strip_tags($account_name[0]->asXML());
// Some Product Names have & in them so convert the characters properly
$product_one_name  = htmlspecialchars_decode ((strip_tags($product_one_name[0]->asXML())));
$product_one_avail  = strip_tags($product_one_avail[0]->asXML()) . "%";
$product_one_margin  = strip_tags($product_one_margin[0]->asXML());
$product_one_trans_lost  = strip_tags($product_one_trans_lost[0]->asXML());

// Build Object Array for the Easelly REST API. Each object represents an Easelly tagged item, mapped to an OPA attribute.

$myJSONdata = new stdClass();
$myJSONdata->id = "https://s3.amazonaws.com/easel.ly/all_easels/706616/SwanFoodsExample";
$myJSONdata->objects = array();

$myobjectfinal = new stdClass();
$myobjectfinal->tag = "account_name";
$myobjectfinal->type = "textbox";
$myobjectfinal->text = $account_name;
$myobjectfinal->fill = "#f9d423";

array_push($myJSONdata->objects, $myobjectfinal);

$myobjectfinal = new stdClass();
$myobjectfinal->tag = "product_one_name";
$myobjectfinal->type = "textbox";
$myobjectfinal->text = $product_one_name;
$myobjectfinal->fill = "#6bb38e";

array_push($myJSONdata->objects, $myobjectfinal);

$myobjectfinal = new stdClass();
$myobjectfinal->tag = "product_one_avail";
$myobjectfinal->type = "textbox";
$myobjectfinal->text = $product_one_avail;
$myobjectfinal->fill = "#f9d423";

array_push($myJSONdata->objects, $myobjectfinal);

$myobjectfinal = new stdClass();
$myobjectfinal->tag = "product_one_margin";
$myobjectfinal->type = "textbox";
$myobjectfinal->text = $product_one_margin;
$myobjectfinal->fill = "#ffffff";

array_push($myJSONdata->objects, $myobjectfinal);

$myobjectfinal = new stdClass();
$myobjectfinal->tag = "product_one_trans_lost";
$myobjectfinal->type = "textbox";
$myobjectfinal->text = $product_one_trans_lost;
$myobjectfinal->fill = "#ffffff";

array_push($myJSONdata->objects, $myobjectfinal);

// Convert the Object to JSON

$myJSONdataobject = json_encode($myJSONdata);

//Call Easelly with our JSON Object and Get Response

$context = stream_context_create(array(
			'http' => array(
				'method' => 'POST',
				'header' => "apiKey: {$api_key}\r\n".
				"Content-Type: application/json\r\n",
				"Accept' : application/json\r\n",
				'content' => $myJSONdataobject)));
$response = file_get_contents($url, FALSE, $context);

// Check Output

if ($response === FALSE) {
	die('An Error Occurred');
// Use a timestamp as the filename
$time = time();
$fileoutputname = $time . ".pdf";
file_put_contents($fileoutputname , $response);

// Show the Link to the User for clicking to access the generated file
<a target="_blank" href="https://theopahub.com/main/external/<?php echo $fileoutputname ?>"
>Click Here</a>

Walk Through

The code has been broken down into it’s constituent parts – for learning purposes. Of course there are many areas that would be rewritten in a professional example, but this will help non-coders understand what is going on.

  • 1-15, Set up some basic stuff like the URL to your infographic. In the final part of this series, I’ll show you how to build a graphic and tag it correctly with the OPA attribute.
  • 17-25 The Oracle Policy Automation Custom Control integration passes the session data (your attributes and their values) into the PHP page as a series of XML nodes. So we need to get that XML and make sure we can read the parts we are interested in.
  • 29-25 We strip the attribute values out of the XML, and in one case, because the OPA attributes contain special characters like “&” we make sure they display properly.
  • 38-80 Overly simplified for the purposes of demonstration, we build a JSON object using standard objects and arrays, to create the JSON structure that Easelly is looking for. In the next part of this series I will show you where to get it.
  • 84 Convert the Object into a JSON Object
  • 88-106 Call Easelly with our API Key and JSON Object
  • 107 – End Process the output and draw the link for the user


Oracle Policy Automation and Easelly

So you can see the integration is fairly simple in this case – the PDF is generated before the user reaches the link, so the link should respond straight away. And we chose PDF but Easelly also can generate PNG for example, if you wanted to embed it directly as an image.

In the third part of this series, we will show you how to get Easelly to tag your infographic so you can use it in an Oracle Policy Automation integration.

Detail Pop-up in Oracle Policy Automation

Detail Pop-up in Oracle Policy Automation

The other day someone came to me with a curious and interesting problem. They had a number of entity instances, inferred in an Excel spreadsheet. These had to be displayed in the usual way with an Entity Container in a Screen of Oracle Policy Modeller. So far so good, I hear you say.

Detail Pop-up in Oracle Policy Automation 1

The inferred attributes (which in the end would probably be coming from a data source, but for now come from Excel as inferred instances) included a Text attribute that was frankly far too large to display correctly in the Screen, given that there might be a few rows of instances in the final result.

We experimented with lots of different layouts, dynamically hiding and showing items based on various criteria in order to make room, but in the end we came to the conclusion that we needed some sort of Detail Pop-up in Oracle Policy Automation – something that could be called upon by the user as and when they needed it, but ignored (and invisible) when not needed.

Here is the starting point for our adventure.

The Screen above is populated with all the instances of the student’s scholarship. On the left is a set of information that we need to display on request. Normally we will only display the name of the Scholarship. You will see in the list of attributes there is an overview ( a text attribute), a deduction ( a currency attribute) and a renewable status (a boolean attribute). There are a few others, including the contact details (a text attribute, which is a URL).

So we are going to customise the label control I have just described. It is “inside” the Entity instance loop : so in reality there will be one per instance. We need our label to contain, as you would expect, the correct information. We wish to avoid pop-ups (nasty!) and dialogs (too complex for a simple window) and tool-tips are too small and simple for the data we have. The label shown will have a custom property called “name” and will be used as a hook for our JavaScript Extension.

We experimented with all sort of things before we went for this option : JavaScript is a last resort. We were frustrated by the behaviour of hidden items that appeared slowly (we could see “uncertain” appearing before the out of the box JavaScript populated the bound controls). So it was going to be JavaScript.

So,  our Detail Pop-up in Oracle Policy Automation needs to meet these challenges. We are going, as a simple demonstration, to use a CSS toggle to show or hide the relevant data for our instances. We can set the scene as follows:

.area {

.area:hover {
cursor: pointer;

.fixed {

The above CSS file sets up two main classes and a pseudo-class for a mouse hovering over our row. The area is the area we will normally show – with just the name – and the fixed area is a fixed DIV which will display (or not) when we decide we want to visualise the information. Now for the main content of our customLabel extension. Here is the mount key with as usual, my simplistic attempts at coding : for the umpteenth time I’m not a professional – but my job is to show something can be done, and let other’s get on with making it happen.



if (control.getProperty("name") == "xLabel") {
return {
mount: function (el) {
var maindiv = document.createElement("div");
maindiv.style.visibility = 'visible';
maindiv.innerHTML = interview.getValue("scholarship_award", "scholarship", control.instance);
maindiv.setAttribute("id", interview.getValue("scholarship_award", "scholarship", control.instance));

var tooltipdiv = document.createElement("div");
tooltipdiv.style.visibility = 'visible';
tooltipdiv.innerHTML = control.getCaption();
tooltipdiv.setAttribute("id", interview.getValue("scholarship_award", "scholarship", control.instance));

$("div [id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").click(function () {
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").html("<h6>Name : " + interview.getValue("scholarship_award", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6>Overview : " + interview.getValue("scholarship_overview", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6><b>Renewable</b>: " + interview.getValue("scholarship_renewable", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6><b>Maximum Value</b>: " + interview.getValue("scholarship_deduction", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6><b>Eligibility</b>: " + interview.getValue("scholarship_eligibility", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6><b>Minimum Grade</b>: " + interview.getValue("scholarship_min_grade", "scholarship", control.instance) + "</h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").append("<h6><b>Contact</b>: <a href='" + interview.getValue("scholarship_contact", "scholarship", control.instance) + "' target='_blank'>SFAS Office</a></h6>");
$(".fixed[id='" + interview.getValue("scholarship_award", "scholarship", control.instance) + "']").toggle();


Here is the review of the Detail Pop-up in Oracle Policy Automation code shown above, starting with the usual check to make sure we are only working with our label and not any other label on the Screen. In lines 6 to 11 we add a new DIV (to replace the one that contained all those %substitution%s , and we populate it with only one attribute. Since that attribute is also unique, we use it as a handy way to populate the HTML id attribute.

In lines 13 to 18 we create a second, hidden DIV that uses the fixed class shown above.

In lines 20 to 29 we set up the click event so that the user can click on the label and the hidden text will be revealed. The code preview (I notice) has eaten the ending part of the line, so use the PDF version instead. Notice the use of getValue, with the entity name and the instance, to ensure that we create a DIV with a unique name and unique content. The content will be toggled (hidden or shown) when you click on it.

Finally the unmount is very standard, cleaning up our various pieces by removing them.

if (control.getProperty("name") == "xLabel") {

The end result looks like this, before the click:

Detail Pop-up in Oracle Policy Automation 3And after the click:

Detail Pop-up in Oracle Policy Automation 4

Our Detail Pop-up in Oracle Policy Automation prototype gives the user the information they need when they need it. Of course it can be extended and transformed into something much less ugly, but this is a good start. You can find the PDF in the Shop, it’s free!

Custom Year Picker JavaScript Extension Example

Custom Year Picker JavaScript Extension Example

Continuing in our random series of examples of using the Oracle Policy Automation JavaScript Control Extension API, this one came up the other day. How to allow the user to only enter a year in a calendar? The data type underneath fully expects there to be a day, month and year to complete the picture, but suppose you are entering an attribute such as “Year of Registration” and the business rule states that the product is always registered as of January 1st of that year. We can call it a Custom Year Picker JavaScript Extension.

Of course as always there are many ways to achieve this, and JavaScript is definitely not the only solution. As good citizens of the Oracle Policy Automation world, we should always try and reach our goals without resorting to scripting unless it is completely necessary. Since this is supposed to be an article about the technique rather than the business requirement, let’s push on and find out how you might do it.

Firstly, there are a couple of pre-requisites. This example uses jQuery, and jQuery UI plugin called, unsurprisingly perhaps given the topic, Year-Select. I am sure there are a multitude of different plugins or tools to do this. Year-Select has the advantage of being super small and easily styleable. In addition it requires minimal coding to get it to work. Two good reasons to use it for this example. Download the file and place it in your folder. Add the jQuery files that you can download from the official site.

Now your resources folder will probably look like this : note the three external files (two from jQuery and “yearpicker.js” for the Year Picker) and your own custom JavaScript file that you are about to create “datepicker.js”. For this example, you should also create the following

  1. A Word document with a global goal that relates to couple of date attributes
  2. The two date attributes just mentioned that you should also create. Give them names as well.
  3. A label which displays these pieces of information.
  4. A date control on the Screen with a custom Property called name, value “xDate” or anything else you might like to use instead. This is similar to the other examples already described on this site.

Here are the images to help you work all that out. First the screen, with the Date control and the two attributes in the label:

Custom Year Picker JavaScript Extension Example

And secondly, the actual content of the Word document. You will notice that I am just trying to usefully have two attributes, one which is the session timestamp (which we can use when the Interview starts up, to default the Year Picker to the current year, for example) and the second attribute is going to store the selected value chosen by the user.

For the avoidance of doubt, in this Custom Year Picker JavaScript Extension Example, dt_sess is the name given to the date of the session and dt_circ is the name given to the date of registration.

On to the JavaScript code. As usual this will take the form of several different sections. In the first mount section we will

  • Create an Input control, which is the basis of our Year Picker
  • Get the Session Timestamp
  • Convert it to a Date object
  • Extract the Year
  • Apply the magic CSS class and call the yearselect.js code to intialise the jQuery UI widget

Custom Year Picker JavaScript Extension Example

  • If the date of registration has no value, then set the value to the year of the Session Timestamp, January 1st (since this was the requirement)
  • If the date of registration already has a value – because someone has already edited the year in this Interview session, then get that value and apply it to the Year Selector

Custom Year Picker JavaScript Extension Example

That’s quite a lot going on there. Most of the code is actually spent getting the actual date from the attribute and converting it into something JavaScript believes is actually a Date. Then looking to see if the date is already set, and updating the picker control.

As usual the code is absolutely filled with console logging, and the code is willfully non-optimized in order to make it as easy to read as possible for someone who just wants to know what it does. The final parts of the code handles if the user decides to update the year with the picker, and the usual unmount clears the element from the DOM.

Custom Year Picker JavaScript Extension Example

Now, in your debug session if you have added a new Screen, you can flick back and forth between the End Screen and your New Screen to observe the changes. Your new Custom Year Picker JavaScript Extension should be up and running like the following screenshot.

Custom Year Picker JavaScript Extension Example

The OPA Hub Shop – Download the Script for Custom Year Picker JavaScript Extension Example

And now for some good news (I got a lot of requests for this!). The code example, and all the other code examples, are free to download in the OPA Hub Website Shop as PDF files.

Remember if you have any ideas for examples, or you want to contribute your own, just leave a comment below!

Oracle Policy Automation -JavaScript Custom API : Google Maps

Oracle Policy Modelling – OPA Custom Control : Google Maps

The other day I was confronted with a requirement to display Google Maps within an Interview. The requirement was not window-based or dialog-based : the Google Map had to be in the main HTML Interview. I was using the August 2017 release, and thus able to us the Control Extension API in JavaScript. Here is a quick tutorial for this OPA Custom Control (using the new Extension API).

The example is so generic that I thought I would share it with you. As before this example is just for educational purposes and there are lots of steps that were synthesised in the end after some refactoring, but is easier to show the long and wordy version here for educational reasons.

Firstly, let’s make the OPA Custom Control Project and set up the simple attributes and Screens.

OPA Custom Control - Attributes

Then we can build out the two Screens.

OPA Custom Control Map Screen

The map screen is just, for the moment, a Screen that is always displayed (because in this demonstration project we will not be doing any logic in rules).

OPA Custom Control Data Collect

The preceding screen, we will collect the information we need to display : firstly the visible details and secondly the latitude and longitude in the Location options of the Screen.

OPA Custom Control Value List

In this demonstration project, the incident type will have a value list, with four choices. These will correspond to four different icons from the Google Maps standard icon list. The list I was able to view from this site, and download the files needed for the demo. They were placed in the usual folder of our OPA Custom Control project, as shown below.

OPA Custom Control Images

We’ll make some adjustments to the Map Screen, adding all the attributes we intend to use in the demonstration, using the public names and substitution tags.

OPA Custom Control Map Elements

The label that will be the basis for the map, and as you can see it needs (for this demonstration) a custom property, as shown below:

Now we can bring in the JavaScript file, using the Oracle Policy Automation Extension API to extend the label control. Now you will add the JavaScript file that will be the basis of the control, by clicking the Custom Files button in the Styles.. dialog.


OPA Custom Control Extension API Add File

Our file will use the standard framework of all the JavaScript Extensions (See earlier posts here and here).

The content of the file, extended for the purposes of illustration, begins here, with three main areas of interest.

  1. Creating the script tag to load the Google Maps library
  2. Do the same to create an empty container for the future map
  3. Obtain the latitude and longitude from our project.

Continuing with our script, the entire mount, as you can see at the top of the previous image, is preceded by a check for our custom Property.

OPA Custom Control Extension API Map Setup

TIP : If you are planning on implementing only this customLabel, and you want to display other labels using the standard rendering, then you should put  your custom property if statement right to the top immediately after the customLabel: line, and wrap everything in this if statement so that the entire script will be ignored for ordinary labels.

The next chunk is mostly setting up the Google Map functionality

4. These are the icons that will be used in the different types of incident. We use the $() notation to avoid fixed references to folders.

5. This is the callback function used when Google Maps has loaded

6. This actually loads the map

7. You can build an array of elements if you intend to display multiple markers. Here you will just use the one, with the latitude and longitude garnered earlier and the incident type.

OPA Custom Control Map Label

8. For each of the loaded points, create a marker and add it to the map,

9. With a click event to handle the user interaction

10. The click event will display a dynamic content, in a typical Google Maps information box.

11. Finally as good citizens we will implement the unmount which will remove the Map when we leave the page, avoiding errors about multiple maps being loaded.

The interview experience gives us the following lovely rendering when you enter the details and pass to the Map Screen.

The icon will change depending on the type of incident, and the information box will display whatever attribute values you wish to show.

If anyone is interested in obtaining the JavaScript code for learning purposes, please leave a comment. Note that remove() is not compatible with all browsers, and the Internet Explorer embedded in the Debugger will not like it. But open the Debugger with Ctrl+F5 in your real browser and it will work (for a list of supported browsers see here).


OPA 12 – Interview Screen with no Buttons

OPA 12 – Interview Screen with no Buttons

A colleague asked me an interesting theoretical question about an Interview Screen with no Buttons last week. Much of the detail I will skip and just get right to the things that he was adamant about!

  • He wanted an interview with a single Screen
  • He wanted an Interview Screen with no Buttons
  • There should be no JavaScript
  • The conclusion should auto-calculate when the data is entered

We all love a challenge don’t we? So the objectives proved to be by and large achievable, although for the final point my solution was not at first accepted, but with a bit of arm-twisting it passed muster. So let’s look at the steps to bring this to fruition, in a simplified case.

I first create my Project in Oracle Policy Modeler and then add my rules. In this case, since there was a mathematical calculation involved, there really was, from the user perspective, one answer to be obtained. Asking the user to click a Submit button did feel a bit like overkill.

After adding all the requisite parts to the (only ) Interview Screen with no Buttons, we have something like the following screenshot:

OPA 12 - Single Screen Example Interview Screen with no Buttons

And the Debug session will provide the following, utterly non-interactive output:

OPA 12 Single Screen Debug Interview Screen with no Buttons

Assume for the case in point that the two inputs are the drivers of the goal. The goal, which was placed on the only Screen in the Interview editor above, never displays since there is no button. You cannot go forward or backward or submit or anything else. Since it is the first and the last Screen, no buttons are allowed anyway. And my colleague said no buttons!

So what’s the answer?

Add a custom control, that contains only HTML (no JavaScript, remember!). The custom control is just a snippet of HTML that looks and feels just like an OPA button, but is invisible. The custom control is required since the HTML button tag is not white-listed by OPA, so if you try and add the HTML tag to your interview Screen manually, you will get an error. But as a custom control, no problem. Upload the custom control to your favorite Web Server.


Plant a label on your Interview Screen and edit it so that it is using your Custom HTML file, as shown in the two steps below. Remember that you first add the Label, then you change “Normal” to “Custom” in the Ribbon. Please note that inline styling like that style=”display : none !important;” HTML attribute is not a good idea, but I did it here for the sake of brevity.

OPA 12 - Add Label Custom Control Interview Screen with no Buttons

So now we have a form, with a Submit button. And you can probably guess what is going to happen when you run the Interview in the Debugger. Our Interview Screen will display as before. But this time, enter some data in the Input boxes, and press Enter when you are ready to get the answer. The Interview Screen behaves just like an everyday HTML form and the Enter key submits the form, the Submit fires and we get our answer.

Logo by Southpaw Projects LLC