Reading OpsContext check header/detail is a common operation in extensibility applications. Since the JavaScript API makes OpsContext available to the JS extension application, the ext app can iterate through the check detail in the same way as a C# program would.
Reading check detail is made slightly more complicated for the following reasons.
Consider the following C# examples:
foreach ( var dtl in opsContext.CheckDetail )
{
}
for ( int i = 0; i < opsContext.CheckDetail.Count; i++ )
{
var dtl = opsContext.CheckDetail.ItemAt( i );
}
Both of these C# code samples iterate over the top-level CheckDetail entries.
// forEach() does NOT work here. CheckDetail is a C# collection, not
// a JavaScript Array
.CheckDetail.forEach((dtl) => console.log(dtl));
opsContext
// standard iteration pattern works
for (let i = 0; i < opsContext.CheckDetail.Count; i++) {
let dtl = checkDetail.ItemAt(i);
}
In these 2 JavaScript samples, only the 2nd iteration method is valid.
The detail lists in OpsContext.CheckDetail are a
“ExtensibilityDetailArray” object. This class implements a few
collection-like methods: Count, item indexer, GetEnumerator(), but the
container itself is not as flexible as the IList<> container. The
Scriptable
property on each detail container provides an
IList<> implementation to aid with iteration.
The following properties are ExtensibilityDetailArray objects on the following classes:
The following Javascript examples show two ways to iterate over check detail, the native way and using Scriptable.
// native
for (let i = 0; i < checkDetail.Count; i++) {
let dtl = checkDetail.ItemAt(i);
}
// Scriptable
for (let i = 0; i < checkDetail.Scriptable.Count; i++) {
let dtl = checkDetail.Scriptable[i];
}
Consider the following Javascript code sample.
for (let i = 0; i < checkDetail.Count; i++) {
// dtl is a CheckDetailItem reference
let dtl = checkDetail.ItemAt(i);
}
“dtl” is a CheckDetailItem reference. Even though it may be a MenuItemDetail or DiscountDetail object, the only members available on “dtl” are ones defined on CheckDetailItem.
If one wants to access MenuItemDetail members, the script write must either cast “dtl” to a MenuItemDetail or a C# object. This is JavaScript engine behavior, not OPS behavior.
Casting to an Object has been made trivial in Simphony 19.7.
var _api = SimphonyExtensibilityAPI;
for (let i = 0; i < checkDetail.Count; i++) {
// dtl is a CheckDetailItem reference
let dtl = checkDetail.ItemAt(i);
// dtl is now an object reference, and all members are available to scripting,
// even from dervied types.
= _api.Common.ToObject(dtl);
dtl }
Since the Scriptable member returns an IList <object> this casting is not necessary when using Scriptable.
for (let i = 0; i < checkDetail.Scriptable.Count; i++) {
// dtl is an object reference via Scriptable
let dtl = checkDetail.Scriptable[i];
}
Should you use Scriptable or the native iteration method? Both patterns are equivalent, it is purely a stylistic choice.
The following samples show how to iterate over CheckDetail and the ComboSides array within the menu item.
// iterate over native list.
for (let i = 0; i < checkDetail.Count; i++) {
let dtl = checkDetail.ItemAt(i);
= _api.Common.ToObject(dtl);
dtl
if (dtl.DetailType == _api.Common.CheckDetailType.DtlTypeMi) {
for (let j = 0; j < dtl.ComboSides.Count; j++) {
let childDtl = dtl.ComboSides.ItemAt(j);
= _api.Common.ToObject(childDtl);
childDtl
}
}
}
// iterate over Scriptable
for (let i = 0; i < checkDetail.Scriptable.Count; i++) {
let dtl = checkDetail.Scriptable[i];
if (dtl.DetailType == _api.Common.CheckDetailType.DtlTypeMi)
{for (let j = 0; j < dtl.ComboSides.Scriptable.Count; j++) {
let childDtl = dtl.ComboSides.Scriptable[j];
}
} }
When the JavaScript engine encounters a fatal error in parsing a script, it will throw an exception back to ServiceHost. This exception provides module/line/column information about the script error.
Previous versions of Simphony would not display this detailed information. ServiceHost will now display/log the detailed script error details to help the developer narrow down the syntax issue.
Consider the following script:
Line 7 is not valid javascript.
For all host types (OPS, TS, ES) the error will be logged to the egateway log. For OPS, an error window will be raised.
The following error is logged:
05/21/25 14:32:19.472, 0, 0,Unknown , 10,=== exception encountered: Micros.PosCore.Extensibility.ExtensibilityException: JS Engine Exception
Ext App: DateTimeTest
Host Type: OPS
Script Name: js
Engine Type: Root
Engine ID: #17
SyntaxError: Invalid or unexpected token
at Module [temp]:7:3 -> a # c;
The following dialog is displayed in OPS:
The information logged identifies the context (ext app name, script name, etc) and the syntax error (message, module, line, …)
In this case the “a # c” syntax occurred on line 7, column 3.
Since this is a root script, the module name is [temp].