Rules¶
Rules are JavaScript modules that can be used to add application functionality using ES5 or ES6 syntax.
Syntax¶
ES5 Syntax¶
Only ES5 default exports are supported.
For example, this module exports two functions AlwaysFalse
and AlwaysFalse2
. AlwaysFalse
is the default export and AlwaysFalse2
is a named export. Currently only AlwaysFalse
is available directly to the application.
function AlwaysFalse() {
return false;
}
function AlwaysFalse2() {
return false;
}
// export option #1 using default ES5 syntax
module.exports.default = {AlwaysFalse};
// export option #2 using named ES5 syntax
module.exports.AlwaysFalse2 = {AlwaysFalse2};
ES6 Syntax¶
Only ES6 default exports are supported.
For example, this module exports two functions AlwaysTrue
and AlwaysTrue2
. AlwaysTrue
is the default export and AlwaysTrue2
is a named export. Currently only AlwaysTrue
is available directly to the application.
// export option #1 using default es6 syntax
export default function AlwaysTrue() {
return true;
}
// export option #2 using named es6 syntax
export function AlwaysTrue2() {
return true;
}
NativeScript Framework Modules¶
MDK provides a set of NativeScript Framework Modules that can be accessed on any Client API object using a well known property name. Each Client API property maps to a NativesScript Framework Module.
Use the provided links to view NativeScript Framework details.
ClientAPI Property Name | NativeScript Module |
---|---|
nativescript.appSettingsModule | ApplicationSettings |
nativescript.connectivityModule | Connectivity |
nativescript.fileSystemModule | FileSystem |
nativescript.platformModule | Platform |
nativescript.uiDialogsModule | Dialogs |
nativescript.utilsModule | Utils |
nativescript.applicationModule | Application |
Example¶
export default function SomeRuleFunction(anyClientAPI) {
// Obtain a reference to the NativeScript Platform Module
const platformModule = anyClientAPI.nativescript.platformModule;
if (platformModule.isAndroid) {
console.log("You are using Android device");
}
const applicationModule = anyClientAPI.nativescript.applicationModule;
console.log("Current device appearance: " + applicationModule.systemAppearance());
// return value: "dark" | "light" | null
// For Android, the value returned would be based on device settings. When the app is in force light UI mode, and the device appearance is in 'dark' theme, the value returned on Android for this `applicationModule.systemAppearance()` is still 'dark'.
// To get the current appearance of the app, please refer to getAppearanceMode client API.
}
The ClientAPI objects¶
The exported rule function will be given a ClientAPI object as an argument. Through this object, the rule function can query application state and data.
The ClientAPI
object implements the IClientAPI interface or one of its sub-interfaces (or Proxies). The specific interface type will depend on the context the rule is executed from. For example, if the rule is executed in the context of a Page (as is the case for an "OnPageLoaded" rule), it will receive a PageProxy instance as its ClientAPI object. (Note that IPageProxy extends IControlContainerProxy which in turns extends IClientAPI).
Example¶
export default function OnPageLoaded(pageProxy) {
// The rule function can use the pageProxy object here. This
// object will have all of its APIs ...
pageProxy.setCaption('A new page caption');
// ... as well as all of the IClientAPI methods
pageProxy.executeAction('/App/Actions/SomeAction.action');
// ... can set the action bar item #2 to hidden.
pageProxy.setActionBarItemVisible(1, false);
}
IClientAPI
¶
The IClientAPI is the base interface for all objects passed to rule functions.
IControlProxy
¶
The IControlProxy is the interface of the object passed to a rule function, when the rule is ran in the context of a control.
IControlContainerProxy
¶
The IControlContainerProxy is the interface of the object passed to a rule function, when the rule is ran in the context of a control container.
IFormCellProxy
¶
The IFormCellProxy is the interface of the object passed to a rule function, when the rule is ran in the context of a Form Cell.
IFormCellTargetProxy
¶
The IFormCellTargetProxy is the interface of the object returned to a rule function, when the rule executes the IFormCellProxy::getTargetSpecifier()
method.
IPageProxy
¶
The IPageProxy is the interface of the object passed to a rule function, when the rule is ran in the context of a Page.
ISectionedTableProxy
¶
The ISectionedTableProxy is the interface of the object passed to a rule function, when the rule is ran in the context of a Sectioned Table.
ISectionProxy
¶
The ISectionProxy is the interface of Sections.
ILinkSpecifierProxy
¶
The ILinkSpecifierProxy is the nterface of the object returned to a rule function, when the rule executes the IClientAPI::createLinkSpecifierProxy() method.
ILoggerManager
¶
The interface of the object returned to a rule function when the rule executes the IClientAPI::getLogger()
method.
export interface ILoggerManager {
// Toggles the state of the Logger "on"/"off"
toggle(): Promise<any>;
// Turns logging "on"
on(): Promise<any>;
// Turns logging "off"
off(): Promise<any>;
// Returns whether the logger is turned on
isTurnedOn(): boolean;
// Gets the logging level. See below for values
getLevel(): string;
// Sets the logging
// Valid logging levels are:
// 'Trace', 'Debug', 'Info', 'Warn', and 'Error'
public setLevel(logLevel: string): Promise<any>;
// Logs a message.
// Severity is one of the logging levels mentioned above.
public log(message: string, severity: string): Promise<any>;
// Uploads the log file
public uploadLogFile(backendURL: string, applicationID: string): Promise<any>;
}
IToolbarProxy
¶
The IToolbarProxy is the interface of the object passed to a rule function when the rule is ran in the context of a Toolbar container.
IToolbarItemProxy
¶
The IToolbarItemProxy is the interface of the object passed to a rule function when the rule is ran in the context of a Toolbar Item.
IActionResult
¶
The IActionResult is the interface of the object passed to a rule function when the rule is ran in the context of an Action.
Rules Examples¶
Getting the value of a collection based control¶
This example uses the IControlProxy.getValue()
interface in a Control.Type.FormCell.SegmentedControl
control.
// Control definition
{
"_Name": "SegmentedFormCell",
"_Type": "Control.Type.FormCell.SegmentedControl",
"Caption": "Priorities",
"OnValueChange": "/MDKApp/Rules/SegmentControlChange.js",
"Segments": [
"Low",
"Medium",
"High"
],
"Value": "Low"
}
// Whenever a new selection is made
// "/MDKApp/Rules/FormCell/SegmentControlChange.js" is called:
// SegmentControlChange.js
export default function FormCellSegmentedChangeHandler(controlProxy) {
let selections = "";
// getValue returns an array of Objects in the form:
// [{SelectedIndex:value, ReturnValue:value}, ...]
controlProxy.getValue().forEach((selectedItem) => {
selections += selectedItem.ReturnValue + '\n';
})
console.log(selections); // Log all selections to the control
alert(controlProxy.getValue()[0].ReturnValue); // Alert with the first selection
}
Changing PickerItems programmatically¶
This example uses the IFormCellProxy.setTargetSpecifier()
interface to change
picker items programatically.
// Control definition
{
"_Name": "SegmentedFormCell",
"_Type": "Control.Type.FormCell.SegmentedControl",
"Caption": "high via rule",
"Segments": [
"Low",
"Medium",
"High"
],
"Value": "Low",
"OnValueChange": "/MDKApp/Rules/FormCell/UpdateListPickerItems.js"
}
// Whenever the a new segmented button is selected
// "/MDKApp/Rules/FormCell/UpdateListPickerItems.js" is called
export default function UpdateListPickerItems(controlProxy) {
// selection is the selected SegmentedControl value
let selection = controlProxy.getValue()[0].ReturnValue;
let containerProxy = controlProxy.getPageProxy().getControl('FormCellContainer');
if (containerProxy.isContainer()) {
// get a proxy to the Control.Type.FormCell.ListPicker instance
let listPickerProxy = containerProxy.getControl('ListPickerFormCellSingle');
let specifier = listPickerProxy.getTargetSpecifier();
specifier.setDisplayValue("{OrderDescription}");
specifier.setEntitySet("MyWorkOrderHeaders");
specifier.setReturnValue("{OrderId}");
specifier.setService("/MDKApp/Services/Amw.service");
// set the query options for the list picker based on SegmentedControl Value
switch (selection) {
case 'Low':
specifier.setQueryOptions("$top=5");
break;
case 'Medium':
specifier.setQueryOptions("$top=10");
break;
case 'High':
specifier.setQueryOptions("$top=15");
break;
}
}
listPickerProxy.setTargetSpecifier(specifier);
}
Changing ObjectCell PickerItems programmatically¶
This example uses the IFormCellProxy.setTargetSpecifier()
interface to change
picker items (ObjectCell) programatically.
// Control definition
{
"_Name": "SegmentedFormCell",
"_Type": "Control.Type.FormCell.SegmentedControl",
"Caption": "high via rule for ObjectCell",
"Segments": [
"Low",
"Medium",
"High"
],
"Value": "Low",
"OnValueChange": "/MDKApp/Rules/FormCell/UpdateListPickerObjectCellItems.js"
}
// Whenever the a new segmented button is selected
// "/MDKApp/Rules/FormCell/UpdateListPickerObjectCellItems.js" is called
export default function UpdateListPickerObjectCellItems(controlProxy) {
let selection = controlProxy.getValue()[0].ReturnValue;
let containerProxy = controlProxy.getPageProxy().getControl('FormCellContainer');
if (!containerProxy.isContainer()) {
return;
}
let listPickerProxy = containerProxy.getControl('ListPickerFormCellObjectCellSingle2');
let specifier = listPickerProxy.getTargetSpecifier();
specifier.setObjectCell({
Title: "{OrderDescription}",
Subhead: "{OrderId}",
DetailImage: "/MDKApp/Images/workorder.png"
});
specifier.setReturnValue("{OrderId}");
specifier.setEntitySet("MyWorkOrderHeaders");
specifier.setService("/MDKApp/Services/Amw.service");
switch (selection) {
case 'Low':
specifier.setQueryOptions("$top=5");
break;
case 'Medium':
specifier.setQueryOptions("$top=10");
break;
case 'High':
specifier.setQueryOptions("$top=15");
break;
}
listPickerProxy.setTargetSpecifier(specifier).then(() => {
listPickerProxy.setValue(['4000189']);
})
}
Logging Examples¶
These examples show how to use the logging interfaces inside the rules.
// Initialize logger by rule
// Ideally used when the application starts
export default function InitializeLoggerRule(clientAPI) {
const logFileName = 'LogFile.txt';
const maxFileSizeInMegaBytes = 8;
// If the logger has already been initialized, it has no effect.
// FileName and fileSize are optional values, if not specified, default values will be used.
clientAPI.initializeLogger(logFileName, maxFileSizeInMegaBytes);
// You can even initialize logger state and level
let logger = clientAPI.getLogger();
logger.on();
logger.setLevel('Info');
}
// Or you can even use this
// Initialize logger by rule which calls an action
export default function InitializeLoggerWithCallingAnAction(clientAPI) {
return clientAPI.executeAction('/MDKApp/Actions/Logger/SetState.action');
}
// Use the logger by rule (it should have been already initialized)
// Available functionality:
// Log a message, Edit log level, Edit state (turn on/off), Get current logger state,
// Get current root log level, Upload log file
export default function UseLoggerRule(clientAPI) {
// Get logger instance
let logger = clientAPI.getLogger();
// Returns a boolean according to current logger state (on=true, off=false)
logger.isTurnedOn();
// Turns off the logger
logger.off();
// Turns on the logger
logger.on();
// Toggles the logger state (on/off)
logger.toggle();
// Returns the current logger root level. Possible values: Debug, Info, Warn, Error, Off
logger.getLevel();
// Sets the logger root log level. Possible values: Debug, Info, Warn, Error, Off
logger.setLevel('Info');
// Logs a message with the specified log level.
// If log level is not specified, the root log level will be used.
const optionalLogMessageLogLevel = 'Debug';
logger.log('This is a test message', optionalLogMessageLogLevel);
//Log uploading works only after successful authentication
// Upload the log file according to client settings
clientAPI.executeAction('/MDKApp/Actions/Logger/Upload.action');
// Upload log file according to own settings
logger.uploadLogFile(backendURL, applicationID);
}
Setting links using rule¶
This example shows how to use the ClientAPI.createLinkSpecifierProxy()
interface to set links.
// Definition
{
"_Type": "Action.Type.ODataService.UpdateEntity",
"Target": {
"EntitySet": "MyWorkOrderHeaders",
"Service": "/MDKApp/Services/Amw.service",
"ReadLink": "{@odata.readLink}"
},
"Properties": {
"OrderDescription": "#Control:OrderDescription/#Value",
},
"UpdateLinks": "/MDKApp/Rules/OData/UpdateLinkRule.js"
}
export default function UpdateLinkRule(ClientAPI) {
let containerProxy = ClientAPI.getControl('PageOneFormCell');
let listPickerProxy = containerProxy.getControl('EquipmentList');
let queryOption = '';
// odata action expects link array
let links = [];
if (listPickerProxy.getValue().length > 0) {
let selectedValue = listPickerProxy.getValue()[0].ReturnValue;
queryOption = `$filter=EquipId eq '${selectedValue}'`;
let link = ClientAPI.createLinkSpecifierProxy('EquipmentHeader', 'MyEquipments', queryOption, '');
links.push(link.getSpecifier());
}
return links;
}
Setting Toolbar item property value using rule¶
This example shows how to use the IToolbarItemProxy.getParent().getToolbarControls()
interface to get the array of toolbar items and set the property value.
// Definition
{
"Caption": "Dynamic toolbar item value based on rule",
"Controls": [],
"ToolBar": {
"Controls": [
{
"_Name": "DynamicItem",
"_Type": "Control.Type.ToolbarItem",
"Caption": "/MDKApp/Images/off.png",
"Image": "/MDKApp/Images/off.png",
"OnPress": "/MDKApp/Rules/Toolbar/SetToolbarItemValue.js"
},
...
]
}
}
// Rule
export default function SetToolbarItemValue(controlProxy) {
var toolbarItems = controlProxy.getParent().getToolbarControls();
var imageOn = '/MDKApp/Images/on.png';
var imageOff = '/MDKApp/Images/off.png';
var imageOnText = 'AddedAsFavorite';
var imageOffText = 'RemovedFromFavorite';
var newValue, newText;
toolbarItems.forEach(function (element) {
if (element.name == controlProxy.getName()) {
if (element.name == 'DynamicItem') {
newText = imageOnText;
newValue = imageOn;
if (element.caption == imageOnText) {
newText = imageOffText;
newValue = imageOff;
}
element.setCaption(newText);
element.setImage(newValue);
/*
The properties that rule writer is allowed to set and get are:
//SET
element.setCaption(newValue); // text
element.setStyle(newValue); // style
element.setImage(newValue); // image
element.setSystemItem(newValue); // 0 - 22 (more details on Apple Developer website - https://developer.apple.com/documentation/uikit/uibarbuttonsystemitem)
element.setWidth(newValue); // integer
element.setEnabled(newValue); // boolean
element.setVisibility(newValue); // visible/hidden/collapse
element.setItemType(newValue); // Button/Normal
//GET
element.name;
element.clickable;
element.caption;
element.enabled;
element.visibility;
element.width;
element.systemItem;
element.itemType;
*/
return controlProxy.executeAction('/MDKApp/Actions/Toast/' + newText + '.action');
}
}
});
}
Using feedback indicators in ObjectTableSections¶
This example shows how to use the feedback indicator for downloading/opening documents + how to properly call the ISectionProxy.setIndicatorState()
interface to update the feedback indicator in ObjectTableSections.
// Definition
{
"_Name": "SectionedTable",
"_Type": "Control.Type.SectionedTable",
"Sections": [
{
"_Type": "Section.Type.ObjectTable",
"ObjectCell": {
"ProgressIndicator": "/MDKApp/Rules/ProgressIndicator/SetIndicatorState.js",
"DetailImage": "/MDKApp/Images/compressor.png",
"Description": "{Description}",
"Footnote": "{MimeType}",
"StatusText": "{FileName}",
"SubstatusText": "/MDKApp/Rules/OData/IsMediaLocal.js",
"Subhead": "{DocumentID}",
"Title": "{ObjectKey}",
"OnPress": "/MDKApp/Rules/ProgressIndicator/DownloadOrOpenDocument.js"
},
"Target": {
"EntitySet": "BDSDocuments",
"Service": "/MDKApp/Services/Amw.service"
}
}
]
}
// Rules
export default function DownloadOrOpenDocument(sectionedTableProxy) {
const pageProxy = sectionedTableProxy.getPageProxy();
let bindingObject = pageProxy.getActionBinding();
let readLink = bindingObject["@odata.readLink"];
let serviceName = '/MDKApp/Services/Amw.service';
let entitySet = 'BDSDocuments';
// first we need to decide if the media exists locally or needs to be downloaded
return sectionedTableProxy.isMediaLocal(serviceName, entitySet, readLink).then((result) => {
if (result) {
// the media has been downloaded, we can open it -> the path needs to be provided in the action definition
// or it should come from binding
// persist the media data to local sandbox, so we can open it with the document viewer
let fs = require('@nativescript/core/file-system');
const actionBinding = pageProxy.getActionBinding();
if (typeof actionBinding === 'undefined') {
return pageProxy.executeAction('/MDKApp/Actions/OData/ODataDownloadFailure.action');
}
let key = actionBinding['@odata.readLink'];
let filename = actionBinding.DocFile;
if (typeof filename === 'undefined' || filename === '') {
filename = actionBinding.FileName;
}
if (typeof filename === 'undefined' || filename === '') {
filename = actionBinding.SaveDocFile;
}
if (typeof filename === 'undefined') {
// Document filename not found. proceeding with a test filename.
filename = "res://TestOpenDocument.pdf";
}
const filepaths = filename.split('/');
const filelastSegment = filepaths[filepaths.length - 1];
filename = filelastSegment;
if (key) {
var tempDir = fs.knownFolders.temp();
var tempPath = fs.path.join(tempDir.path, filename);
var tempFile = fs.File.fromPath(tempPath);
tempFile.writeSync(pageProxy.getClientData()[key], err => {
return pageProxy.executeAction('/MDKApp/Actions/OData/ODataDownloadFailure.action');
});
pageProxy.setActionBinding({
'FileName': tempPath,
});
return pageProxy.executeAction('/MDKApp/Actions/Document/OpenRelatedDocument.action');
}
} else {
// The media is on the server, we can download it
const pressedItem = pageProxy.getPressedItem();
// get the object table section proxy, which contains the feedback indicators and performs download/open in order to update the indicator state
const objectTableSection = sectionedTableProxy.getSections()[0];
// set the indicator's state to in progress and start the download
objectTableSection.setIndicatorState("inProgress", pressedItem);
sectionedTableProxy.executeAction("/MDKApp/Actions/OData/DownloadDocumentStreams.action").then((result) => {
// success case
// the document was successfully downloaded, we can set the indicator's state to open
objectTableSection.setIndicatorState("open", pressedItem);
}, (error) => {
// error case
objectTableSection.setIndicatorState("toDownload", pressedItem);
sectionedTableProxy.executeAction("/MDKApp/Actions/OData/ODataDownloadFailure.action");
});
}
});
}
export default function SetIndicatorState(sectionProxy) {
let bindingObject = sectionProxy.getBindingObject();
let readLink = bindingObject["@odata.readLink"];
let serviceName = '/MDKApp/Services/Amw.service';
let entitySet = 'BDSDocuments';
// first we need to decide if the media exists locally or needs to be downloaded
return sectionProxy.isMediaLocal(serviceName, entitySet, readLink).then((result) => {
if (result) {
// The media is saved locally, we can open it
return 'open';
} else {
// The media is on the server, we can download it
return 'toDownload';
}
});
}
Localization and Formatting in rule¶
setLanguage client API function is to set the app language (for in-app language setting implementation). For iOS, the app need to be restarted to fully take effect, it's advisable for app to inform user to restart app after changing the language.
// Languages related API
export default function ManageLanguages(context) {
// get supported languages based on resource files under i18n directory, returns in key value pair
var supportedLanguages = context.getSupportedLanguages();
// set language in appSettings by language key
context.setLanguage('en');
// get current language in appSettings
var language = context.getLanguage();
}
// Regions related API
export default function ManageRegions(context) {
// get regions based on system, returns in key value pair
var regions = context.getRegions();
// set region in appSettings by language key
context.setRegion('SG');
// get current region in appSettings
var region = context.getRegion();
}
// Localize text examples
export default function Localize(context) {
// work_orders="Work Orders"
var localizedText = context.localizeText('work_orders');
// result: Work Orders
// dynamic_localizable_value="{1} and {2} are required for {0} development."
var dynamicParams = ['MDK', 'NativeScript 3.x', 'XCode 9.x'];
var localizedTextWithDynamicParams = context.localizeText('dynamic_localizable_value', dynamicParams);
// result: NativeScript 3.x and XCode 9.x are required for MDK development.
// order id binding is 4013
// dynamic_binding_localizable_value_order_id="The order id is: {0}."
var dynamicBindingParams = ['{OrderId}'];
var localizedTextWithDynamicBindingParam1 = context.localizeText('dynamic_binding_localizable_value_order_id', dynamicBindingParams);
// result: The order id is: 4013
var orderId = context.binding.OrderId;
var localizedTextWithDynamicBindingParam2 = context.localizeText('dynamic_binding_localizable_value_order_id', [orderId]);
// result: The order id is: 4013
}
// Number formatting examples
export default function NumberFormattingExamples(context) {
var valueToBeConverted = 123456.789;
// Format as Number
var customLocale = 'en-US';
var formattedAsNumber = context.formatNumber(valueToBeConverted, customLocale);
// result: 123,456.79
// Format as Currency
var currencyCode = 'USD';
customLocale = 'en-FR';
var formattedAsCurrency = context.formatCurrency(valueToBeConverted, currencyCode, customLocale);
// result: 123 456,79 $US
// Format as Percentage
valueToBeConverted = 0.7865;
customLocale = 'en-US';
var formattedAsPercentage = context.formatPercentage(valueToBeConverted, customLocale);
// result: 78.65%
// Format as Scientific Notation
var customLocale = 'en-US';
var formattedAsNumber = context.formatScientific(valueToBeConverted, customLocale);
// result: 1.23456789E5
// Formatting with options.
// Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
let options = {
maximumFractionDigits: 1,
useGrouping: false,
}
// Format as Number
var customLocale = 'en-US';
var formattedAsNumber = context.formatNumber(valueToBeConverted, customLocale, options);
// result: 123456.8
// Format as Currency
var currencyCode = 'USD';
customLocale = 'en-FR';
var formattedAsCurrency = context.formatCurrency(valueToBeConverted, currencyCode, customLocale, options);
// result: 123456,8 $US
// Format as Percentage
valueToBeConverted = 0.7865;
customLocale = 'en-US';
var formattedAsPercentage = context.formatPercentage(valueToBeConverted, customLocale, options);
// result: 78.6%
// Format as Scientific Notation
var customLocale = 'en-US';
var formattedAsNumber = context.formatScientific(valueToBeConverted, customLocale, options);
// result: 1E5
}
// DateTime, Date, Time formatting examples
export default function DateTimeFormattingExamples(context) {
var dateTimeValue = context.formatDatetime(new Date(), "en-GB", "UTC");
// result: 28 Nov 2017 at 06:16:02
var dateValue = context.formatDate("2017-11-28T11:40:00Z", "de-DE");
// result: 28.11.2017
var timeValue = context.formatTime("2017-11-28T11:40:00Z", "zh-CN", "Asia/Shanghai");
// result: 下午7:40:00
}
ActionResult Examples¶
Using ActionResult in a target path and in a rule
// Message Action definition of action run after CreateWorkOrder action result is stored
{
"_Type": "Action.Type.Message",
"Message": "/MDKApp/Rules/OData/CreateEntityMessage.js",
"Title": "{#ActionResults:CreateWorkOrder/data/OrderDescription}",
"OKCaption": "Ok",
"OnSuccess": "/MDKApp/Actions/Navigation/NextChangeSetAction.action"
}
// CreateEntityMessage.js
export default function GetCreateEntityMessage(clientAPI) {
let actionResult = clientAPI.getActionResult('CreateWorkOrder');
if (actionResult) {
let entity = actionResult.data;
return 'Entity created with description \"' + entity.OrderDescription + '\"';
}
return 'Entity successfully created';
}
// CreateEntityFailMessage.js
// Suppose the action result returns an error message in the error.message as below:
// 'Error 400 (bad request); POST https://abc.xyz.com/ODataDemo/OData/OData.svc/Suppliers(0) {"code": "", "message": "Both If-Match and If-None-Match HTTP headers cannot be specified at the same time. Please specify either one of the headers or none of them."}'
export default function CreateEntityFailMessage(clientAPI) {
let actionResult = clientAPI.getActionResult('CreateWorkOrder');
if (actionResult && actionResult.error) {
if (actionResult.error.responseCode > 0) {
// return only the error message coming from backend
// The actionResult.error.responseCode is 400.
// The actionResult.error.responseBody is '{"code": "", "message": "Both If-Match and If-None-Match HTTP headers cannot be specified at the same time. Please specify either one of the headers or none of them."}'.
return actionResult.error.responseBody;
} else {
// return the full error message
// The actionResult.error.message is 'Error 400 (bad request); POST https://abc.xyz.com/ODataDemo/OData/OData.svc/Suppliers(0) {"code": "", "message": "Both If-Match and If-None-Match HTTP headers cannot be specified at the same time. Please specify either one of the headers or none of them."}'.
return actionResult.error.message;
}
}
return 'Entity failed to created';
}
callFunction Example¶
call a function import in a rule
// TaskDetail page
{
"_Name": "TaskDetail",
"_Type": "Page",
"Caption": "Function Import Example",
"OnLoaded": "/MDKOnlineFioriTrial/Rules/FunctionImport/GetDecisionOptions.js",
"Controls": [
{
"_Name": "FormCellContainer",
"_Type": "Control.Type.FormCellContainer",
"Sections": [
{
"Caption": "CilentAPI",
"Controls": [
{
"_Name": "ApproveButton",
"_Type": "Control.Type.FormCell.Button",
"OnPress": "/MDKOnlineFioriTrial/Rules/FunctionImport/ApproveRequest1.js",
"Title": "Approve",
"IsVisible": false
},
{
"_Name": "RejectButton",
"_Type": "Control.Type.FormCell.Button",
"OnPress": "/MDKOnlineFioriTrial/Rules/FunctionImport/RejectRequest1.js",
"Title": "Reject",
"IsVisible": false
}
]
}
]
}
]
}
// GetDecisionOptions.js
export function GetDecisionOptions(clientAPI) {
var functionName = 'DecisionOptions';
var parameters = { 'InstanceID': '001' };
var oFunction = { Name: functionName, Parameters: parameters };
var serviceName = '/MDKOnlineFioriTrial/Services/FioriTrial.service';
var approveBtn = clientAPI.evaluateTargetPa('{#Page:TaskDetail1/#Control:ApproveButton}');
var RejectButton = clientAPI.evaluateTargetPath('{#Page:TaskDetail1/#Control:RejectButton}');
clientAPI.callFunction(serviceName, oFunction).then(function(result) {
if (result && result.length > 0) {
result.forEach(function (item) {
if (item.DecisionKey === '0001') {
approveBtn.setVisible(true);
}
if (item.DecisionKey === '0002') {
RejectButton.setVisible(true);
}
});
} else {
console.log('No resul set');
}
}).catch(function (error) {
return console.log('------ERROR--------' + error);
});
}