Javascript Overview

Within XpertRule Knowledge Builder, the developer can create custom procedures and command blocks to perform runtime procedural tasks.

Procedure code is written in the JavaScript language.

For those familiar with JavaScript, the only addition is that of a dictionary lookup identifier which allows (knowledge base) objects to be referenced more intuitively.

For readers more accustomed to working with the XpertRule commands a mapping has been provided to help in the transition.

Setting dictionary values

XpertRule Commands

@ASSIGN Grade = 'Director'

XpertRule JavaScript

#Grade.val("Director");
Notes

#Grade : This shortcut is translated into JavaScript code which retrieves the "Grade" object from the dictionary.
.val(<value>) : This method of the dictionary object (in this case the "Grade" object) sets its value.

Getting dictionary values

XpertRule Commands
@IF ( Grade = 'Director' )
XpertRule JavaScript
if ( #Grade.val() == "Director" )
Notes

.val() : If no parameter is passed to the val method, it returns the current value of the dictionary object.

Tips

In JavaScript there is a difference between using the equals sign as a comparator and an assignment. e.g.

if ( a == 57 )

    Check to see whether a is equal to 57

a = 57

    Assigns the value of a to be 57

The comparator for an "if" statement MUST be contained in brackets

Showing Messages

XpertRule Commands
@DEBUG 'Hello World'
Standard JavaScript
alert("Hello World");
XpertRule JavaScript
xpertrule.message('Hello World');
Notes

xpertrule : The "xpertrule" object contains a number of helpful methods to enable the developer to achieve specific functionality which traditionally came from @commands.
.message(<contents>[,<title>]) : Display a message. An optional second parameter can be used to change the title of the message box.

Executing Objects

XpertRule Commands
@DO Expenses
XpertRule JavaScript
#Expenses.run();
Notes

.run() : Execute an XpertRule object. This could be a tree, a procedure, a dialog etc.

Tips

As "run" is a method, the open and close brackets are required.

Executing Procedures (extension of object execution)

Procedures are called in the same was as any other Knowledge Builder object. e.g.

#MyProcedure.run();
Values can be returned from a procedure with the JavaScript return statement. e.g.

MyProcedure definition

return 42;
Calling procedure
var retVal = #MyProcedure.run();

Conditional Code Blocks (if command)

XpertRule Commands
@IF Grade = 'Director'
  @ASSIGN Department = 'Boardroom'
  @DEBUG 'Boardroom location'
@ELSEIF Grade = 'Senior Manager'
  @ASSIGN Department = 'Management'
  @DEBUG 'Management office'
@ELSE
  @ASSIGN Department = 'Office'
  @DEBUG 'General office'
@ENDIF
XpertRule JavaScript
if (#Grade == "Director") {
  #Department.val("Boardroom");
  xpertrule.message("Boardroom location");
} else if (#Grade == "Senior Manager") {
  #Department.val("Management");
  xpertrule.message("Management office");
} else {
  #Department.val("Office");
  xpertrule.message("General office");
}
Notes

Command blocks in JavaScript are denoted by open and close braces {}

Again, note the use of the double equals sign == to test equality

Looping (for command)

XpertRule Commands
@DIM loop:n
@FOR loop = 1 TO 10
  @ASSIGN strArr[loop] = 'Empty'
@NEXT
XpertRule JavaScript
var loop;
for ( loop = 1 ; loop <= 10 ; loop = loop + 1 ) {
  #strArr.val()[loop] = "Empty" ;
}

Alternatively, a more optimized version...

for ( var loop = 1 ; loop <= 10 ; loop++ )
#strArr.val()[loop] = "Empty" ;
Notes

If there is only a single command in the command block, the braces {} are not required.

To increment a number, you can use the ++ syntax (there's also -- for decrement)

Clearing Values

XpertRule Commands
@Clear Grade
XpertRule JavaScript
#Grade.clear();
Tips

As with the run method, note the () after the method name.

Checking if an Object has a Value

XpertRule Commands
@IF ( Grade.isempty )
XpertRule JavaScript
if ( #Grade.isEmpty() )
Tips

JavaScript is CaSe SeNsItIvE. XpertRule JavaScript methods names are in "Lower Camel Case". So the isEmpty method name has a lower case initial "i" and an upper case "E" as it's a separate word.

Local Variables

XpertRule Commands
@DIM aName:s
XpertRule JavaScript
var aName;
Tips

JavaScript is a type-less language so there is no need to specify that the aName local variable is a string.

Indirect Referencing

XpertRule Commands
@DIM aName:s
@ASSIGN aName = 'Grade'
@ASSIGN !(aName) = 'Director'
XpertRule JavaScript
var aName = "Grade";
dictionary.findObject(aName).val("Director");
Notes

We define a local variable called "aName" (note the trailing semicolon)

dictionary : The "dictionary" object allows the developer to access the knowledge module's dictionary of objects

findObject(<object name>) : Get a reference to specified dictionary object. Note that this is quite an expensive (in terms of processing time) operation. If the same referenced object is accessed more than once in the code, it is preferable to store the object in a local variable. e.g.

var aObject = dictionary.findObject("Grade");
if ( aObject.isEmpty() )
  aObject.val("Director");

Encode Data

XpertRule Commands
@ENCODEDATAXML aStr
XpertRule JavaScript
#aStr.val(xpertrule.encodeData());
Notes

encodeData([<object array>[,<add captured attributes>]]) : Encode the relevant objects into an XML message (string) and return that string.

If you wish to specify specific objects to include in the message, you specify them as an OBJECT ARRAY as the first parameter. e.g.

xpertrule.encodeData([#Grade,#Department])

Note that an array is passed by using the square brackets, also, objects are passed (not names).

You could alternatively use the dictionary.findObject method to look up objects to pass although this would be slower e.g.

xpertrule.encodeData([dictionary.findObject("Grade"),dictionary.findObject("Department")])

If you need to include all the captured objects in addition to the specified objects, you can pass "true" as the second parameter e.g.

xpertrule.encodeData([#Grade,#Department],true)

URL Fetch

XpertRule Commands
@URLFETCH 'http://localhost/temp/temp.php',retStr
XpertRule JavaScript
var dataObj = xpertrule.urlFetch('http://localhost/temp/temp.php');
Notes

The urlFetch method returns a JavaScript object. This object has 2 properties...

data : The data returned from the HTTP request
success : A boolean indicating whether the request was successful

Tips

Once the call is complete, you can use the retuned object's properties thus...

var dataObj = xpertrule.urlFetch('http://localhost/temp/temp.php');
if (dataObj.success)
  xpertrule.message(dataObj.data);
else
  xpertrule.message("Error");

Object Properties

XpertRule Commands
@IF Grade.description = ''
  @ASSIGN Grade.description = 'Boss Type'
@ENDIF
XpertRule JavaScript
if (#Grade.props.description == "")
  #Grade.props.description == "Boss Type";

alternatively

if (#Grade.prop("description") == '')
  #Grade.prop("description","Boss Type");
Notes

The first snippet uses the props object to access the object control properties. This should be quite self-explanatory.

You'll see that the second snippet uses the prop method. This can be called with 1 or 2 parameters...

.prop(<object control property name>) Get the value of the specified object control property
.prop(<object control property name>, <new value>) Set the value of the specified object control property to the new value.

n.b. If setting a new value (either via the props object or the prop method), the TYPE of the new value must be the same as the XpertRule object control property type. e.g.

Set a string type property: .prop("help", "Foo Bar")
Set a numeric type property: .prop("minvalue", 22)
Set a boolean type property: .prop("allowblank", true)

Object Value Properties

Get the number of object instance properties...

XpertRule Commands
@IF Grade.nValues = 1
XpertRule JavaScript
if (#Grade.nValues == 1)

You can also retrieve the array of object instances via the value function...

var valArr = #Grade.value();

So an alternative way of getting the number of object instance properties would be...

if (#Grade.values().length == 1)

Or get an individual value...

var dirVal = #Grade.value(1)

n.b. The object returned from the value function (or array of objects if no parameter passed) are instances of the following object...

{
  aName: string /*The internal name of the value*/
  selected: boolean /*Is this value selected*/
  valid: boolean /*Is this value valid*/
  hidden: boolean /*Is this value hidden*/
  [Instance Prop Name]: <type from xpertrule> /*User defined instance property*/
}

Example. If the display text of the FIRST instance value's runtime text is empty then set it to a value

XpertRule JavaScript
if (#Grade.inst("displaytext",1) == '')
  #Grade.inst("displaytext",1,"Big Boss Person");

Or, get the instance property value of the CURRENT selected value...

xpertrule.message(#Grade.inst("displaytext"));
Notes

You'll see that the inst method can be called with 1, 2 or 3 parameters...

.inst(<object instance property name>) Get the value of the specified object instance property for CURRENT value instance
.inst(<object instance property name>, <instance index>) Get the value of the specified object instance property for specified instance
.inst(<object instance property name>, <instance index>, <new value>) Set the value of the specified instance control property for specified instance to the new value. Specifying an <instance index> or 0 sets the property on the currently selected value.

n.b. If setting a new value, the TYPE of the new value must be the same as the XpertRule object instance property type. (see Object Control Properties for more details)

Modifying the Object's Values

The existing methods to modify the object instances are also supported in JavaScript

XpertRule Commands
@DO Grade.ClearInstances
@DO Grade.AddInstance('Big Boss')
@DO Grade.DelInstance(4)
XpertRule JavaScript
#Grade.clearInstances();
#Grade.addInstance("Big Boss");
#Grade.delInstance(4);

There is an optional second parameter for the dictionaryObject.addInstance method...
#Grade.addInstance("Big Boss", {DisplayName: "Big Boss Person"});
If supplies, the javascript object is used to populate the instance properties of the newly added value. The above example assumes that the Grade object has an instance property called DisplayName of type string.
The type of the object property must match the instance value property, e.g. if the Grade object also has an Age instance property (of type integer), this could be set with...
#Grade.addInstance("Big Boss", {DisplayName: "Big Boss Person", Age: 45});

jQuery Tricks and Tips

With the use of the new OnShow dialog event, you can achieve some cool extras in your UI design.

The OnShow procedure is called once the dialog controls have been created for the first time. At this point you can retrieve a jQuery reference to any control on your dialog with the following selector (from an XpertRule procedure)...

var el = $("#myControlName");

The # means "find the element by id" and as the element ID is the same as the control name, you can find any of your controls.

If you wish to use a dialog element for your own use, it's a good idea to use a label control with the caption set to "__EMPTY__". This instructs the engine to NOT populate the control with the specified text (as the population of controls happens periodically from AFTER the OnShow event).

If the label caption is set to "__EMPTY__" then you can manually set the control's contents via the jQuery "html" method. So to extend our previous code...

var el = $("#myControlName");
el.html("This is <a>some text set via jQuery</a>");

We can also do cool stuff like animate the showing of the controls...

el.hide();  // start with the control hidden
el.show("slow"); // show the control "slowly"

Additional ideas...

Scroll controls onto the dialog (with the jQuery animate method)...

el.css('left','-100px').animate({left: '100'}, 2000);

The full jQuery reference can be found on the jQuery web site