Welcome to the OPA Hub!


Category Archives: JavaScript Extensions

JavaScript Extension : Geomapping with Leaflet JS

Hi There!


This content is accessible only to logged in users of the OPA Hub Website.

To Register takes only 10 seconds and uses LinkedIn for authentication.

Once registered you can change your OPA Hub password and manage it independently of LinkedIn.

We recommend you keep different passwords for all your sites.

To register, click the Log in link in the menu at the top of your page.

Thanks, the OPA Hub Website.

Importing Data into an Interview : Excel Example

Importing Data into an Interview : Excel Example

Readers will remember a while ago I explained briefly how to use Microsoft Excel to act as a Connection Datasource – in this overview article, followed by this one in a little more detail. Now we look at another challenge : Importing Data into an Interview.

Well, here comes another example of the ubiquitous nature of Microsoft Excel. The customer requirement was as follows:

Using a simple mechanism, let the user upload an existing Excel spreadsheet into the Interview. Parse the spreadsheet, read the data in it, create corresponding rows in an Entity. Let the user review the data but do not require any new data entry. There may be up to 250 rows of data to import. So how do you go about about Importing Data into an Interview?

So how can we face up to a challenge like that? We need:

  • An upload that isn’t a standard File Upload Group
  • A parsing mechanism to read Excel and extract the data in a given tab, or wherever
  • A custom Entity Collect to handle the data import / create the rows in a Screen

The shopping list above isn’t that long.

The File Upload is essentially an HTML 5 component to let the user select a file on their computer. We cannot access an arbitrary local path from JavaScript, so we need the user to point to the file they want to upload.

There are a number of JavaScript-based Excel parsers, including the excellent SheetJS js-xlsx which we used. It is capable of converting to and from Excel, which is no easy task when you consider that an Excel file is basically a Zip file with a bunch of complicated stuff inside it. The library can convert to HTML, CSV and magically (for our requirement) JSON. Awesome!

Plus, in a previous post we’ve also looked at the (large amount of) work required to build a Custom Entity Collect Extension. In fact when I was writing that article I was thinking, for goodness sake Richard, when do you think you will actually need to go to the trouble of building that Entity Collect Extension? Well, I’ve finally found a use for it – Importing Data into an Interview!

We need an Entity Collect Extension since we need some way of getting the Excel data into the Entity Collect, which ultimately means we need to do some work behind the scenes between the import of the data and the display of the Entity Collect. We need to rewire the Entity Collect temporarily so that it sucks our Excel data up, before we show it to the user so they can examine the results.

For the purposes of a raw demo, I unplugged all the other functionality (delete buttons, add buttons, etc.) and just concentrated on getting the data into the Entity Collect. There are how ever a few caveats. Once you get into the larger imports, at least in the Debugger, you can expect to see “concurrent record editing” errors. I’m trying to find out what the limit is exactly. But up to a few hundred I think it’s OK.

So let’s look at the items in turn.

File Upload and Data Load

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
					//console.log("Starting customInput Mount");
					var div = document.createElement("input");
					div.id = "myFile";
					div.type = "File";
					//div.value = control.getValue();
					el.appendChild(div);
 
					function handleFile(e) {
						var files = e.target.files,
						f = files[0];
						var reader = new FileReader();
						reader.onload = function (e) {
							var data = new Uint8Array(e.target.result);
							//console.log("In Change");
							var workbook = XLSX.read(data, {
									type: 'array'
								});
 
							worksheet = workbook.Sheets["YOURWORKSHEET"];
							jsonoutput = XLSX.utils.sheet_to_json(worksheet, {
						raw: true, header : 1
							});
						//console.log("Read " + jsonoutput );
						};
 
						reader.readAsArrayBuffer(f);	
						var completepath = $(':file').val();
							//console.log(completepath);
						interview.setInputValue("rest_filenameandpath", completepath);
					}
 
 
				var filedialog = document.getElementById("myFile");
					filedialog.addEventListener('change', handleFile, false);
 
					var completepath = $(':file').val();
						control.setValue(completepath);
						//console.log("Hello " + completepath);
						//console.log("Ending customInput Mount");
				}

Assuming you have a custom Input framework as your starting point, the above code will be in the mount. This will build an HTML5 file upload control, and attach an event handler. The code regarding Excel depends upon xlsx.full.min.js being in the resources directory. But that’s it. You’ve loaded the Excel file into a JSON object.

Entity Collect

The next step is to include a Custom Entity Collect in your project, and use the jsonoutput object (which you just created from the imported file above) in the mount of the Entity Collect to load the JSON into the Entity Collect. The following is an extract from the mount code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var numEntities = Object.size(jsonoutput);
					//console.log(numEntities);
					// Remove header row if the file has one
					jsonoutput.shift();
					// load records into the Entity Collect
 
					if (control.getRows() == 0) {
						for (j = 0; j < numEntities - 1; j++) {
							control.addNewRow();
							var mycurrentrecords = control.getRows();
							mycurrentrecords[j][0].setValue(jsonoutput[j][0]);
							mycurrentrecords[j][1].setValue(jsonoutput[j][1]);
							mycurrentrecords[j][2].setValue(jsonoutput[j][2]);
							mycurrentrecords[j][3].setValue(jsonoutput[j][3])
drawrows();

The end result is something like this:

Importing Data into an Interview

The File is loaded into the Entity Collect, and the contents displayed to the user. In my case I unhooked all the code related to modification (the onchange stuff from the original idea) and removed the add / delete buttons, since it was designed to just allow the user to see the loaded result, not modify it.

Importing Data into an Interview

If you want to have a look at the project, just download the very basic example here.

Calendar Black Out Dates with Control Extensions

Calendar Black Out Dates with Control Extensions

The OPA Hub Website is always happy to hear from readers and learn about the things they are doing and trying to do. In this case, this article was inspired by our reader AF, from Adelaide. The question was; how can we implement a calendar control, to allow the users to select a date – but the calendar control must be able to black-out certain dates (public holidays, non-work days). It’s the sort of thing we probably can all relate to.

The Calendar control that Oracle Policy Automation uses is a very standard JavaScript dropdown, but there is little in the way of configuration in respect of the dates shown. We can style the calendar and we can offer two different ways to enter dates (either as the traditional calendar or the three-fields-in-a-row style that some applications use).

So it comes down to what can be done with an Extension. Regular reader will remember that we have spoken about calendar controls before, on the subject of Year-Only Selection. So that Extension will be the basis of this article.

Firstly, what are the tools we might need?

  • jQuery
  • JQuery UI, especially datepicker

The datepicker widget from jQuery supports a variety of user-related events, including one called BeforeShowDay, which is where we can come in a specify which days should not be clickable. They remain in the calendar display of course.

The basic concept therefore, for this demonstration is:

  1. The user can select a date from the control. Certain days are not available.
  2. The control must handle both adding a date when the date is not currently entered, as well as when the date is already entered and the user wants to correct it (for example, going back to a previous screen in the interview.
  3. The date must of course be saved to our chosen attribute.

As always this is without any warranty or guarantee of fitness for purpose. It’s a quick demonstration that you can then add to and correct yourselves.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
 * Richard Napier The OPA Hub Website March 2019
 * Educational Example of Custom Date Control Extension
 * I will remember this is for demonstration purposes only
 */
OraclePolicyAutomation.AddExtension({
	customInput: function (control, interview) {
		if (control.getProperty("name") == "xDate") {
			return {
				mount: function (el) {
 
					var myDatePicker = document.createElement('input');
					myDatePicker.setAttribute("id", "dateselect");
					var mySessionDate = interview.getValue("dt_session");
 
 
					el.appendChild(myDatePicker);
 
 
					$('#dateselect').datepicker({
						dateFormat: "yy-mm-dd",
						onSelect: function (dateText) {
							var RecoveredDate = dateText;
 
							interview.setInputValue("dt_circ", RecoveredDate);
 
						},
						beforeShowDay: function (date) {
							var array = ["2019-03-14", "2019-03-15", "2019-03-16"]
							var string = jQuery.datepicker.formatDate('yy-mm-dd', date);
 
							return [array.indexOf(string) == -1]
						}
					});
 
					var mySelectedDate = "";
 
					if (interview.getValue("dt_circ") == null) {
 
						$('#dateselect').datepicker("setDate", mySessionDate);
						var RecoveredDate = mySessionDate;
 
						interview.setInputValue("dt_circ", RecoveredDate);
 
 
					} else {
 
						var myPreviouslySelectedDate = new
							Date(interview.getValue("dt_circ"));
 
 
						var myPreviouslySelectedDateAsDate = new
							Date(myPreviouslySelectedDate);
 
						var myDayPrefix = "";
						var myMonthPrefix = "";
						if (myPreviouslySelectedDateAsDate.getDate() < 10) {
							myDayPrefix = "0"
						}
						if (myPreviouslySelectedDateAsDate.getMonth() < 10) {
							myMonthPrefix = "0"
						}
						var myConvertedYear = myPreviouslySelectedDateAsDate.getFullYear();
						var myConvertedMonth = myPreviouslySelectedDateAsDate.getMonth() + 1;
						var myConvertedDay = myPreviouslySelectedDateAsDate.getDate();
						var myPreviouslySelectedDateOnly =
							myConvertedYear + "-" + myMonthPrefix + (myConvertedMonth) + "-" + myDayPrefix + myConvertedDay;
 
 
						mySelectedDate = myPreviouslySelectedDateOnly;
 
 
						$('#dateselect').datepicker("setDate", mySelectedDate);
 
 
						var RecoveredDate = $('#dateselect').datepicker("getDate");
 
						interview.setInputValue("dt_circ", new Date(RecoveredDate));
					}
				},
				update: function (el) {},
				unmount: function (el) {
					var RecoveredDate = $('#dateselect').datepicker("getDate");
 
					interview.setInputValue("dt_circ", new Date(RecoveredDate));
 
					var myPicker = $('#dateselect');
					myPicker.remove();
 
 
				}
			}
		}
	}
});

Calendar Black Out Dates with Control Extensions – About the Code

The first part of the Mount is basically setting up the jQuery datepicker to be able to hide some days. We also set the date format to the international YYYY-MM-DD that we all know. Of course a more sophisticated approach would check the region and apply the correct format.

Line 22 Sets up the Select Event and Line 29 the BeforeShowDay  Event.

We attempt to grab the value of our user-entered date (dt_circ) and place it in the date control. If that is unknown or null, then we will default to the current date.

When the user selects a valid date, we will of course copy it into the attribute again.
Finally, when the Unmount fires, we will clean up.

The End Result

 

In a later post we will look at using an entity to store the blackout dates. Stay tuned! For the time being the Project is in the OPA Hub Shop.

Custom Options : Hierarchical Lists

Hi There!


This content is accessible only to logged in users of the OPA Hub Website.

To Register takes only 10 seconds and uses LinkedIn for authentication.

Once registered you can change your OPA Hub password and manage it independently of LinkedIn.

We recommend you keep different passwords for all your sites.

To register, click the Log in link in the menu at the top of your page.

Thanks, the OPA Hub Website.

Custom Options : Dynamic List of Values

Hi There!


This content is accessible only to logged in users of the OPA Hub Website.

To Register takes only 10 seconds and uses LinkedIn for authentication.

Once registered you can change your OPA Hub password and manage it independently of LinkedIn.

We recommend you keep different passwords for all your sites.

To register, click the Log in link in the menu at the top of your page.

Thanks, the OPA Hub Website.

Template Generator Update – JavaScript for Control Extensions

Template Generator – JavaScript for Control Extensions

Another update, quite a big one, for the template generator. We’ve added lots more information to explain how to use the generator, and hopefully how to work on the template once you have created it. In addition, we have added the Entity Container as a new extension type, so you can create scrollbar-friendly lists of instances for your Entities. Read on for more information. If you just want to download the new version leave a comment and I will send it to you. In the not too distant future we will be releasing it to the OPA Hub Shop, but for now just ask and we can pass it to you.

Control Extension Template Generator : New Form Available

If you don’t intend to use the template code straight away, you can now just print the Form and keep it for later. At the moment the form just dumps the code in plain text, it does not pretty-print it like the screen output, but the code is still ready to copy-and-paste.

Control Extension Template Generator : Information Added

In the Form, we have included some hopefully useful background information about using the code, what to look out for and what to know in terms of where you might want to customize the code. We’ll keep adding to this Form as time goes on, with anything we think might be useful.

Control Extension Template Generator : New Extension

You can now generate Entity Container Extensions. This template requires an extra Property and uses jsGrid to provide a scrolling layout. Again, more information is given in your Form about how to use it and how to customize it to go even further. As always, the official documentation is your friend.

Control Extension Template Generator : Example Container

New Video

And so, to close, you will find below a short video explaining the new Extension Template for Entity Containers, and giving you a bit more background about the different aspects of this Extension type. Nothing beats having a go yourself. Of course, as we always say, the code is entirely for entertainment purposes, never for production, and it’s your own fault if you don’t get a professional to rewrite it. But at least you will know that it can be done, and as a consultant that is often one of the most important things to know.

The video can be viewed here:

Entity Collect Extension

Entity Collect Extension

Some time ago I wrote about Entity Collect Extension and the challenges of writing a demonstration piece of code. The challenges of Entity Collect Extension are pretty well known, but here is a run down of the most important one:

  • You must build the container and the contents,  and manage them

That means, that if you build an Entity Collect Extension, you cannot use other control extensions inside it :- you must code the entire contents yourself, so you would be looking at

  • Handling all different data types of attribute
  • Handling all the basic events of these attributes
  • Managing instance creation and deletion
  • Handling styling options and look and feel

So when you look at this shopping list, it can be quite daunting. Even so, I said to myself, if Oracle provides such a functionality, then somebody somewhere is going to use it. And so the idea came to create a demonstration Entity Collection Extension. When I started working on it I really did not have much time to look at it, so I wrote a couple of articles about my experiences and left it at that.

Recently I have been revisiting the concept again, and have found  time to work on it a little bit more. I added it to the OPA Hub Shop (on the strict understanding, as usual, that it is completely for educational and amusement purposes only).

That statement is particularly important in this case. I only decided to do this because I am fascinated by other people’s JavaScript frameworks. I find it useful to know what goes on underneath the glossy Oracle Policy Modeling HTML output. And my example is basic to the point of being little more than a sandbox (oh, and by the way, it still has a lot of issues – especially when you are running it in the Debugger rather than the Browser).

Entity Collect Extension in JavaScript

This version tries to cover off the 4 shopping list items shown above, and adds a couple of interesting ideas

  • Dynamic Delete Button (remove the button based on an attribute value). This is one request I have seen many times – the ability to forbid deleting in certain circumstances.
  • Handling Date Time and Value Lists for display and data entry.

I still have to find time to investigate :

  • Handling Inferred attributes that need to be refreshed as you are entering instance attributes.

I’ve just about had enough of this now so I am going to leave it for a while.  It has started to make my head spin.  Nonetheless it is an interesting exercise and helped make clear how cool the out of the box JavaScript really is.

The silent movie below shows where I’m at. All that work, for this rather dull looking thing. Sometimes there is not much to show for efforts. Of course, if I was a real programmer, I would be doing all of this in a much more efficient way (avoiding complete page refreshes at every change and so on) but I found this exercise very interesting. Certainly it gives me a better understanding of the scale of such a task.

Have a nice day!

Showing a Loading Image During Entity Creation

Showing a Loading Image During Entity Creation

When a user is entering some information into Entity attributes, it is entirely possible that one of those entity attributes may take its information from a Search extension. For example, you are entering instances of the Person entity and each Person has a location, so you want to select the location using a Search extension.

The Search, given that it is perhaps an Ajax call, could take some time. So you want to signal to the user that there is nothing to worry about, but they need to wait. Typically this is done through some sort of icon or image being displayed, much in the style of the Windows egg-timer or similar. This probably will also need a CSS style rule or two, in order to make it a bit funky.

We want to make sure that this is displayed in the right place, even if the user is creating several instances of the same entity. I mean that the icon should be displayed in the correct area of the screen, especially if you have instances whose screen layout takes up some space.

Anyway as always a picture is worth a thousand words. Here is the instance collection form:

Showing a Loading Image During Entity CreationWhen you have several on the screen, it might look like this:

Showing a Loading Image During Entity Creation

The Destination attribute is a Search extension that helps the user search for a Train Station in the United Kingdom. It take a few seconds for the search to happen.

So our timer needs to be shown in the right place whenever the user is searching. It needs to be instance A or B for example, depending on the instance the user is working on.

Showing a Loading Image During Entity Creation

In the example above the user has typed the Search criteria. The loader is shown in the centre of the instance while the search is happening. So we are Showing a Loading Image During Entity Creation.

Showing a Loading Image During Entity Creation

When the search data is returned, as in the example above, the user should no longer see the loader and the operation can continue as normal.

If the user moves to another instance, then the process should start again but the loader should be instance-aware and show in the correct place so as not to confuse.

Showing a Loading Image During Entity CreationTo do this we can use the Search extension, and add a little bit of extra code to

  • Check to see if we have already displayed the special icon
  •  If we have not, create it, center it on the instance we are working on, show it and make the Search
  • If the icon already exists, move it to the correct instance and show it then make the Search
  • When the search data is returned, hide the icon until the next time.

This example will work with non-tabular forms. I’ll be back with a second post investigating them in a couple of days.

You can find this simple example (with all the usual caveats and reminders that this is just for fun) in the OPA Hub Shop.  The official documentation is here, as always. Thanks to Shankar for the great example of Showing a Loading Image During Entity Creation!

Siebel CRM as a custom Search source

Hi There!


This content is accessible only to logged in users of the OPA Hub Website.

To Register takes only 10 seconds and uses LinkedIn for authentication.

Once registered you can change your OPA Hub password and manage it independently of LinkedIn.

We recommend you keep different passwords for all your sites.

To register, click the Log in link in the menu at the top of your page.

Thanks, the OPA Hub Website.

Travel Compensation : JavaScript Extensions

Travel Compensation : JavaScript Extensions

Many of our readers will be familiar with the Example Projects (which include Travel Compensation)  that are provided with the download of Oracle Policy Modeler. If you are not, they are accessible here:

OPA 12 - Travel Compensation Example Access

If you are not familiar with them, we encourage you to dive right in and to find out about all the wonderful examples you can find in there. It is a great learning tool and a good way to discover potential use cases. One of the more famous ones is the Project related to the legislation relating to Travel Compensation by Airlines, in the European Union (EU261/2004), mentioned above.

This allows the traveler to receive a compensation amount when their flight is delayed or they are refused boarding (among various criteria)  if the flight meets certain conditions (there are various exclusions for territories such as Gibraltar and so on).

The Project

The provided example Project has a number of key learning points :

  1. The project has multiple translation files
  2. The project is mapped to a RightNow Connection
  3. The project uses the CurrentLocale() functions introduced in 18C
  4. It uses a number of Excel tables to maintain static data.
  5. It links to various websites for example to calculate distances.

The existence of Translation files is a good chance for new started to discover how multiple interfaces are built inside Oracle Policy Automation 12, and the mapping to RightNow has two side effects (even if you do not have access to the RightNow instance specified in the Connection).

OPA 12 - Travel Compensation Example RightNow Dialog

Firstly if you have never seen the RightNow-specific (as opposed to the generic Web Service Connection dialog) window, it can come as a bit of a shock. If you need a primer as to what the different icons mean, you can check out our series about Service Cloud (RightNow) and OPA. The second side effect is the long set of Value Lists that are drawn down from Service Cloud as part of the Connection (even if they are not being used here).

OPA 12 - Travel Compensation Example Value Lists

We mentioned the arrival of locale-detection functions in our What’s New post a few weeks ago. The two most interesting things, and the point of this post, is the fact that Excel is used to store static data (in the case below, airline names and countries)

OPA 12 - Travel Compensation Example Excel Sheet

and that some of the information to be entered is referenced using URLs : in the case below, the need to calculate a distance between two airports:

JavaScript Extensions : Airports, Airlines and Great Circle Mapping for Travel Compensation

In the example Project, the focus is on a clear definition of the Policy and a demonstration of how to implement a good design pattern. But the end user experience suffers a bit – this is not a criticism, since it obviously was not the learning focus – because of the kind of data to be entered.

Take for example the first screen, where we enter our journey details : departure and arrival airports. Given that the airport information is extremely useful (namely, every airport has an ICAO code, and a latitude and longitude), we are going to use a custom Search to let the user find the airport and we will capture some extra information : the Country and the ICAO code. The Country is used later in the rules, and the ICAO code will come in very handy in a moment.

OPA 12 - Travel Compensation JavaScript Search Extension Airports

We’ve actually two versions. The first version uses a website called http://geonames.org : they have a variety of free (registration required) web services for searching for places including airports. It does not have ICAO codes but has a lot of other information. The second version uses a freemium web service from https://market.mashape.com/marcusgoede/great-circle-mapper/ which includes an airport search which additionally returns an ICAO code. Both of them return the Country.

A later page asks for the name of the Airline : again we decided to use a custom Search, from a website called https://aviation-edge.com which has a variety of web services including an Airline lookup which includes the operating country (which is referenced in the rules).

OPA 12 - Travel Compensation JavaScript Search Extension AirlinesFinally, the legislation bases compensation in part on the kilometer distance of the flight. It must be calculated using the Great Circle method according to the law, this method takes into account the curvature of the earth. We returned to the freemium web service listed above to take advantage of the airport to airport Great Circle mapping Web Service, which also can return duration (based on a supplied average airspeed) and many other nuggets of information.

OPA 12 - Travel Compensation JavaScript Label Extension Distance

For the above example we use a custom Label (which is not displayed) which drops the calculation into the Input box so the user can adjust it if required (but our tests proved it to be very accurate indeed).

As such, these three extensions increase the data entry speed and make the process much simpler. So there you have it, some examples of useful JavaScript extensions. The Project now looks like this:

You can find them in the OPA Hub Shop as usual, search for Travel Compensation. Don’t forget the official Oracle Policy Automation Developer Guide Interview Extensions Reference.