Chapter 2—JavaScript Remote Forms

To create a web or mobile application in Omnis Studio, you need to create a Remote Form class using the JavaScript Components available in the Component Store in design mode. At any stage during the design process, you can test a Remote form by clicking on the Test button in the Design bar in the form, or by pressing Ctrl/Cmnd-T. Alternatively, you can Right-click on the background of a Remote form and select the Test Form option, to open the form in your default web browser, or you can select the Select Browser and Test Form option to select the browser in which to test the Remote form. The following screenshot shows the jsCharts Remote form in design mode in the JS Charts sample app:

image1

When you Test (open) a Remote form in design mode it will open in a web browser on your development computer. The remote form you created will be opened in a simple HTML template file in your web browser using the JavaScript Client and rendered using JavaScript and CSS created for you automatically. This is the JS Charts remote form opened in a web browser (you can view this app under the Samples section in the Hub in the Studio Browser).

image2

To test or open a remote form, your Omnis library also needs to have a Remote Task class which will handle the remote form instance(s) and any current connections to web or mobile clients. If your library does not contain a Remote task and you create a new Remote form (using a wizard, for example), Omnis will create a Remote_Task for you automatically; see Remote Tasks later in this chapter.

JavaScript Remote Forms and Remote Tasks are discussed in this chapter, while the individual JavaScript Components are described in the next chapter.

Creating JavaScript Remote Forms

You can create a new Remote form class in the Studio Browser using the New Class>>Remote Form option, or the Class Wizard>>Remote Form option. The first option creates a blank remote form ready for you to drop in JavaScript components from the Component Store, while the second option launches the Remote Form Wizard, which helps you build a complete form, step-by-step (based on an existing Schema or Query class, and a SQL session).

If you create a new library in the Studio Browser using the Web and Mobile option, the new library will contain a Remote form (and a Remote task) ready for you to add your own JavaScript Components.

Creating a Remote Form using a Wizard

You can very quickly create a Remote form to access and browse your database in a web browser using the SQL JavaScript Form Wizard.

Before using the Remote form wizard, you need to create a schema class in your library, to match the data structure in your database, and you need open a session to your database. To create a Remote form using a wizard:

The Remote form wizard provides the option to create a new server database connection, or use an existing connection, to enable you to logon to your database and view your data. The wizard also creates any schema classes required to match the data structure in your database. To create a Remote form using a wizard:

These steps are described in detail in the Tutorial in the ‘Creating a Web Form using a wizard’ section, so you may like to work through that section if you want to try the Remote form wizard.

Creating a Blank Remote Form

You can create a blank Remote form and add JavaScript components and code yourself.

Remote Form Name

Like any other class in Omnis, the name of a new Remote form can be anything you like, but the name would normally take account of its function within your application. The class name does not have to conform to any convention other than any conventions you may like to use in your application to identify different class types: so, for example, your remote forms could be prefixed with “js” (short for JavaScript), such as “jsCustomerForm”.

You should note that the name of the Remote form class, plus the “.htm” extension, is used as the name of the HTML file which is created when you test your remote form in a web browser in design mode. Therefore, you should restrict any characters used in the name of your Remote form to only those normally allowed in a web context, or to be sure of removing all possible conflicts, you should only use alphanumeric characters and do not use spaces; you can use underscore to separate words if required. A remote form name cannot include the hash symbol (#) or other special symbols, since this may cause unexpected results in a web browser, or in the case of #, the remote form may not open in test mode at all. Omnis will warn you if you try to use any characters that are not allowed.

JavaScript Client

The JavaScript Client functionality is enabled by setting the $client property in a new remote form class. When you create a new remote form, either a blank one or using the Remote Form Wizard, Omnis will set the $client property to kClientJavaScript automatically, so the JavaScript Client is the default client for your web and mobile apps.

In previous versions, the kClientiOS and kClientPlugin values of $client were available, but these options have been removed from the Property Manager; in effect, the kClientJavaScript option is now the default or only possible value of $client.

Client Browser Support

The following Web Browsers support the Omnis JavaScript Client:

The JavaScript Client does not support Internet Explorer.

Please check the Install.txt file accompanying the latest release for the minimum versions of these browsers the JavaScript Client supports.

JavaScript Components

When you edit a remote form in design mode, the Component Store will be displayed, showing different JavaScript components in different groups. The following screenshot shows the Buttons group containing a number of related components, including the Button, Check box, and Switch controls.

image3

See the JavaScript Components chapter for more information and example code for each JavaScript component.

Remote Form Design

When you create or modify a JavaScript Remote form class, the form design window is displayed in a Web Preview using the Chromium web browser built into Omnis (using the Chromium Embedded Framework or CEF), so you can see how your form will look at runtime in the end user’s web browser. Specifically, JavaScript controls (and JSON-defined controls) will look virtually the same in design mode as they will do at runtime in a web browser, including the visual effect of any CSS styles you have applied to the controls (using $cssclassname). In addition, your remote form and its controls will be displayed using the current JavaScript theme, which you can change by pressing Ctrl-J and selecting a different theme: see JS Themes.

To render the Web Preview, an HTML file is generated using the jsctempl.htm template file in the ‘html’ folder in the Omnis tree, or the file named in the $htmltemplate property in the design task, and placed in the ‘html/design’ folder; note the files in this folder are only used for rendering the Web Preview in design mode and are not required when you deploy your application.

Note to pre-Studio 10.2 users: Using old design mode

You should note that there are a few differences between the Web Preview mode for remote forms and the form design mode in previous versions, as follows:

Remote Tasks

To test or run your remote form in a web browser, your library must contain a Remote Task and the $designtaskname property of your Remote form must be set to the name of a Remote task in the current library. When you create a new library or Remote form, Omnis will in most circumstances create a Remote task for you; the following points summarize how this is handled:

If your library contains multiple remote tasks, and you create a new Remote Form from the Studio Browser (using the New Class option, not the wizard), the $designtaskname property will not be set, so you will have to assign the design task name manually before you can test the remote form.

Creating Remote Task Classes using Wizards

For the purposes of prototyping and testing your web or mobile application, you can use the Remote tasks created for you automatically. You will need to edit the Remote task when you are ready to deploy your application, or if you want finer control over the processes in your web application. However, if you want to create a Remote task, you can use one of the templates or wizards provided in the Studio Browser.

To create an empty remote task

A suitable alternative would be the Plain remote task, described below.

To create a remote task using a class wizard

The following wizards/templates are available:

$enablesenddata Property

Existing users should note that the remote task property $enablesenddata should be set to kFalse for all remote tasks controlling JavaScript remote forms since the $senddata() method is not implemented for JavaScript remote forms. Therefore, this property is not necessary in new web or mobile applications using the JS client and may not be shown in your version of Omnis Studio.

Plain Remote Task Wizard

The Plain Task wizard creates a basic template remote task that is suitable for linking to most simple remote forms. The Plain remote task also has an $event() method containing a template event handling method that detects evBusy and evIdle events in the task. You can add your own code to handle these events.

The Plain Remote Task has a $construct() method containing a parameter variable called pParams of type Row Variable. This row variable receives all the parameters of the JavaScript Client, such as the remote form name, the client width and height, and the user agent string: see below.

When you create a task using the Plain Task wizard you can specify the Inherit from Monitor task option. This option adds a set of “monitor” classes to your library which allows you to record client connections associated with the new plain task you are adding to your library. If you check the Monitor option, the wizard prompts you for details about the new monitor task. If your library does not contain a monitor task, you need to specify the Create New Monitor Task option. If, however, your library contains a monitor task, you can specify the Use Existing Monitor Task option to add the new plain task you are currently adding to your library to the existing monitor.

Monitor Remote Task Wizard

The Monitor wizard (or checking the ‘Inherit from Monitor task’ option in the Plain Task wizard) creates a number of “monitor” classes, including a new task and monitor Remote form and /or Window class, that allow you to record remote connections between web or mobile clients and your application hosted on the Omnis App Server.

The wizard prompts you to enter the name of the new Monitor remote task and remote form for displaying the connection results and activity: alternatively, the wizard can create a desktop window class, or both the remote form and window classes. In addition, an extra pane allows you to identify the remote task in your library that needs to have the Monitor set for its superclass (this had to be set manually in versions prior to Studio 10.x).

The Amend Startup Task option lets you add code to the Startup_Task in the current library to open the Monitor form/window at startup; this is checked by default.

The Monitor form/window has three panes. The Connections pane shows the connections grouped by remote form name. The History and Server Usage panes let you monitor the traffic flow on your Omnis App Server and provide some general information about server usage. You can print the server usage using the Print Report button.

Server Management Library

The Server Management Library contains the same Monitor classes (as created in the Monitor wizard) that you can use to monitor an instance of the Omnis App Server; the servermgmt.lbs library is located in the /webserver folder under the main Omnis folder.

On Windows, the Server Management Library can display a tray icon. To enable the icon, you need to set the "showTrayIcon" item in the "servermgmt" section of the config.json file to true.

The remote task of your library can inherit the behavior of the Monitor task in the Server Management Library using servermgmt.Monitor in the $superclass property of your own remote task, and using the command Do inherited in the $construct of your own remote task.

Remote Task Instances

When the JavaScript Client first connects to the Omnis App Server, Omnis creates an instance of the Remote Task Class associated with the Remote form class to which the client is connecting (and specified in the $designtaskname property of the remote form). Once the remote task class has been instantiated, next the Remote form instance is created. The $construct method of first the Remote task and then the Remote form are run, so these methods can include any code you want to run prior to opening the form (in the task construct method) or when the form is opened.

$order property

The $order property is an integer that uniquely identifies the remote task instance within the lifetime of the Omnis Server (since it was started). The value will not be re-used for a different remote task until the Omnis Server is restarted. Also, values are unlikely to be incremental.

Construct Row Variable

When a form is opened and the Remote task and Remote form instances are created, Omnis passes a parameter variable of type Row to the $construct() method of the Remote task and then the Remote form (in that order); this is called the Construct Row parameter variable. The row variable contains a column for each parameter of the JavaScript Client Object instantiated on the client: therefore, it will include columns for OmnisLibrary name and OmnisClass name (as defined in your HTML file), as well as extra columns containing additional information about the client object.

There is an example app called Construct row in the Samples section in the Hub in the Studio Browser showing how you can return information from the construct row; the same app is available in the JavaScript Component Gallery.

The construct row variable will contain the following columns and typical values:

Column Description
OmnisLibrary <OmnisLibrayName> minus the .lbs extension
cookies a row with each column matching a name-value pair for each cookie terminated by a semi-colon. For example, cookie1=value; cookie2=value;
OmnisClass <RemoteFormName> e.g. jsRemoteForm
appid <OmnisLibrayName>.<RemoteFormName>
param1, 2, .. 9 Up to 9 pre-defined custom parameters called param1, param2, etc, which receive the values in the parameters added to the JavaScript Client object in your HTML page; you can add custom parameters prefixed with “data-“ to send further values to the remote task or form $construct method, e.g. data-param1="123" data-param2="abc", etc.
OmnisPlatform JSU, the JavaScript Client
JSscreenWidth The screen width of the client, e.g. 2048 for desktop
JSscreenHeight The screen height of the client, e.g. 1152 for desktop
JSscreenSize The initial setting of $screensize (only applies to kLayoutTypeScreen based forms in Studio 8.0 or earlier, so not relevant for responsive remote forms)
JSDeviceInfo Device screen size (Width x Height) and density, e.g. 1920x1080 (devicePixelRatio:1) for desktop with standard monitor, 360x640 (devicePixelRatio:2) for mobile phone with HD display
clientPlatform The platform on which the client is running, one of the following strings: 'Windows', 'macOS', 'Linux', 'iOS', 'Android' or 'Unknown'
userAgent The navigator.userAgent of the client, which usually contains the browser type and version (e.g. Mozilla/5.0)
appName The navigator.appName of the client, i.e. the browser application name, e.g. “Netscape” (or “Microsoft Internet Explorer” for older clients)
Flags Currently indicates if the client supports animation: 1 means the browser does support animation, zero means that it does not
JStimezoneOffset offset from UTC in seconds, e.g. “60” for clients on UTC+1, “120” for clients on UTC+2, etc.
ClientLocale the Locale language setting of the client, e.g. “en_GB” for clients in the UK, or “en_US” for America
theme The current JS theme as set in the $javascripttheme Omnis preference (e.g. ‘default’)
URLparams One or more parameters added to the URL for the web page containing your remote form; see below. For example, ?x=y&a=b appended to the URL are returned as a JSON object string {"x":"y","a":"b"}
window_ specified as data-window, a comma-separated list of members of the JavaScript 'window' object; see below
localpref_ specified as data-localstorage, a comma-separated list of preference names saved to localStorage; see below

The appName and userAgent columns return properties of the client browser and therefore allow you to determine which browser and version the client is using, such as whether it is a desktop or mobile browser.

Using the Construct Row Variable in your Code

If you want to use the values in this parameter variable, you can create a parameter variable of type Row in the $construct() method of your remote task or remote form which will receive the parameter variable when the task/form is constructed. To examine the values in the variable, you can set a breakpoint in the $construct() method of your remote task or remote form, open the form (using Ctrl-T), and Omnis will switch to the debugger allowing you to right-click on the variable to examine its value.

The following example uses the screen size of the client device to set the size and position of various controls in the initial remote form for the app. The $construct() method of the remote form receives the pRow parameter row variable containing the screen size of the client device, and calls another method to setup the columns for a data grid control on the main remote form:

# $construct method containing a Parameter var called pRow of type Row; the form also 
# contains an instance var iScreensize (Char)
Calculate iScreensize as pRow.JSScreensize
Do method setupSizes
Etc.
# code for setupSizes method
Switch iScreensize
Case kSSZjs320x480Portrait
  Do $cinst.$objs.pagePane.$objs.orderGrid.$::columnwidths.$assign("150,50,50,70")
Case kSSZjs320x480Landscape
  Do $cinst.$objs.pagePane.$objs.orderGrid.$::columnwidths.$assign("70,40,40,70")
Case kSSZjs768x1024Portrait
  Do $cinst.$objs.pagePane.$objs.orderGrid.$::columnwidths.$assign("300,75,75,175")
Case kSSZjs768x1024Landscape
  Do $cinst.$objs.pagePane.$objs.orderGrid.$::columnwidths.$assign("250,75,75,175")
Default
  Do $cinst.$objs.pagePane.$objs.orderGrid.$::columnwidths.$assign("100,50,60,75")
End Switch

Passing Additional Parameters via a URL

You can pass additional parameters to a remote task (or remote form) from the JavaScript Client by adding the parameters to the URL for the web page containing your remote form. This is in addition to the parameters that can be sent to the remote form or task in the construct row variable, and any that may be quoted in the HTML page containing your remote form using the data-param1, data-param2,.. tags.

The additional parameters can be appended to the URL pointing to the remote form in the following format:

http://127.0.0.1:5988/jschtml/rfSetCurField.htm?x=y&a=b

The JavaScript client adds the parameters as an optional column called URLparams in the row variable passed to the $construct() method of the remote form and remote task. The data in URLparams is encoded as a JSON object string, e.g. if the URL params are x=y&a=b, as above, the JSON object string has the value {"x":"y","a":"b"}. You can use the new OJSON static function to convert this to a row:

Do OJSON.$jsontolistorrow(pRow.URLparams) Returns lRow

where lRow is a row variable. For the JSON above, the value of lRow.x will be 'y' and lRow.a will be ‘b'. Note: the client also decodes any special encoded URI characters before generating the JSON, e.g. %3D will become =.

Sending Data to the Form construct

You can send data or content to the $construct method of a remote form by specifying some extra attributes in the Omnis JavaScript object, contained in a <div> called “omnisobject1”, as follows:

For example, the following parameters added to the omnisobject (shown in bold) will send the pixel ratio of the current device, plus the myPref1 and myOtherPref parameters from local storage to the $construct of the remote form:

<div id="omnisobject1" style="position:absolute;top:0;left:0" 
data-webserverurl="" data-omnisserverandport="" data-omnislibrary="" 
data-omnisclass="" data-dss="" data-param1="" data-param2="" 
data-commstimeout="0" data-window="document.URL,devicePixelRatio" 
data-localstorage="myPref1,myOtherPref"></div>

Class Cache Logging

You can log and control the caching of classes in the JavaScript Client. For most applications, you should not need to use the cache logging and control, since the default behavior of caching all class data to localStorage provides the best performance, and is adequate for most remote forms and data.

The options are only provided if you find your application reaches the limits of localStorage (e.g. with a very large application) and you need to examine and control the contents of the cache.

If you have reached the localStorage limit, and need to manually clear the cache, you can do so by running the following JavaScript code in your browser:

localStorage.clear();

To enable the cache logger, the omnisobject <div> can have two optional attributes:

These parameters will need to be added to or enabled in the HTML page containing the initial remote form for your web or mobile application (they could also be added to enabled in the jsctempl.htm file, although the cache logging does not need to be enabled for most applications).

Changing Forms

The remote task instance has a method, $changeform(), which enables you to replace the form currently in use on the client, with another form in the same library. $changeform() has a single argument, which is the new remote form name. When it executes, the current form instance destructs, and the client constructs an instance of the new form to display in the user’s browser. You can use task variables in the remote task instance to pass information between the destructed remote form instance, and the new remote form instance.

There are some restrictions to note:

One scenario for using $changeform() is where the end user is required to log onto your web application, whereby the initial “logon” form prompts the user for a name and password, and the application changes to another form when the user has successfully submitted a valid name and password.

Multiple Forms

You can open more than one form within a single client connection, that is, within a single remote task instance. At any one time, only one of these multiple instances is visible, and the forms must be from the same library.

There are two methods of a remote task instance which you can use to manage multiple forms: $openform() and $closeform(). Like $changeform(), both these methods take a single argument, the remote form name.

If the form passed to $openform() already has a remote form instance open in the context of the remote task instance, it becomes the visible form for the remote task. Otherwise, Omnis constructs a new instance of the remote form in the remote task, and makes the new remote form instance the visible form.

The $closeform() method closes (destructs) the remote form instance for the named form, without closing the task instance or any other forms that may be open within the task. It is possible to close the last remaining remote form instance, but this is not recommended, since the end user will be presented with a blank screen. If the referenced form is not visible, the client observes no effect; otherwise, the most recently visible open remote form instance becomes visible.

There are some further restrictions to note:

You can use task variables to handle communication between multiple remote form instances in a remote task instance.

To facilitate communication between different remote form instances, remote forms can also receive the event evFormToTop. In design mode, you can enable this event for a form, using the $events property of the form. The event generates a call to the $event() method of the remote form. evFormToTop occurs when an existing remote form is about to become visible on the client as a result of a call or calls to $openform() or $closeform().

Client Access Properties

Remote tasks have a number of properties for managing the connections between the Omnis App Server and the web or mobile clients connected to your application. These properties will be populated only when there are live remote task and remote form instances created by a client connection.

Timeouts

You can control how long someone is connected to the Omnis App Server and how long a single client connection can remain idle, using the following properties.

Client Connections

Remote tasks have some properties that tell you about the current client connection.

Managing Timeouts in Remote Tasks

Remote Tasks can be ‘suspended’ to allow greater control over how client connections are managed. A task may (optionally) be suspended if the web page is sent into the browser’s persistent cache, or if the page becomes hidden (e.g. the user switches tabs).

When a task is suspended, it can automatically transition to a shorter timeout. An event is also fired on the task, so you might also want to take this opportunity, for example, to close your database or push connections.

A benefit of this is that it much improves the chance that Omnis will receive some kind of notification that mobile apps have gone away or have been killed by the user/OS, and will not leave the Remote Task open indefinitely.

Properties

Remote Tasks have the following properties:

The conditions under which the client may suspend are:

If the Task times out while the client is suspended, you will receive a "You have been disconnected..." message on resuming. You can override this, as usual, by implementing a client-executed "$ondisconnected" method on your form, which returns true.

Important Note: The HTML templates contain support for this new mechanism (introduced in Studio 10.1), therefore you need to update any existing .htm files on your web servers to match, otherwise you will get errors or leak Remote Tasks.

Remote Tasks Events

Remote Tasks have the following events to handle task suspension:

Remote forms Events

When the client is sent to/resumed from the cache or becomes hidden/visible again, an attempt will be made to call a client-executed form method named “$suspended” or “$resumed” on your main form.

This happens regardless of whether the Remote Task is actually suspended, so can be made use of in serverless-client apps, or if you just want to react to the page becoming visible again without using the suspend functionality.

These methods receive the following parameters:

Secure Sockets

You can use secure sockets (HTTPS) if you have installed an SSL certificate on your web server. The JavaScript Client will use a secure connection to connect the client to the web server if you prefix the URL or IP_address in the data-webserverurl parameter with “https://”. In addition, remote tasks have the $issecure property that lets you turn secure mode on and off dynamically, by assigning to the property for the current task at runtime.

Remote Task Events

For remote tasks, the evBusy and evIdle events are sent to the $event() method during the lifetime of a connection: evBusy is sent when Omnis receives a request from a client, evIdle is sent when Omnis is about to return the result of a request, i.e. the task instance is about to become idle. The following example, shows the code for the $event() method in the Monitor task created using the Monitor task wizard:

On evBusy
  If iMonitorOpen
    Do iMonitorRef.$setstatus($cinst,kTrueReturns lServerBusyFlag
      If lServerBusyFlag
        Quit event handler (Discard event)
        ; server cannot handle request
    End If
  End If
On evIdle
  If iMonitorOpen
    Do iMonitorRef.$setstatus($cinst,kFalse)
  End If
On evRejected
  Do $cinst.$showmessage(pErrorText)

In addition, tasks report the evRejected event which is generated when Omnis rejects a connection by a client. Usually this occurs if there are too many users trying to connect to Omnis, or $maxusers of the remote task has been exceeded. The parameter pErrorText is "Too many users connecting to server" for the first case, and "Too many users connecting to task [taskname]" for the second.

Push Connections

Under normal operation, the Omnis Server cannot initiate communications with the client – all communications must originate as a request from the client. However, you can “push” data to the client using Push Connections by creating a web socket connection to the client. An example use-case could be that you could start off a long query using a SQL worker on the server, and then push the response to the client when the results are ready, updating any instance variables in the remote form.

Support for push connections has been implemented via a Long Polling mechanism called Pollymer, a general-purpose AJAX/long-polling library, since it provides a simple HTTP based solution that is supported in all browsers.

There is an example app called HTTP Push in the Samples section in the Hub in the Studio Browser showing how you can use push connections, and there is a Tech note describing how to use the example: ‘REST Web Services HTTP JavaScript Push Example’ TNWS0005.

Creating a push connection

Each JavaScript client remote task in Omnis can have a single “push connection”, established using the client command openpush.

The openpush client command can be executed in either a server or client executed method, but you are advised to use it in a server method to gain greater control over when the results are pushed. That way, you know exactly when you are using a push, or whether or not you want to push data. The syntax is:

$cinst.$clientcommand("openpush",row([iMaxPollDelayMillisecs=1000]))
$cinst.$clientcommand("openpush",row([iMaxPollDelayMillisecs=1000,iMaxTries=5,cRetryCodes='500-599']))

The timeout period of each request is 60 seconds, so it can take multiple minutes for an error to be reported, if you have more than a few iMaxTries. Timeouts are a normal part of push connections – if the server hasn't pushed anything back, the requests will keep being sent and timing out until it does.

There is a matching client command, closepush, which you can use to close the push connection. The syntax is:

$cinst.$clientcommand("closepush",row())

Utilizing REST

The push connection uses Omnis RESTful support to carry its requests, therefore, if you are using a Web server to pass JavaScript client requests to the Omnis server, you need both the standard Web server plugin, and the RESTful Web server plugin to be installed with the Web server, i.e. you need to install both omnisapi.dll and omnisrestisapi.dll.

The client scripts automatically generate a URL for push by converting the parameters in the web page. For example, if your HTML page for the JavaScript client uses the URL:

http://localhost:8080/omnisservlet

then the client scripts will convert this to:

http://localhost:8080/omnisrestservlet

for the push connection. When generating push URL, Omnis only amends the plugin name part of the complete URL, so in the above case, omnisservlet becomes omnisrestservlet. You can see the URL used for push connections by using browser debugging tools.

If you are not using standard names in your HTML page, there is a parameter in the Omnis configuration file (config.json) that allows you to override the default push URL generated by the scripts: this can only be used when using openpush in a server method. To configure this set the member “overridePushURL” of the “server” entry to the desired URL.

Remote Form Methods

To support push connections there is a method for remote form instances called $pushdata(), which has the following syntax:

Omnis maintains a queue of pushed data for the remote task, which is independent of calls to openpush. As soon as a push connection arrives from the client, Omnis sends all queued pushed data that the client has not yet received as the response. The client then processes the response, and issues a new push connection to the server, telling the server it has received the data. This allows the server to remove the received data items from its queue, and free their memory. Typically, at this point there will be no more queued data. The connection stays open, and as soon as the server code calls $pushdata, Omnis sends the data as the response to the client. This gives the impression of a permanent pipe from the server back to the client, with acknowledgement of pushed data received by the client, so pushed data should not go missing.

Typically, you would take data from the row returned by $pushdata and assign it to an instance variable, or subset of variables, to update the remote form.

There is a tech note TNWS0005 to show how you would use a RESTful web service with the openpush client command in the JavaScript Client.

The client-executed method $pushclosed can be implemented for remote forms which is called (on all forms) if a push connection closes. Return kTrue from the method to prevent the default behavior. It has two parameters:

Remote Task Methods

Remote Task classes also have the $pushdata() method. When called, this will send data to the client and fire the $pushed() method of the Remote Task's 'current form', which is effectively the last form to have sent an event to the server.

Poll delay

The 'openpush' client command has an optional column which can be passed in its parameter row. The 'maxPollDelay' column allows you to override the default maximum delay (1000ms) between the client receiving a '$pushdata()' from Omnis, and making a new connection to Omnis ready for the next '$pushdata()' command. Passing a value of 0 (or less) will not change the maximum delay.

If your application bounces back and forth between client & server in quick succession (you call a server method from $pushed, which in turn calls $pushdata), you may find that reducing this makes your application more responsive. There is a small overhead to reducing this too low, however, so it's recommended to leave the default value unless you have a need to change it.

Remote Objects

Remote Object classes (or Remote Objects) are Object classes that are instantiated and executed entirely on the client, in the JavaScript Client. Each Remote Object class instance has a JavaScript object “class” that directly corresponds to it on the client.

Remote Objects are useful if you have some code that you want to be executed purely on the client, and you want to use it in multiple remote forms, so a Remote Object would provide a good way to structure the code in your application, that is, it provides an alternative to having to inherit methods from a Remote Form superclass, so may be useful in a serverless-client based mobile app.

Remote Object classes (or Remote Objects) are Object classes that can be instantiated and executed on the client, in the JavaScript Client, or on the server. When executed on the client, each Remote Object class instance has a JavaScript object “class” that directly corresponds to it on the client.

Remote Objects are useful if you have some code that you want to be executed on the client, or on the server, and you want to use it in multiple remote forms, so a Remote Object would provide a good way to structure the code in your application, that is, it provides an alternative to having to inherit methods from a Remote Form superclass, so may be useful in a serverless-client based mobile app.

The following sections describe how you use Remote Objects on the client only, while the section Running remote object code on the server describes how you implement code that can be run on the client or the server.

Creating Remote Objects

The Studio Browser window allows you to create a new Remote Object, create a subclass of an existing remote object class, and edit a remote object. Editing a remote object opens the Method Editor, in the same way as when you edit a normal object class. Within the Method Editor itself, the main difference is that every method in a remote object class is always marked as client-executed.

The JSON library representation now includes support for remote objects. You can print methods in a remote object class.

Find and replace supports remote object classes, and has an additional entry in the class selection menu, to select remote object classes.

The inheritance tree includes a node for remote object classes.

Omnis Language

Library Notation

The notation for manipulating remote objects is similar to that for objects. There is a new group within each library, called $remoteobjects, containing all of the remote object classes in the library. Each remote object class has a subset of the properties and methods supported by object classes:

Variables

Remote object classes can have class and instance variables. These are restricted to the set of client execution data types: var, date, list, row, and (new for remote object support) object. In addition, each method in a remote object class can have local variables, which are likewise restricted to the set of client execution data types including object.

Creating Instances

You create an instance of a Remote Object by specifying the remote object class name as the subtype of a variable in a remote object (see the previous section) or for remote forms, either:

Note that this means that remote form instance variables of type object can now have a remote object class as their subtype, in addition to an object class or a non-visual external object. Remote form object variables with a remote object as their subtype are not synchronised between client and server – they exist only on the client.

Behavior

You can write the methods in a Remote Object class in the same way as you create the methods in an object class, except you are restricted to client-executable code. Inheritance works as you would expect using the normal Omnis mechanism, although you cannot override variables in a subclass – you must inherit superclass variables. Variables are referenced as you would expect, e.g. you can just use iName or you can use $cinst.iName.

However, note that you cannot use $new to create a new remote object instance. This is because the Omnis server needs to be able to quickly parse a remote form and its superclasses in order to determine the remote object classes it uses, in order to generate the code correctly.

Remote objects do not execute $destruct, because they are JavaScript objects (which are naturally garbage collected by the execution environment).

If you execute a remote form method marked as client-executed, by calling it from a server method, then because the method is actually executing on the server, Omnis will generate an error if you try to use a remote object.

When coding in the Method Editor, the Code Assistant will only provide assistance for remote object instance variables, and object instance variables, when you are coding for an environment that is applicable: so for example, you would get no assistance for a remote object instance variable when coding a server-executed method.

When passing remote objects around between methods, bear in mind that they are passed by reference, so they are never copied.

$cwind for Remote Objects

You can use the notation $cwind from code written in a Remote Object, to refer to the top-level remote form instance that contains the remote object, for example, you can write code like the following in a remote object method:

Calculate $cwind.$objs.[pName].$backcolor as pick($cinst.$isodd(),kMagenta,kCyan)

In addition, you can use the notation $cinst.$container in a remote object to refer to the remote form that immediately contains the remote object.

Code Generation

The Omnis server automatically generates the JavaScript code for Remote Objects, in a similar way to how it generates JavaScript code for client-executed methods in remote forms. The JavaScript for each remote form contains the JavaScript for all of the remote objects it uses, using a conditional test which means that if 2 remote forms use the same remote object, the code used for all instances of the remote object will be that loaded with the first remote form.

If you modify and save a remote object class, Omnis will regenerate the code when the remote form is re-loaded.

Running remote object code on the server

You can use Remote Objects to implement common code that is available to both server and client methods. In this case, you can place the code in a Remote Object and run it from either client or server executed methods.

To run code in a Remote Object on the server, you need to specify a Remote Object class as the subtype of an object variable, using $new and $newref in server methods, or as the superclass of an object variable. In the case where a remote form instance object variable has a remote object as its subtype, there will be two distinct (unrelated) copies of the remote object and its instance and class variables, one on the client, and one on the server. Note that the server copy is not instantiated until the instance object variable is used during server code execution.

In addition, when editing a client-executed method, the variable panel of the method editor allows you to specify the server type of variables that would have the type Var in client executed methods. In the JavaScript code for the remote object, these variables will have type Var, whereas in a server copy of the remote object, these variables will have the specified server type(s).

If the remote object is being used in server code, and it contains code that cannot execute on the server, then a runtime (debug) error is generated.

Remote Form Properties

Like other types of Omnis class, Remote Form classes have many properties that control their appearance and behavior. You can set most properties of a remote form class in the Property Manager, but the properties for remote form instances must be assigned or controlled in the code in your app. Remote form instances also have methods: see the Remote Form Methods section.

Many of the properties, including many of the standard form properties, are reasonably self-explanatory, but some properties that are specific to remote forms require further explanation and are described in the following sections. The $serverlessclient property enables the Standalone Mobile Apps capability, and is described later in the Serverless Client section, while the $stringtabledata and $stringtabledesignform are discussed in the Localization chapter.

Responsive Forms

Responsive design is a technique used to design form layouts that cater to different devices or screen sizes, including phones, tablets, and desktops, from a single remote form class. The motivation for employing responsive design is to create a single form, with one set of code methods, that adapts its layout automatically when it is displayed on a range of different devices, or when the client browser is resized. For standard web pages, responsive design is implemented using CSS media queries and breakpoints, and Omnis takes a similar approach by allowing you to specify a number of layout breakpoints in a single JavaScript remote form, where each breakpoint corresponds to a different layout for the fields and other controls on your remote form.

Migrating to Responsive Form design

All new remote forms created in the Studio Browser via the New Class option or the Remote Form wizards are set to the responsive layout type by default.

Remote forms in converted libraries (Studio 8.0 or earlier) will continue to use the $screensize property to specify the layout for different devices. There is a migration tool, available under the Tools>>Add-Ons menu, JS to Responsive option, that allows you to migrate existing $screensize based remote forms to the responsive type. (Note the old Sync Screen tool only applies to the old $screensize based remote forms, and should not be used for responsive forms.) See Remote Form Migration.

Form Layout Type

JavaScript remote forms have a property, $layouttype, that specifies how the layout of the form is designed: it can be set in design mode to one of the kLayoutType... constants, and is only assignable when the remote form is empty, when it does not contain any controls. You can return the value of $layouttype in a remote form instance, but you cannot change it at runtime in your code.

The possible values for $layouttype are:

A responsive remote form does not have the following properties, since they are not relevant to responsive design: $resizemode, $screensize, $width, $height, $horzscroll, or $vertscroll, however $edgefloat still applies to components in responsive forms.

If you change $layouttype to kLayoutTypeSingle, and the $resizemode property is set to kJSformResizeModeNone, then $resizemode will be set to kJSformResizeModeFull automatically to make it resizble.

Creating Responsive Remote Forms

You can create a new Responsive Remote form class in the Studio Browser using the New Class>>Remote Form option, and in this case, the $layouttype property is set to kLayoutTypeResponsive automatically. The remote form wizards, available under the Class Wizard option in the Studio Browser, also create remote forms with the responsive layout type. If you want to change the layout type, you must change it before you add any controls, since you cannot change the form layout type once it contains any controls.

A new responsive remote form contains two layout breakpoints by default: these are set to 320 and 768 which correspond to the relative widths for mobile devices and desktop computers (note the default breakpoint values for new remote forms are set in the $initiallayoutbreakpoints library preference).

image4

Remote forms can have only one breakpoint, but in most cases, you would define two breakpoints to cater to mobile devices and desktops or tablets.

Changing and Adding Breakpoints

You can change the default breakpoints to suit the layouts you wish to support in your application. You may find, for example, that setting two breakpoints is enough to cater to mobiles and tablets or desktop screens, and then use the floating edge properties of objects ($edgefloat) to resize and reposition them for different device or screen sizes (the remote form wizards take this approach).

Each layout breakpoint must be a positive integer in the range 100 to 32000, with at least 32 pixels between any breakpoints; therefore, you cannot create a breakpoint with an existing value, or within 32 pixels of an existing breakpoint. The minimum width of the first breakpoint is 100.

The Breakpoints for a Remote form are shown in the Design bar. Clicking on a layout breakpoint makes it the current layout.

image5

You can change, delete or add new layout breakpoints using the toolbar at the top of the remote form design screen, as follows:

You can right-click on a breakpoint (which also makes it the current breakpoint) to open a context menu which provides options to edit the breakpoint value and delete the breakpoint.

When adding a new layout breakpoint, all breakpoint-specific properties are copied from the nearest breakpoint, including the size and position coordinates of the components in the existing breakpoint, plus the following: layout padding for the form, edge float, align, drag border, error text pos, and ‘visible in breakpoint’ properties.

Deleting Breakpoints

When you delete a breakpoint, the positioning and individual properties you have set for all of the fields and controls in the layout are lost, so use this option with caution. You can restore a deleted layout breakpoint immediately after deleting it using the Undo option. If undo is not available, you will lose the breakpoint and any custom settings for the all the fields and controls in that layout; in this case, you would have to recreate the layout again.

Layout Breakpoints

A responsive remote form must have one or more layout breakpoints. Layout breakpoints are widths measured in CSS pixels, so they represent logical sizes rather than physical sizes. The JavaScript client chooses the layout for one of the breakpoints defined in the form based on the logical width of the area in which the remote form is to be displayed in the browser on the device.

The client chooses the most appropriate layout for the device, from all the layouts available in the form. Specifically, the client uses the layout for the largest breakpoint that is less than or equal to the display area width, or if no such breakpoint exists (because all breakpoint widths are greater than the display area width), the layout for the smallest breakpoint.

Once the client has chosen a breakpoint, the client will apply floating and component properties to make use of the available extra width (if any), and if there is no extra width, the client will automatically turn on horizontal scrolling if necessary.

Layout Breakpoint Properties

Remote forms have a property called $layoutbreakpoints, which stores the layout breakpoints for a remote form. This is a comma-separated list of one or more breakpoint values, and these values are shown and edited in the toolbar in the remote form design screen: you cannot set layout breakpoints for a form in the Property Manager. You can return the value of $layouttype in a remote form instance, but you cannot set it at runtime.

When you create a new responsive remote form, the layout breakpoints in the form (and the value of $layoutbreakpoints) are initialized with the value of the library preference $initiallayoutbreakpoints. If you wish to create new remote forms with different layout breakpoints you can edit this preference: to do this, select the library in the Studio Browser and set the property under the Prefs tab in the Property Manager.

A responsive remote form has a property, $currentlayoutbreakpoint which is the value of the current layout breakpoint. In design mode, the current breakpoint is highlighted in the form toolbar: it is not shown in the Property Manager. At runtime, the value of $currentlayoutbreakpoint may change if the end user resizes their browser window, or changes the orientation of a mobile device.

Minimum Layout Height and Padding

Each layout breakpoint in a remote form has a property $layoutminheight, which is the minimum height of the responsive layout. The default setting of $layoutminheight is zero which means the minimum height of the form is set to the bottom-most coordinate of all controls plus an additional 2 pixels for padding (other non-zero values must be in the range 100 to 32000 inclusive).

Each layout breakpoint in a remote form has a property $layoutminheight, which is the minimum height of the responsive layout. The default setting of $layoutminheight is zero which means the minimum height of the form is set to the bottom-most coordinate of all controls plus an additional 2 pixels for padding (other non-zero values must be in the range 10 to 32000 inclusive).

The minimum height is indicated in design mode as the white area containing all the controls; the surrounding area in the form design screen is shaded gray. When the available client height at runtime is larger than this value, controls can float to use the additional vertical space, depending on their $edgefloat properties.

The $layoutpadding property allows you to set the amount of padding under the bottom-most control on the form. By default, the bottom edge of the form is set to 2 pixels under the bottom-most control.

The range for $layoutpadding is 0 to 512 which is added to the bottom-most coordinate of all controls, to generate the minimum layout height when $layoutminheight is zero. When available client height is larger than this, the controls on the form can float. A value is stored for each breakpoint.

When you create a new remote form class (or convert an existing remote form), $layoutpadding is set to 2 by default for each breakpoint. The default value of $layoutpadding is specified in the "responsiveLayoutPadding" item in the "defaults" section of the Omnis configuraration file (config.json), which is set to 2 by default.

When a remote form is accessed for the first time, e.g. in a converted library, the value of $layoutpadding is initialized to the default padding (unless the remote form is read-only, in which case the default value is used, but not written to the class).

Layout Breakpoints for Subforms

Subforms within the inheritance hierarchy of a set of responsive remote forms do not have to have the same layout breakpoints. Therefore, a subform can have different layout breakpoints to its superclass.

What breakpoints should I use?

In general, you need to create a breakpoint for the smallest device within each category of device you wish to support (phone, tablet, or desktop). Therefore, the value of the first breakpoint would be the logical width of the smallest phone you wish to support (bearing in mind logical dimensions are not the same as the pixel dimensions, which depend on the density of the screen). For example, the logical dimensions of the iPhone 13/14 are 390 x 844 (Pro versions are larger), and the Samsung Galaxy S21 is 360 x 800, so you could set the first layout breakpoint to 350 to allow a safe margin and to accommodate form layouts for both phones; or you could retain the default 320 breakpoint to cater to older phones that have a smaller logical width.

Similarly, to set the layout breakpoint for tablets you should consider the minimum width for the range of tablets you wish to support. The default breakpoints defined in a new remote form (320 and 768) provide support for a wide range of mobile devices or tablets, both in vertical and horizontal orientations, but you may need to adjust the default breakpoints to suit your requirements, or as new phones are released.

Adding Controls

When you add a control to a responsive remote form it is added to the current layout and all other layout breakpoints: initially, a control will be in the same position in all layouts, but you can switch to another layout and change its position and other object properties for that layout, such as $edgefloat. If you delete a control from one layout it will be removed from all other layouts, and any individual object property settings will be lost.

Copying Layouts

You can copy the layout from another layout to the current layout using the Copy Layout from Breakpoint option in the remote form. To do this, select the layout breakpoint you want to update, right-click on the background of the form, select the Copy Layout from Breakpoint option, and choose the breakpoint value of the layout you want to copy from (values other than the current breakpoint are shown). This has the effect of synchronizing the layouts of the current and selected breakpoints, by applying the size and position properties of all components in the chosen layout, including their $edgefloat settings. (Note this has a similar function to the Sync Screen tool available for old $screensize based forms.)

The Copy Layout from Breakpoint menu option can also apply to selected objects only if an object or multiple objects are selected. The layout properties of the selected objects in different breakpoints are set to the same values, while the other non-selected objects are unaffected; in this case, the menu option text changes to show 'selected fields only'.

Assigning Properties

The 'Copy <property> To All Other Layout Breakpoints' option on the Property Manager context menu allows you to copy the property value of a control to other instances of the control on all other breakpoints.

In addition, the 'Copy Position To All Other Layout Breakpoints' option allows you to copy the position (meaning left, top, width, height and edgefloat) of a control to all other breakpoints.

Control Size and Layout Properties

The following layout properties are stored for each control for each layout breakpoint, that is, they can be set to different values for each layout: $left, $top, $width, $height, $align, $edgefloat, $dragborder, $errortextpos, and $visibleinbreakpoint, which allows you to hide a control for certain layouts. For example, you could use this property to show a vertical tabbar for one layout and a horizontal tabbar for another layout.

When setting the $align, $edgefloat, $dragborder, $errortextpos and $visibleinbreakpoint properties in the Property Manager, you can assign the selected value to the control on all layouts by checking the ‘Set for all layout breakpoints’ option in the property droplist.

Responsive Form Methods

Remote form classes have a number of methods to allow you to manipulate the layout breakpoints in the form (note these cannot be used in remote form instances, since you cannot change breakpoints at runtime):

Remote Form Inheritance

$layouttype cannot be overridden or changed in a subclass. $layoutbreakpoints cannot be inherited: each class has its own set of layout breakpoints. However, $layoutminheight can be overridden.

Remote Form Migration

The Remote Form Migration tool, under the Tools>>Add-Ons menu JS to Responsive option, allows you to convert an existing JavaScript remote form in a library converted from Studio 8.0, or earlier, to the responsive form type. The migration tool creates new layout breakpoints corresponding to the old screen sizes available in remote forms in previous versions, and tries to adjust the positioning and layout of fields to fit those breakpoints. The migration tool creates a new responsive remote form with breakpoints and modified screen layouts, based on an existing remote form, and retains the old unmodified form in your library.

image6

The migration tool will create breakpoints at 320, 768, and 1024 in the new remote form, and assign them to the form layouts corresponding to the old screen sizes (the kSSZ... constants) set under $screensize: to create a breakpoint it must be set to True in the Migrate column in the Migration tool window. The 480 breakpoint is available but is not enabled by default, since it is not needed in the new responsive form.

You can add a new breakpoint using the Add New Breakpoint button and assign that value to one of the old screen sizes; the new Breakpoint value is added to the dropdown menu in the Breakpoint column. For example, you may wish to create a breakpoint at 300 and assign it to the old phone screen size (320x480) to ensure that all content is displayed on all types of phones.

The Set $edgefloat kEFright option sets the $edgefloat property of certain controls to kEFright to ensure that when the form is resized in the browser the right edge of those controls is also resized or moved. In this case, only controls with no other controls to their right, which are generally on the right-hand side of your form, are updated. Specifically, the $edgefloat property of any buttons is set to kEFleftRight, rather than kEFright, to ensure they float without resizing when the browser window is resized.

The Update method lines… option will replace all references in your code to the old remote form name to the new name, so your code continues to work.

When you have set up the appropriate options you can click the Make Responsive button to create the new responsive form(s), which are placed in a new folder in your library. You can modify them, or test them straight away using Ctrl/Cmnd-T.

Migration Log and detecting form width

When you have run the migration process, the tool creates a change log which will contain any issues that may need your attention. This may include any places in your code that use the old $screensize constants (kSSZjs...), which no longer apply to responsive forms.

Screen Type Layout (kLayoutTypeScreen)

The following section refers to Remote forms when the $layouttype is set to kLayoutTypeScreen. This layout type enables the use of the old $screensize property and fixed screen sizes, available in Studio 8.0 or earlier, which you are advised not to use for new remote forms. Any remote forms in an existing library which is converted to Studio 8.0 or earlier will have this layout type. Note that in addition, only remote forms of type kLayoutTypeScreen trigger the evLayoutChanged event when their layout changes (from Studio 10.0).

The $screensize property provides a number of fixed screen sizes for displaying remote forms on desktop browsers, tablets and phones. As with responsive remote forms, each fixed screen size uses the same set of objects (and methods) and the remote form class stores the position of the fields for each screen size setting.

The following fixed screen sizes and orientations are available (for $screensize based forms only, not responsive type forms):

When opening (constructing) a remote form, the JavaScript Client uses the most appropriate fixed screen size and orientation stored with the form, for the screen size and orientation of the current device. If the user swaps from portrait to landscape, or back again, the JavaScript Client repositions the controls automatically.

Form Width and Height

When specifying the width and height for the mobile fixed screen sizes, you can set the $width and $height properties to match the exact coordinates in the current setting of $screensize, allowing for the mobile title bar which is 20 pixels high. If you have set $designshowmobiletitle to kFalse you may want to add 20 pixels to the height of the form.

Adding new fixed screen sizes

The screen sizes enabled in the $designedscreensizes library preference will be used to populate the $screensize property in the Property Manager. The omnisobject containing the JavaScript client in the HTML page has the ‘data-dss’ attribute, which contains the designed screen sizes for the library. If you use forms from more than one library in a single client instance, each library must have the same set of $designedscreensizes. If not, a runtime error will occur when trying to use a form from another library.

If you change the screen sizes supported in the $designedscreensizes library preference, all the HTML files for all remote forms in your library need to be rebuilt to reflect the new set of screen sizes: this is done automatically when you test a remote form since the HTML file is rebuilt every time you test a remote form. Note the jsctempl.htm template file contains the data-dss attribute and any screen sizes currently implemented for the JavaScript client.

Testing Form Layouts in Firefox

If you are using Firefox during development, you can test different layouts for mobile and tablet screen sizes in a single browser window using the ‘Responsive Design View’ mode: note this is a feature of Firefox and is not available in other browsers. This may save you a lot of time during the initial stages of designing your mobile application, since this avoids having to test your app on multiple devices to test different sizes and layouts. However, we recommend that you should test your final app on any real device that you wish to support when you are ready to deploy your app.

To enable this functionality, you need to set the ‘gResponsiveDesign’ flag to true in the ‘ssz.js’ script file located in the html/scripts folder in your Omnis development tree. For this to take effect, you must restart Omnis after setting the responsive design flag. To enable this mode in Firefox, go to the Tools>Web Developer menu option and select ‘Responsive Design View’: you will need to show the Menu bar in Firefox to see this option. Then when you test your remote form in Firefox, you can select different screen sizes and orientations in the dropdown menu in the Firefox browser window, and your remote form will redraw using the appropriate screen size specified in $screensize for the remote form. When you have finished testing using this mode, you should set gResponsiveDesign in the ‘ssz.js’ script file back to false.

Sync Screens Tool

The Sync Screens tool applies to $screensize based forms only; it does not apply to responsive forms.

The Sync Screens Tool configures the components on the different fixed screen sizes stored in a single remote form. The Sync Screens tool is available under the Tools>>Add Ons menu in the main Omnis menu bar.

To use the Sync Screen tool you need to select a library from the Library dropdown and then select the JavaScript form in which you wish to synchronize objects. The ‘Source Screensize’ is used as the starting point upon which the other screen sizes/layouts are based (the desktop size/layout is chosen by default). You can choose which screen sizes/layouts will be synchronized, and under the ‘Options’ check boxes whether or not to scale objects by horizontal or vertical position and/or by width and height. If you don’t want a particular object to be resized or repositioned by the tool, you can lock it in the remote form in design mode (Right-click the object and select Lock) and enable the ‘Ignore Locked Components’ option (enabled by default). When you have adjusted the settings, click on the Sync button.

You should change the setting of $screensize in your remote form and check the layout of the objects for each screen size/layout. You should also test the form in a browser and on different devices to check that the form objects have been sized and positioned correctly.

Resize Mode (Screen & Single layout only)

Remote forms with the layout type kLayoutTypeScreen and kLayoutTypeSingle have the $resizemode property which allows a form displayed in a desktop web browser to be resized ($resizemode is not available for kLayoutTypeResponsive forms). The $dragborder and $edgefloat properties can then be used to allow JavaScript forms and components to be dynamically resizable at runtime in the end user’s browser.

The $resizemode property only applies when the remote form is being displayed in a standard browser window on a desktop computer or laptop, that is, the property does not apply when the form is displayed in a browser on a mobile device or when the form is being used as a subform since in this context the form size is fixed.

The $resizemode property determines whether or not a form resizes when the end user resizes the browser window. The value of $resizemode is one of the kJSformResizeMode... constants that specify how the form behaves when it initially opens and when the browser window is resized. The kJSformResizeMode... constants are as follows:

You can assign $width and $height of the remote form at runtime, however this may conflict with $resizemode, so you should only assign these properties when $resizemode is kJSformResizeModeNone.

Component Transitions

Remote forms have a property, $animatelayouttransitions, which specifies whether or not the controls on the form will animate to their new position and size when the form layout or orientation changes on the client. If this property is set to kTrue, all the controls on the form will animate on the transistion, e.g. when changing from vertical to horizontal orientation, or when resizing your desktop browser window. You can stop the animation for individual controls by setting the $preventlayoutanimation property to true for the control. (The transition properties apply to responsive remote forms and the old $screensize based forms.)

The animation time is hard-coded to 500ms, but you can override this for individual controls using JavaScript as follows:

Calculate lControl as $cinst.$objs.myButton1
JavaScript: lControl.animateLayoutTime = 1000;
# Set layout transition animation time to 1000ms for myButton1

Or, to set a new animation time for ALL controls on the form, execute the following in the remote form's $init method:

JavaScript: ctrl.prototype.animateLayoutTime = 1000;

Initial Field and Tabbing Order

The $startfield property specifies which field in a remote form will get the focus when the form is opened; it takes the field number of the control as specified in the $order property of the control. The relative values of the $order property for all the controls in your remote form determines the tabbing order of the controls in the form. In general useability and accessibility practices it is usual to specify the left- or top-most control of the form as $order = 1 and follow consecutive order number values across to the right (if you have rows of controls) and downwards.

For inherited forms, the $inheritedorder property determines the tabbing order for the first inherited field: zero means maintain the designed order from the base class through to this class.

Responding to OK and Cancel Keys

You can specify which object in the remote form receive OK and Cancel events from the keyboard, e.g. when the end user presses the OK or Cancel button. For the JavaScript remote forms, $okkeyobject specifies the object in the form that receives evClick when the user presses Return or Enter. Similarly, $cancelkeyobject specifies the object that receives evClick when the user presses Escape. Both of these properties only apply if the field currently with the focus does not use the key that is pressed, in which case these properties will have no effect.

Form background and Subforms

The $okkeyobject and $cancelkeyobject properties are activated when the focus is on the containing form, so $okkeyobject and $cancelkeyobject will now receive a click when the Enter or Esc keys are pressed, and the focus is on the whitespace within its container. Each parent form (when working with subforms) will be checked for an $okkeyobject or $cancelkeyobject until it reaches the top form. The exception to this is if the subform is contained within a subform set, and in this case, it will keep checking parent forms until it reaches its containing subform.

Form and Component Transparency

Remote forms have the $alpha property which sets the transparency of the form (an integer from 0 to 255, with 0 being completely transparent and 255 opaque). In addition, $backalpha lets you control whether or not subforms in the main form use the background color of the subform field or the form itself. The majority of the JavaScript components have the $alpha and $backalpha properties which control the transparency of the foreground and background colors of the component.

In combination with the animation methods, you can use the $alpha of a form or control to make elements in your form appear and disappear. The About windows in the sample apps (available in the Welcome screen when you start Omnis) are displayed by setting the $alpha property of the About subform and using the animation “ease in” effects. See the Animations section.

Gradients

To create a gradient for the background of a JavaScript remote form, you can select a gradient fill pattern for $backpattern and control the start and end colors for the gradient by setting $forecolor and $backcolor.

Remote Form Instances and Methods

When you “open” or test a remote form in Omnis it is opened in a web browser. In development mode, this will be the default web browser on your development computer, but when your app is deployed, the remote form will open in the end user’s web browser, or the browser on a mobile device, or within a wrapper application for standalone mobile apps. When a remote form is opened a Remote Form Instance is created which will have a number of methods that you can use in your code to perform various actions.

Remote Form Instance Properties

Remote form instances have a number of properties, including:

Remote Form Methods

Remote form instances have the following methods, to enable animations, client messages, client commands, and the ability to open a web page from within the client:

See also Client Methods for remote form methods that can be executed on the client (including $init method).

The cWindowProperties parameter for the $showurl() method is ignored if cFrame is not empty. Otherwise, it has the same format as the JavaScript argument to ‘window.open’, for example, "toolbar=0,menubar=1" specifies that the browser window will have a menubar, but not a toolbar. The keywords are all boolean (0 or 1) except for the width, height, top and left, which are numbers in pixel units. Possible keywords are:

Keyword Description
toolbar specifies if the browser window has a toolbar
status specifies if the browser window has a status bar
menubar specifies if the browser window has a menu bar
scrollbars specifies if the browser window has scrollbars
resizable specifies if the browser window is resizable
location specifies whether the browser window has a location bar
directories specifies whether the browser window displays Web directories
width width of browser window
height height of browser window
top top coordinate of browser window
left left coordinate of browser window

$redraw and $senddata Methods

The $redraw and $senddata Methods are only relevant to remote forms used with the now obsolete Web Client plug-in, so do not apply to JavaScript based remote forms. Redraws are handled automatically for JavaScript remote forms and controls, so the $redraw() method is not required and if it is called it does nothing. In addition, the $senddata() method was used in the old plug-in to control when data was returned to the client, but this is irrelevant for JavaScript Client which handles the transfer of data between the client and server automatically.

Client Messages

The $showmessage() method allows you to display a message on the client device. This method only applies to remote tasks that are associated with remote forms, that is, the method does not work for remote tasks that handle HTML forms or “ultra-thin” clients. Only one message can be shown in response to a single event. Executing $showmessage() more than once in response to the same event will result in a single Ok message with the text and title of the last call to $showmessage being shown. Alternatively, you can use the OK message command provided it is executed on the client; in this case the command uses a standard browser alert() or confirm() dialog.

Adding Objects to JavaScript Forms

You can add a new object to a remote form instance or a Paged Pane in the form at runtime using the $add() method. Note that you cannot create an entirely new object using this method, rather the $add() method in this context lets you copy an existing object in the form and add it to the form or pane. The following method can be used, where $cinst is the remote form instance:

$cinst.$objs.$add(cName,rSrcItem[,rParentPagedPane,iPageNumber,bAllPanes=kFalse])

adds new object cName to the JavaScript remote form instance by copying rSrcItem (existing object in same instance). The default action is that the new object is added to the form (when rParentPagedPane etc are omitted), otherwise you can specify the Paged Pane parameters to add the new object to a Paged Pane in the remote form.

This method can only be used in server methods, not a client-side method, that is, the information about methods etc is not present on the client. There is a logical limit of 16384 controls on a remote form, although performance will be impaired well before that limit.

The rSrcItem and rParentPagedPane parameters must both be item references to objects in the same remote form instance: their original properties and methods defined in the class when the form was instantiated will be the initial properties and methods of the new object.

If the object to be copied (rSrcItem) is a paged pane, then its children are not copied.

This method of copying objects cannot be used to copy complex grids. Furthermore, complex grids cannot be anywhere in the parent hierarchy.

Note that you cannot use the $remove() method to remove objects you have added using the $add() method: to remove or hide such an object, you can set $visible for the object to kFalse. In addition, you should note that $order is not assignable at runtime so you cannot add a new object and then change its field order.

Remote Form Instance Group

The item group $root.$iremoteforms is a global group of all remote forms instantiated in Omnis at any one time. You can inspect the $iremoteforms group within the context of the current remote task (the current global group remains unchanged).

Therefore you can use $ctask.$iremoteforms in a remote task to return an item group containing both top-level remote form instances and subform instances. In addition, the $obj notation has been implemented for subform objects, so that if the current item is an item reference to a remote form instance contained by a subform object, item.$obj is the item reference to the remote form subform object. For example, if RF1 is a remote form containing a subform object named sfobj, with a classname of RFSUB, then after both forms have constructed:

$ctask.$iremoteforms     ## will contain instances RF1 and RFSUB
$ctask.$iremoteforms.RFSUB.$obj     ## will be $iremoteforms.RF1.$objs.sfobj

Remote Form Events

JavaScript fields and controls trigger events which you can respond to in the $event() method for individual controls. JavaScript remote forms also trigger events, including when the screen size or orientation of the client device changes, or when a form or subform is brought to the top when multiple forms are open. Remote forms trigger the following events:

Event Parameters

When an event is triggered, a number of event parameters are sent from the client to the event handling method. The first of these parameters is always the name of the event that occurred, and all subsequent parameters are specific to the event and describe the event in more detail. For example, a click on a list passes the click event in the first parameter (pEventCode=evClick) and the list line clicked in the second parameter (pLineNumber).

Enabling Form Events

If you want to use any remote form events in your code, you have to enable the events in the $events property of the remote form. You have to do this in design mode by clicking on the background of the form, selecting the Properties option, and selecting the $events property in the Property Manager. You can enable an event by selecting it in the dropdown list for the $events property.

Form Orientation

When the orientation of a remote form changes (e.g. when the end user rotates their mobile device, or in some cases resizes the browser window), Omnis sends an evScreenOrientationChanged event to the top remote form. This allows the remote form to adjust the coordinates of any dynamically added objects. In addition, evFormToTop also receives the pScreenSize event parameter, allowing other forms to make adjustments if necessary when they come to the top. In addition, remote forms of type kLayoutTypeScreen (non-responsive) trigger the evLayoutChanged event when their layout changes.

Event Methods

You can trap and respond to events generated in a remote form in the $event() method in the form. You have to add a method called $event to the Class methods for the form to create an event handler. Like other event methods you can use the On event command to trap specific remote form events. The following $event method responds to the evScreenOrientationChanged event and sets the iScreensize variable to the correct screen size.

On evScreenOrientationChanged
  Switch pScreenSize
    Case 3
      Calculate iScreensize as kSSZjs320x480Portrait
    Case 4
      Calculate iScreensize as kSSZjs320x480Landscape
    Case 9
      Calculate iScreensize as kSSZjs768x1024Portrait
    Case 10
      Calculate iScreensize as kSSZjs768x1024Landscape
    Default
      Calculate iScreensize as kSSZDesktop
  End Switch
  Do method setupSizes

Running Event Methods on the Client

Event handling methods can be set to run on the client and for most simple methods and calculations this is advisable; in most cases, when you add a $event method it is set to execute on the client automatically (and marked in pink, the default color). To set a method to run on the client you need to Right-click on the method in the method editor and select the ‘Execute on Client’ option. By default, an event is sent back to the Omnis App Server, the client is momentarily suspended while the event handling method is processed on the server, and when the method is finished control is passed back to the client. In some cases, this may not be a problem, or when server data is required, but in general it makes sense to execute your methods on the client and avoid any network delay if possible. Whether or not you execute a method on the client will depend what the method has to do and what information it requires: in general, any method that changes the user interface on the client can be executed on the client, while a method that needs to fetch data or write data to your server database needs to execute on the Omnis App Server.

Testing JavaScript Remote forms

You can test a JavaScript remote form in a number of different ways:

To test a Remote form your library must contain a Remote task and its name must be assigned to the $designtaskname property of the remote form for it to be tested or opened: see Remote Tasks for more information about remote tasks.)

The Test button or Test Form option will open the remote form in a web browser specified as the default browser on your development computer; the remote form will open in a new browser window or create a new tab if your browser is already open.

The Select Browser And Test Form option (Shift+Ctrl/Cmnd+T) on the Remote form design Context menu (or in the Studio Browser) opens a dialog containing a list of web browsers installed on your system, including an entry for the System Default, allowing you to select a browser in which to test your remote form. This can be useful if you want to test a remote form in several different browsers while designing the form and testing your app, for example, to check that some JavaScript code behaves the same in all browsers. Note that the option is only present in the Context menu when your system has more than one registered web browser, otherwise the option is hidden, and the default system browser will be used via the standard Test Form option.

Having tested a remote form in your web browser, you can switch back to Omnis and continue to change your remote form or its methods, and use Ctrl/Cmnd-T at any time to test your form. Each time you press Ctrl-T, Omnis will try to open a new browser window or tab. Alternatively, if your web browser is already displaying your remote form, and you have modified the form, you can switch to your web browser and Refresh/Reload the browser to see the latest changes to your form (but if you change JS theme you have to re-open the browser window/tab using Ctrl-T).

HTTP Server

Omnis has a built-in HTTP server to allow you to test remote forms locally in a web browser.

By default, the HTTP Server supports IPv4. You can set the “IPv” item in the ‘server’ group in the Omnis Configuration file (config.json) to set the IP version support. The values can be 4 for IPv4, 6 for IPv6, and 64 for a dual-stack IPv6 socket, that is, an IPv6 socket which has support for IPv4 on the same socket.

Default Web Browser

When you test your remote form using the Test button or Test Form option (Ctrl/Cmnd-T), it is opened in the default web browser on your development computer. If you want to test the form in another browser on your computer, you can use the Select Browser And Test Form... option (Shift+Ctrl/Cmnd+T) on the Remote form design Context menu; alternatively, you can copy the test URL and paste it into another browser (note the port number may change from session to session).

If you want to override the default action for the Test Form option, you can specify the name and path of an alternative browser in the $webbrowser Omnis preference (edit the Omnis preferences via Tools>>Options on Windows, or Omnis>>Preferences on macOS). If this preference is empty, then the default browser on your development computer will be used for testing remote forms.

Test Web Page

When you test your remote form using Test Form (Ctrl/Cmnd-T) an HTML page is created for you automatically containing the JavaScript Client and all the required parameters to allow you to open your Omnis app in a web browser. The test HTML file is located in the HTML folder under the main Omnis folder, and can be used or incorporated into the other web pages on your website when you are ready to deploy your application. The Web Preview displaying your form in the remote form editor also creates an HTML file in the ‘html/design’ folder, in order to render the page in design mode, but this is not required for deployment.

The name of the test HTML file will be the same as your remote form class name plus the .htm extension. The test HTML is based on a template file which is also located in the HTML folder: see below for more information about the template.

The URL for the test HTML page will be something like the following:

http://127.0.0.1:51452/jschtml/<remoteformname>.htm

The test URL contains the IP address of your Localhost (127.0.0.1), the port number of your copy of Omnis Studio, a reference to the test JavaScript Client HTML folder, and the name of the HTML file. The port number during testing will be the port number specified in the $serverport Omnis preference, or if this is empty (the default) a port number is selected randomly from the available ports on your computer.

If you try to open or navigate to the test URL from your browser history it may not work: in this case such a URL may not have the correct port setting since the port number is assigned dynamically during testing if the $serverport property is empty and therefore may be different from one session to another. In addition, you cannot open or test your remote form by opening the test HTML in the template folder: again your browser will not have the correct URL to load the test HTML file.

Omnis Studio and your library must be open and running to test your remote form. So if you open the test HTML file from your file system, and Omnis and your library are not open, then your remote form will not be displayed and your web or mobile app will not run.

Template HTML File

The test HTML created when you use the Test Form or Ctrl-T option is based on a template file called ‘jsctempl.htm’, which is located in the HTML folder under the main Omnis folder. When you press Ctrl-T a copy of the template file is made and the individual parameters for your remote form are written to the test HTML file: this occurs every time you test your form to ensure the test HTML file is up to date and has the correct parameters. Therefore, if you make any changes to the HTML file in HTML folder your changes will be overwritten the next time you test your remote form: if you want to keep a version of this file, either rename it or copy the file to another location.

See Editing Your HTML Pages for more information about the contents of the test HTML page and what changes you may need to make for deployment.

Using an Alternative Template file

The remote task class property $htmltemplate allows you to specify a different HTML template to use to test a remote form, rather than using the default template ‘jsctempl.htm’. For example, you may want to create a template with your own set of parameters in the “omnisobject” <div>, but retain the default template.

The new $htmltemplate property specifies the name of a template file (which must exist in the html folder) to use when testing any remote forms that use this remote task as its design task. If $htmltemplate is empty (the default), Omnis uses the default template ‘jsctempl.htm’ located in the html folder, which matches the behavior in previous versions.

Debugging Remote Forms

When you open a remote form in your development browser you will need to debug the methods and code in the form. You can do this by setting breakpoints in your code and you can send messages to the Omnis trace log or the JavaScript console (provided it is available) to allow you to debug your code.

Breakpoints

You can set breakpoints in your code, so when you test your remote form using the Test Form option or Ctrl-T and a breakpoint is encountered, control will pass from your web browser back to Omnis. In this case, when a breakpoint is encountered, the Omnis entry (button) in the Windows Task bar will flash (the default color is orange) and you will have to click on the button to return to the Omnis application window to continue debugging.

Trace Log

The tracelog() function allows you send debugging and other messages to the Omnis trace log from within client methods executed in the JavaScript Client: this will allow you to debug client methods. The tracelog(string) function writes the string to the Omnis trace log, or does nothing if debugging is disabled using the library property $nodebug. It returns true if the string was successfully written to the trace log.

Alternatively, in JavaScript client-executed methods you can use the Send to trace log command which sends the text to the JavaScript console.

Runtime & Server Logging

The Library preference $alwayslog ($clib.$prefs.$alwayslog, defaults is kFalse) allows you to log messages in the Runtime and Server versions of Omnis to help you debug your code. When kTrue, the Send to trace log command and tracelog() function always write non-diagnostic messages to the trace log (overriding the check for debuggable code).

Client Caching

There is an entry in the Omnis configuration file (config.json) that allows you to control whether HTML pages are cached or not by the built-in HTTP server in Omnis (which is used for testing forms in design mode). The "preventclientcaching" item under the ‘omnishttpserver’ entry in the config.json file is set to true by default and prevents web pages from caching. When set to true, this would mean that every time a page is accessed, the page and any linked scripts (JS files, CSS files) are loaded or refreshed and not cached: note this is for testing purposes only, and does not apply when you deploy your app. If you want pages to be cached you can set this item to false.

The "preventclientcaching" entry in config.json has the following format:

"omnishttpserver": {
        "preventclientcaching": true
    }

When hosting your files on a web server (as recommended for deployment), this setting does not apply - your web server will have its own settings to control client caching behavior of files it serves.

Testing your Remote Form on a Mobile Device

To test your remote form on a mobile device or any other client apart from your development computer, assuming those devices are within the same local network (LAN/WLAN) as your development computer, you can enter the test URL into the web browser on your device but replace the Localhost IP address (127.0.0.1) with the IP address of your development computer. For example, reusing the test URL above and replacing the IP address, the following URL could be used on a mobile device such as a phone or tablet computer:

http://194.131.70.184:51452/jschtml/jsMain.htm

You can use the ipconfig command to find the IP address of your development computer, via the Command prompt on a PC or the Terminal on a Mac.

You can test a mobile remote form in a wrapper application using the Test Form Mobile (Ctrl-M) option, assuming a wrapper application is setup and enabled: if a wrapper is not setup you can test your mobile forms in a web browser during development, as above. See the Deployment chapter for details about setting up a wrapper application.

Client Script Version Reporting

If the build version of the scripts in the JavaScript Client is different to the scripts on the server, then the mismatch is reported as an error.

If there is a major version difference between client and server, an error message is generated, and the client will not run in this situation. The error message text is determined by a new localizable string "omn_cli_script_majorversion_mismatch" in strings_base.js.

If there is a difference in the build revision, a warning is logged to the browser console describing the issue. For example, if you patch the scripts only (rather than installing a new version of Omnis Studio), then this difference will be logged in the console.

Troubleshooting Remote Forms and Tasks

Remote Tasks

When I try to test my remote form using Ctrl-T, it does not open and the error “To use a remote form class, you must set the design task of the remote form class to a remote task” is displayed.
You need to create a remote task in your library and set the $designtaskname property of the remote form class to the name of the remote task you created. A remote form instance needs a remote task instance to run (for testing or deployment), so will not open without a remote task and the $designtaskname property being set.

Remote Forms

When I open my blank remote form in design mode I don’t see any JavaScript components in the Component Store.
All new remote forms should be set to run on the JavaScript client, but if for some reason the $client property is not assigned, you need to set it to kClientJavaScript to use the new JavaScript components. (Note you cannot switch an existing Web Client based remote form to the JavaScript Client, but there is a migration tool available in the Studio Browser to help you move to the new client.)

Events

I have placed an event method behind my button (or any other event-driven object), but nothing happens when I click it while testing the form in a browser.
You must specify which events are to be triggered by the object or remote form in the $events property of the object or form. So for a button, the evClick event must be checked in the $events property of the button. Events for some objects are checked by default, but you may like to examine the state of each event in the $events property and make sure the events you need are enabled.

Client Methods

You can run certain methods on the client, such as event handling methods ($event), instead of running them on the Omnis App Server: these are referred to as Client-Executed Methods or simply Client Methods. When such client methods are called in your application, runtime execution does not pass back to the Omnis App Server, rather the method is executed entirely in the end-user’s browser within the JavaScript Client. Enabling certain methods to execute on the client can speed up your application, by cutting down on network traffic, while from a design point of view, using client methods allows you to add more interactivity into the UI of your web or mobile app, including using native JavaScript in your Omnis code.

Any methods in your JavaScript remote forms that are enabled to execute on the client are converted to JavaScript files. These JavaScript files are run in the browser when the method is called on the client. When a client browser opens a JavaScript remote form, the Omnis App Server generates a JavaScript file containing the client methods for the remote form (the generation of this file only occurs once unless the remote form class is modified, in which case it will regenerate the file). This file is added to the html/formscripts folder in the Omnis tree inside a subfolder named after the library. Each remote form containing client methods has a separate JavaScript script file.

When you deploy and run your web or mobile app on the Omnis App Server, these JavaScript script files are generated at the same location as in the development version, the first time the client calls the client-side method. For the deployed app, the JavaScript files are in minified form, and therefore are smaller and will run faster since all the comments are stripped out.

There is a sample app called Client Methods in the JavaScript Component Gallery, and under the Samples option in the Hub in the Studio Browser.

Enabling Client methods

To enable a method to execute on the client, you can Right-click on the method name in the Method Editor and select the ‘Execute on Client’ option. Whether or not an existing method can be enabled to execute on the client will depend on the Omnis commands, functions, and in some cases the type and scope of the variables used in the method. When you try to enable the method to execute on the client, Omnis checks whether all the commands and functions within the method can be executed on the client, and if not, it will not allow the method to be marked as ‘Execute on Client’. If the method can be executed on the client, the method name will be shown in pink (the default color) and the restrictions on client methods will then apply to this method.

If you create a new empty method in the method editor, it can be enabled to execute on the client without error (since it does not contain any commands, functions or variables at this stage), but the number of commands and functions available to use will be limited to those shown in the Method Editor. The type of Local and Parameter variables you can create will also be restricted: see Data Types below.

The Omnis Help (F1) indicates whether or not a command or function can be executed on the JavaScript client.

Binary functions

The Binary functions cannot be used in JavaScript client methods since JavaScript does not support binary data particularly well.

Text Blocks

You can use the text block commands (Begin text block, Text:, End text block, Get text block, JavaScript:) in client methods to build up a block of text, e.g. to generate styled text (see the Styled Text section).

Object Properties in Client Methods

While some properties can only be assigned in Server methods, you can read the current value of many more remote form properties and component properties in client-executed methods running in a form instance. So for example, you cannot change the size and position of an object in a client method (by setting $top, $left, $width, and $height), but you can return the current values for an object in a client method, e.g. $cobj.$width returns the width of the object.

An error will be generated if you try to read the value of a remote form/control instance property from a server-executed method: "Cannot get the value of a remote form instance property when executing code on the server".

Code Block Error Checking

JavaScript code generation for client methods detects missing block terminators, and if an error is found, Omnis adds an error to the Find and Replace log and opens the log. For example, an error is generated if there is a While loop with no End While, or an If with no End If. You can open the method containing the error by double-clicking the error message in the Find and Replace log.

Auto Client Executed

When you add a new method in the method editor, and the method editor recognizes the method name as a known method that should be client-executed, then the method editor marks it as client-executed, and also adds any parameters (if required). This applies to new methods with the following names: $candrop, $drag, $filereadcomplete, $filtergrid, $getscrolltip, $init, $pushed, $sfscanclose, $sfsorder, $sortgrid, $sqldone, $term. In addition, the $sqldone method receives some boilerplate or template code when you add it.

$init method

You can create a client-side method with the name $init in your remote form which the client calls after the form and the client scripts file have been loaded. This allows you to do any final initialisation of the remote form, especially when the remote form is running in serverless client mode. When you create or enable the $init method it will be marked as client executed automatically.

Leave Site Prompt

You can use the $init() client method to add a 'Leave Site' prompt to your application which forces the browser’s built in prompt to be shown when the end user attempts to close the remote form if there has been any sort of interaction. To add a ‘Leave Site’ prompt, add a Quit Method command returning any string to the $init method of your remote form, for example, Quit method 'Show leave site prompt'. The default ‘leave site’ text for the browser is displayed, so the text you add to Quit method is irrelevant.

Event Specific Client Methods

You can use the $eventclient() method to call a client-executed method for specific named events. The client will run the $eventclient method if it contains On default or an On <event> statement for the named <event> that has been triggered, otherwise it will run the $event method, which must be server-executed if $eventclient is specified.

When specifying $eventclient, as with $event, events are still only sent when they are present or enabled in the $events property for the control or form. Omnis calculates the subset of $events to be handled by $eventclient as those events specified in an On statement or On default statement in $eventclient, at any level in the inheritance hierarchy for the control or form. In this case, if you use On default, all events are processed by $eventclient.

Any events not present in the subset of $events to be handled by $eventclient are sent to $event for the control or form and run on the server, unless they are one of the small set of client-only events, e.g. $candrop and $drag.

The current event processing model, where all events go to $event, which is either client or server executed, works as in previous versions if there is no $eventclient method present for the control or form.

When using inheritance, you can also override $eventclient in a subclass.

Showing Built-in Methods

When the Show Built-in Methods option is enabled (the default), the method editor tree list shows all possible built-in class and control methods that can be overridden, including $event and $eventclient (in versions prior to Studio 11 most of these methods were available but not listed). Note that control methods that are built-in to JavaScript client objects cannot be overridden, meaning they are not displayed in the method tree list when showing built-in methods. In addition, built-in methods in the tree have a tooltip that is displayed when the Show Method Content Tips option in the View menu is enabled.

Debugging Client methods

Client methods cannot be debugged in the Omnis method editor since method execution occurs in the client browser. Instead, you must use the Script Debugger within the browser you are using to test the client executed parts of your application. Note that for this reason you cannot use any Omnis commands that interact with the debugger or trace log (Trace on, Open trace log, etc) in client methods, or any that would interrupt command execution (Breakpoint, Yes/No message). However, while developing your app, you can use the Send to trace log command in client executed methods to write a line to the JavaScript console.

Client methods cannot be debugged in the Omnis method editor since method execution occurs in the client browser. Instead, you must use the Script Debugger within the browser you are using to test the client executed parts of your application. Note that for this reason you cannot use many Omnis commands that interact with the debugger or trace log (Trace on, Open trace log, etc) in client methods. However, while developing your app, you can use the Send to trace log command in client executed methods to write a line to the JavaScript console.

The Breakpoint command can be used in client-executed methods to set a 'hard' breakpoint in the code, but note that this will only be hit if the web browser developer tools are open. It will then break into the browser's debugger, in the JavaScript code which was generated from your client-executed method. The browser dev tools can usually be opened using the F12 key.

Errors

Omnis maintains two global system variables #ERRCODE and #ERRTEXT that report error conditions and warnings to your methods. Fatal errors set #ERRCODE to a positive number greater than 100,000, whereas warnings set it to a positive number less than 100,000. You can return the values of #ERRCODE and #ERRTEXT in client executed methods in the JavaScript using the functions errcode() and errtext(), so it is possible to write methods to handle errors when they occur.

Calling Custom Methods

You can use the Do method command to call a custom method (your own method) in the current remote form instance. If you use this command in a client method you must include parenthesis after the method name for the method to be called. For example, to call a custom method called $mymethod from within in a client method in the current remote form instance, you must use Do method $cinst.$mymethod(), or you can use Do $cinst.$mymethod().

Data Types for Client methods

JavaScript itself only supports a small number of built-in data types, and these do not correspond directly with Omnis data types. Since instance variables are used by both the JavaScript Client and the Omnis App Server, these can still be given any Omnis data type.

However, Local variables and Parameter variables in client methods can only be Date Time, List, Row or Var type. The Var type is a generic variable used for data of any type. The client does not enforce the type of data stored in a variable, unless you assign a value to an instance variable or list column, in which case the client will convert the assigned value to the correct Omnis type for the instance variable or list column, or failing that, if the data cannot be converted, the client throws an exception, reported by an OK message.

Further restrictions

When you change a method from client to server execution, or back again, the data type of Local variables and Parameters changes to the most logical supported value for client or server execution (restoring the original type when changing from client to server execution if the type on the client is Var).

Variable References in Client Methods

There are some subtle differences to the way variables are passed around in client methods in Omnis Studio, as opposed to methods that are executed on the server. This is due to the fact that client-executed methods are running JavaScript code, and so are bound by the rules of that language.

This is easily understood for primitive data types, such as string, number, and boolean, but objects are slightly more nuanced, that is, anything that’s not a primitive, including Omnis Lists, Rows, Dates and Remote Objects.

Object-type variables

This means that it is cheap and efficient to pass objects around, but there are two important consequences:

  1. If you change some property of a passed object, it will change the property on the original object too.

  2. If you re-assign the whole variable of the passed object, you are replacing the pointer, so will not effect the original object.

In Omnis, this only comes into play when you are using local variables or parameters in a client-executed method.

Example 1

Calculate lRow1 as iRow
Calculate lRow2 as lRow1
# lRow1 & lRow2 are two separate local variables, but because they are object types,
# they are now pointing to the same object in memory (as one was assigned the value of the other).
Calculate lRow1.C1 as "TEST"
# Changing an aspect of lRow1 will now also effect lRow2. So setting column 1 of lRow1 to "TEST"
# also sets column 1 of lRow2.
Calculate lColValue as lRow2.C1
# lColValue is "TEST"

Example 2

Calculate lRow1 as iRow
Calculate lRow2 as lRow1
# lRow1 & lRow2 are two separate local variables, but because they are object types
# they are now pointing to the same object in memory (as one was assigned the value of the other).
Calculate lRow1 as row("TEST")
# Because we have reassigned the whole lRow1 variable, it has created a new pointer
# as the value of lRow1, so is no longer pointing to the same object as lRow2.
Calculate lColValue as lRow2.C1
# lColValue is the original value of column 1 from iRow

Execution and Method Calls

Method execution in the JavaScript client means that that no user-visible updates to the user interface occur until control returns from the executing JavaScript to the browser (or other container). This means that client methods should be as short as possible. This also means that if a client-side method calls a server method, this call cannot occur in a synchronous manner, since the user interface would appear frozen while the server code was executing (since no user-visible updates to the user interface occur while a synchronous AJAX call is running). This means that the mechanism for calling a server method from a client method is implemented differently for the JavaScript client.

When code in a client-side method calls a server method (either using $cinst.$methodname notation, or by using the Do method command), the call to the server is executed asynchronously. While the server method is executing, the UI is made inaccessible using a loading overlay – the exception to this is that $alwaysenabledobject and edit controls calling a server-executed evKeypress are left accessible. After making the server method call, the client-side method continues to completion (note that the server method call returns true or false to indicate if it has started). The client-side method can only call one server method like this – if it makes a second call, the client throws an exception.

When code in a client-side method calls a server method (either using $cinst.$methodname notation, or by using the Do method command), the call to the server is executed asynchronously. While the server method is executing, the UI is made inaccessible using a loading overlay – the exception to this is that $alwaysenabledobject and edit controls calling a server-executed evKeypress are left accessible. After making the server method call, the client-side method continues to completion (note that the server method call returns true or false to indicate if it has started).

If you try to call multiple server methods from a client method, Omnis only allows one method to run at a time, but the others will be queued. They will run in the order in which you call them. If your subsequent server method calls depend on previous server method calls, you should take the “daisy-chain” approach of calling the next method from the previous method's ..._return callback method, described below.

Return Methods

If the client code needs to handle the return value from the server method, then you must implement a client-side method in the remote form with the name <method name>_return. For example, to receive the return value from a server method called $test, implement a client-side method $test_return; the server method ($<method name>) must be called from a client-side method. The <method name>_return method must have a single parameter, which is the return value from the server method. A typical action of the _return method might be to update a progress control, and then issue another call to the server. This allows a time-consuming operation to execute while showing its progress.

The Insert Client Return Method After option in the Modify>>Method menu (and on the Method list context menu) allows you to add a “<method name>_return” method for a server method; the method is named <method name>_return automatically and placed after the server method.

From Studio 10.2 onwards, you can create such return methods for controls (fields). If a client-executed method calls a server-executed method on a control, when execution returns to the client, Omnis will look for the <method name>_return method on the control, and if not found it will look for the return method at the form level, as in previous versions.

Object and Library names

You can use $cinst.$class or $cinst.$lib in client-executed methods to get the name of the current class or library, where $cinst is a JavaScript remote form instance executing the method.

Client Methods Example

There is an example app demonstrating JS Client Methods in the Samples section in the Hub, and the same app is available in the Omnis Components app in the Apps Gallery on the Omnis website (www.omnis.net/platform/#jsgallery). The app includes a simple entry form with client-side field validation, and some animated help tips.

image7

You should open the library in the Hub or download the library and examine the client methods and code. A sample of the code is described here.

Field Validation

A web or mobile form may include several mandatory fields. You can use a client-side method behind the Submit button (called Add in the example app) to check that the fields contain some data – this is the code for the email field:

# $event method behind Submit button – it is enabled to execute on the client
On evClick
  If pos('@',iEmail)=0
    Do $cinst.$objs.EmailLabel.$textcolor.$assign(kRed)
    Calculate lCurField as 'Email'
  Else
    Do $cinst.$objs.EmailLabel.$textcolor.$assign(kBlack)
  End If
  Do $cinst.$setcurfield(lCurField)

The code checks whether or not the Email field contains an ‘@’ and if not the field label is colored red and the cursor is placed in the Email field – if the Email field contains data the method moves onto the next field. All the other fields on the form are checked for any content and handled in a similar way: the password field is checked for a minimum number of characters, as follows:

If len(iPassword)<6
  Do $cinst.$objs.PasswordLabel.$textcolor.$assign(kRed)
  Calculate lCurField as 'Password'
Else
  Do $cinst.$objs.PasswordLabel.$textcolor.$assign(kBlack)
End If
Do $cinst.$setcurfield(lCurField)

Animated Help tips

In the JS Client Method example app, the form has some help buttons that the end user can click on to receive tips about how to fill out the form. These help tips are implemented using a hidden text box and the animation methods – when you click on a button, the text box is made visible and is moved into position next to the appropriate field, and when the button is clicked again the text box is hidden. The code to achieve this is in a client-side method behind the Help tip button marked with a ‘?’ icon: the button is in fact a Picture control with its $iconid set to 1794, and the code is placed behind the $event() method. The Tip box is a paged pane containing a Rounded rectangle and a Text field – when the form is opened its $alpha is set to 0 and it is positioned off the screen. The help tip next to the Password field has the following event method:

On evClick
  If iLastTip='password'
    Do $cinst.$beginanimations(500,kJSAnimationCurveLinear)
    Do $cinst.$objs.Tip.$alpha.$assign(0)
    Do $cinst.$commitanimations()
    Calculate iLastTip as ''
  Else
    Calculate iTip as "A password must to at least 6 characters long."
    Do $cinst.$beginanimations(500,kJSAnimationCurveLinear)
    Do $cinst.$objs.Tip.$top.$assign(270)
    Do $cinst.$objs.Tip.$alpha.$assign(255)
    Do $cinst.$commitanimations()
    ; the Tip box is made visible and moved into position
    Calculate iLastTip as 'password'
  End If

There is a similar Help tip button and method for the Email field. If the Password Tip box is already visible in the form and you click the Email Help button, the Tip text is changed and the Tip box itself is moved next to the Email field.

Client Objects and Inheritance

The JavaScript client uses JavaScript objects to represent each remote form and each control on the remote form. The client methods of a remote form and its controls are defined as methods of the remote form and control objects.

Once a remote form and its client methods script file have been loaded, the JavaScript remote form object has a member called ivars which is a JavaScript object that maps instance variable names to instance variable field numbers. If you override an instance variable, then the ivars object will have more than one entry for the variable – overridden superclass variables will have a numeric suffix to distinguish them.

The Do inherited command is evaluated at the point at which the script file is generated by the server. This means you can only use Do inherited from within the actual method you have overridden. This differs from the other clients, in that they allow you do call Do inherited from a private method called from an inherited public method, and then the call to Do inherited calls the overridden public method.

New Page Browser Prompt

In most desktop browsers (excluding Opera) a web page can prompt the user before navigating to another page. Using the $init client-side method for a remote form you can specify the message to be added to the user prompt.

If the $init method returns a character string, the browser will prompt before navigating to another page, but only if the browser supports this feature. The returned character string may not be in the browser prompt, depending on the browser, for example, Firefox does not currently display it.

If $init does not end with a Quit method command, or returns another type, then functionality is unchanged from the current behavior.

Once one $init method has returned a string, any return values from any other $init calls for other remote form instances are ignored, so there is no way to turn off the prompt once it has been enabled.

Client Commands

The $clientcommand() remote form method allows you to execute various pre-defined commands on the client device, including ones that open various types of message boxes, and ones that can access functions on a mobile device. The suitability of certain client commands will depend on the current client device (e.g. some of the commands may not be available for certain mobile devices), and due to the differences between web browsers on desktop computers and phones, so these client commands should be thoroughly tested, as appropriate, for all platforms or devices you wish to support.

These client commands should be executed in the context of the current remote form instance using $cinst, and require various parameters that depend on the command sent to the client. The client commands must be executed on the client; they have the general syntax:

Do $cinst.$clientcommand(cCommand,wRow)

where $cinst is the current remote form instance, cCommand is the name of the client command to be executed on the client, and wRow is a row variable containing one or more parameters to be passed to the client.

The following is a summary of all the client commands (in alphabetical order), and they are described after the table (in functional groups):

Client command Description
assignpdf Assigns the specified PDF to the specified HTML control
clearerrors Clears all errors set with $errortext for all objects on the form
clearlocale Clears the locale on the client
closefile Closes a file or files supplied by the drag value of kDragFiles to evDrop
closepush Closes an open push connection to the Omnis Server
enablepushnotifications Enables or disables push notifications on the client inside a JavaScript mobile wrapper; see the wrapper docs on the download page
javamessage Shows a message box on the client
loadpreference Loads a named preference value from the client preferences into an instance variable
lockui Locks the client user interface
noyesmessage Opens a no-yes message box
okcancelmessage Opens an ok-cancel message box
openpush Establishes a push connection to the Omnis Server for the remote task
playsound Plays a sound on the client (unlikely to work on mobile devices)
readfile Reads and then closes the file identified by file ident (supplied to evDrop)
savepreference Saves a value (as a character string) as a named preference on the client
setcustomformat Sets the default custom date format used when $dateformatcustom is empty
setlocale Sets the locale on the client
settheme Sets the theme for the JS client, i.e. all remote forms in the library or application
showloadingoverlay Shows or hides a loading overlay over a control or the entire form
showpdf Opens the specified PDF in a new browser window or tab
showtoast Activates a “toast message” which displays a message to the user in a small popup which disappears after a timeout, either 5000ms or specified amount
soundbell Sounds the bell (unlikely to work on mobile devices)
speakmessage Speaks a message, useful for visually impaired users
subformdialogclose Closes the topmost subform dialog
subformdialogshow Opens a single subform as a modal dialog
subformpaletteclose Closes a subform palette
subformpaletteshow Opens a subform palette
subformset_action Where action is one of the following: add, formadd, formremove, formtofront, or remove, e.g. subformset_add adds a set of subforms to the form. See Subform Client Commands
yesnomessage Opens a yes-no message box

Message Dialogs

There are a range of message dialogs available including dialogs for Yes/No messages (Yes is default button), No/Yes messages (No is the default button), and Ok/Cancel messages (OK is the default, with an optional Cancel button).

There is an example app called Dialogs in the Samples section in the Hub in the Studio Browser that shows how to use the client commands to open message dialogs, plus the same library is available in the JavaScript Component Gallery. In addition, the speakmessage client command can speak a message.

The message box client commands allow you to enter the message text in the first column of the row variable. You can create a line break in the message text using //.

Multiple calls to any of the message commands during the processing of a single event will result in only the last call having any effect and that message being shown, so all previous messages will be ignored or overwritten.

Yes/No Messages

The “yesnomessage” command opens a Yes/No message box in which Yes is the default button.

Do $cinst.$clientcommand("yesnomessage",row)

Where rowVariable is row(cMessageText, cTitleText, cPublicFormMethodNameCalledOnYes, cPublicFormMethodNameCalledOnNo [,cPublicFormMethodNameCalledOnCancel]); if the latter is omitted no Cancel button is shown.

For example, in the Webshop sample app a Yes/No message is generated using the $clientcommand method when a user clicks on a product size/type that is not available:

Do $cinst.$clientcommand("yesnomessage",row(con('Would you like to order >',iProductList.product_size_1,'< instead?'),'Not available','$orderYes'))

No/Yes Messages

The “noyesmessage” command opens a No/Yes message box in which No is the default button.

Do $cinst.$clientcommand("noyesmessage",row)

Where rowVariable is row(cMessageText, cTitleText, cPublicFormMethodNameCalledOnYes, cPublicFormMethodNameCalledOnNo [,cPublicFormMethodNameCalledOnCancel]; if the latter is omitted no Cancel button is shown.

Ok/Cancel Messages

The “okcancelmessage” command opens an OK/Cancel message box in which OK is the default button, with an optional Cancel button.

Do $cinst.$clientcommand("okcancelmessage",row)

Where rowVariable is row(cMessageText, cTitleText, cPublicFormMethodNameCalledOnOk, [,cPublicFormMethodNameCalledOnCancel]; if the latter is omitted no Cancel button is shown.

Message Dialog Header Styling

The styling for dialog headers is defined in the classes: .omnis-wf-title.typeheader and .omnis-wf-title.typebody in the core.css file, which can be modified by overriding them in user.css.

speakmessage

The "speakmessage" client command tells assistive technology to announce a message, which can, for example, be used to convey information to visually impaired users.

Do $cinst.$clientcommand("speakmessage",row)

Where rowVariable is row(cMessage, bInterruptCurrentSpeech).

JavaScript Message Boxes

The “javamessage” command shows a JavaScript message box on the client. The message box can be various styles (error, warning, success, prompt, message, or query) and can have up to three buttons and accompanying text.

Do $cinst.$clientcommand("javamessage",row)

Where rowVariable is row('error'|'warning'|'success'|'prompt'|'message'|'query', cMessageText, cTitleText, bOpenAtMouse, cButt1text:servermethodname, cButt2text:servermethodname, cButt3text:servermethodname). For example:

Do $cinst.$clientcommand('javamessage',row('query','Update file?','Warning',kFalse,'No:','Yes:$call_next_method_a','cancel'))

Dialog Icons

The message dialog displayed using the ‘javamessage’ command contains a standard icon from the material design set. Types 'error', 'warning', 'success', 'prompt' and 'query' all contain an icon specific to that type, while 'message' does not use an icon. The images for the icons are defined in the core.css file under the .typeicon classes and can be overridden in user.css.

Using a Promise

The javamessage, yesnomessage, and noyesmessage client commands (as well as the $showmessage method) return a JavaScript promise when the methods are executed on the client; a promise contains a value that can be used in JavaScript code in your remote form, for example, to initiate a specific action.

The promise's resolve function is passed a parameter whose value depends on the message type being shown, as follows:

Method Value returned
javamessage client command The button number which was clicked (1-3)
yesnomessage client command true if 'Yes' was clicked, else false
noyesmessage client command true if 'Yes' was clicked, else false
$showmessage method true

For all these dialog functions which return a promise, the calls will only return a promise when executed on the client. A promise will be 'resolved' when its dialog is closed. You can add code to run at this point using JavaScript, for example:

Do $cinst.$clientcommand("yesnomessage",row("Are you sure?","Really?!")) Returns lPromise
JavaScript: lPromise.then((lResult) => {
Do $cinst.$showmessage(con('You clicked ',lResult))
JavaScript: });

Playing Sounds

The system bell

The “soundbell” command plays the default system sound on the client.

Do $cinst.$clientcommand("soundbell",row)

In this case, rowVariable is empty.

Play a sound file

The “playsound” command plays a sound on the client.

Do $cinst.$clientcommand("playsound",row)

Where rowVariable is row(cNameOfSoundFile1[,cNameOfSoundFile2,...]); the sound file(s) should be located in the html sounds folder.

Browser support

In some cases, these sounds will not work in Safari on macOS or iOS since it generally only allows sounds that are in direct response to a user action. Therefore, sounds triggered in a server method are unlikely to work, whereas if they are triggered in a client-executed method they are more likely to work. In general, sounds tend to work in Chrome on macOS or iOS, regardless of how they are triggered.

In all cases, using the client commands to play sounds should be thoroughly tested, for all platforms and browsers you wish to support.

Date Format

The “setcustomformat” command allows you to set the date format used on the client when $dateformatcustom is empty (defaults to D m y).

Do $cinst.$clientcommand("setcustomformat",row)

Where rowVariable is row(cDateFormat). See the Date and Time Formatting section for more details about setting the data format on the client.

Client Preferences

The following commands allow you to save and load end-user data on the client, such as user preferences. You could use these commands to store and load usernames and/or passwords to allow the end user to log onto your application. As with other client commands, these commands must be executed on the client.

There is an example app called JS Preferences in the Samples section in the Hub in the Studio Browser showing how you can use these client commands to save and load user preferences in a remote form; the same app is in the JS Component Gallery.

Saving preferences

The “savepreference” command saves a value (as a character string) as a named preference on the client.

Do $cinst.$clientcommand("savepreference",row)

Where rowVariable is row(cPreferenceName, cPreferenceValue [,StorageType]).

Loading preferences

The “loadpreference” command loads a named preference value from the client preferences into an instance variable.

Do $cinst.$clientcommand("loadpreference",row)

Where rowVariable is row(cPreferenceName, cInstanceVariableName [,StorageType]), where cInstanceVariableName is a quoted string containing the name of the variable.

The following method can be used for a ‘Save’ button which saves the values in three fields on a form:

# lPrefRow Row var, iPref1, iPref2, iPref3 instance Char vars (on the form)
On evClick
  Do lPrefRow.$define(lPrefName,lPrefValue)
  Do lPrefRow.$assigncols('omnis_pref1',iPref1)
  Do $cinst.$clientcommand("savepreference",lPrefRowReturns #F
  Do lPrefRow.$assigncols('omnis_pref2',iPref2)
  Do $cinst.$clientcommand("savepreference",lPrefRowReturns #F
  Do lPrefRow.$assigncols('omnis_pref3',iPref3)
  Do $cinst.$clientcommand("savepreference",lPrefRowReturns #F

Storage Type

The row variable passed to the “savepreference” and “loadpreference” client commands can have a third parameter, the “storage type”, which allows temporary, session, or local storage options. This allows you to store text values in the client browser, either temporarily or persistently in the browser using JavaScript sessionStorage or localStorage. Storage type is of type character and can have the following values:

For example:

Do lPrefRow.$define(lPrefName,lPrefValue,lStorageType)
Do lPrefRow.$assigncols('omnis_pref1',iPref1,"session")
Do $cinst.$clientcommand("savepreference",lPrefRow)
Do lPrefRow.$assigncols('omnis_pref1','iPref1',"session")
Do $cinst.$clientcommand("loadpreference",lPrefRow)

Locking the User Interface

The “lockui” command lets you lock the user interface manually, for example, when a series of events are taking place, and unlock the UI when the events have completed.

Do $cinst.$clientcommand("lockui",row)

Where rowVariable is row(bLock); kTrue to lock the UI, or kFalse or empty to unlock.

This command is useful with the progress control and $sendcarryon – in this case, you can lock the UI when you start the progress bar, and unlock it when you have finished using the following code:

# to lock:
Do $cinst.$clientcommand("lockui",row(kTrue))
# to unlock, either:
Do $cinst.$clientcommand("lockui",row(kFalse))
# or
Do $cinst.$clientcommand("lockui",row())

Custom Loading Indicator

The “showloadingoverlay” client command allows you to add a loading indicator (animated image and text) over an individual control, or the entire page in the JavaScript Client. As well as providing feedback to the user, that a long running operation may be in progress, it will also prevent user input. It is useful if you are doing any asynchronous operations, such as populating a list using a SQL worker object.

There is an example app called Loading Overlay in the Samples section in the Hub in the Studio Browser showing how you can use the loading overlay client command; in addition, the same app is in the JS Component Gallery.

image8

The showloadingoverlay client command is executed using the $clientcommand method, as follows:

Do $cinst.$clientcommand("showloadingoverlay",row)

Where rowVariable is row(bShow, cControlNameOrEmpty, cMessageText [, cCSSClass]).

By default, the overlay will darken whatever is behind it, and display a spinner and text string. If you wish to customize the appearance, you can do so with CSS. Create a CSS class in your user.css file, and pass this class name as the cssClass parameter.

The loading overlay comprises a toplevel div, which will be given your CSS class name. This contains a div with the CSS class name of “container”, which contains a div with the “indicator” class and a ‘p’ element with the “message” class. You will need to use CSS to style all of these. Look at the 'jsLoadingOverlay' JS form in the HUB sample library which contains 'getUserCss' and 'getUserCss2' methods which build up examples of the necessary CSS and may be useful to form the basis of your CSS.

Subform Sets

There are a number of client commands, all prefixed ‘subformset_’, that allow you to create and manage subforms in a subform set: see the Subform Client Commands section for more information.

Subform Palettes

Subform palettes can be opened or closed using subformpaletteshow and subformpaletteclose, or a subform palette can be closed by clicking outside the subform: see Using Subform Palettes.

PDF Printing

The showpdf and assignpdf client commands allow you to print and display PDF files in the client browser: see the PDF Printing in the JavaScript Client section for more information.

Push Connections

Remote tasks can have a single “push connection”, established using the client command openpush, to allow you to send data to the client: see the Push Connections section for more information.

Dragging and Dropping files

The readfile and closefile client commands enable files to be read from evDrop event while dragging files from the end user's system. See Dragging and Dropping files for more details.

Push Notifications

The enablepushnotifications client command enables and disables push notifications for mobile apps: this is described in a separate doc available with the JavaScript Wrapper download.

Toast Messages

The showtoast client command activates a “toast message” which displays a message to the user in a small popup which disappears after a timeout, either 5000ms or specified amount: see the Toast Messages section for more information.

Locale Commands

The setlocale and clearlocale client commands can be used to manage the locale on the client: see the Localizing Remote Forms section for more information.

Theme Command

The settheme client command can be used to set the JS Theme in the JS Client: see the Changning the Theme section for more information.

Remote Menus

The Remote Menu class allows you to add various types of menus to remote forms and individual controls. A remote menu can be opened as a Popup Menu control, added to a Tab Control or Split Button, or opened as a Context menu for the remote form itself or individual controls (Popup menus, Tab menus, and Split buttons).

There is an example app showing how to use a Remote menu in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

Creating Remote Menu Classes

When you design a Remote menu, you need to create a title, specified in the $title property, and add individual menu lines: the text for a menu line is added to the $text property for the menu line.

To create a Remote Menu

A remote menu does not contain methods, rather each line has a separate ID which is specified in the $commandid for the menu line. When a menu line is selected at runtime, you can use the line ID to detect which line was selected and branch your code accordingly. For example, when a remote menu is used as a popup menu and the menu is clicked, the evClick event is triggered and the value of $commandid for the selected menu line is reported in pLinenumber.

You can add icons to Remote menu lines and can be chosen when you create the remote menu class, along with the text for the menu line (they must be 16x16 if using PNG icon images). The icon in each menu line is specified by $iconid. Checked menu lines use the checked state of the icon if the icon is multi-state.

Note that $objs.$add for a remote menu instance does not have a parameter to add an icon id. You can only set this after adding the menu line, by assigning $iconid for the new line (since the new menu line needs to reference the icon on the server, which cannot be done while executing $add).

Icon Colors

The $iconcolor and $defaulticoncolor properties control the color of icons when using themed SVG icons. The $iconcolor property for a remote menu line sets the icon color when using a themed SVG icon. The $defaulticoncolor property for a remote menu class sets the icon color when using a themed SVG icon and the $iconcolor property of the item is kColorDefault. If $defaulticoncolor is also kColorDefault, then the themed icon uses the text color.

Text Alignment

You can change the text alignment in Remote menus. The pContextMenu event parameter in evOpenContextMenu events has an $align property. This can be used to specify the text alignment of a menu. For example:

Do pContextMenu.$align.$assign(kCenterJst)

Possible values are kLeftJst (default), kRightJst and kCenterJst.

Context Menus

A context menu is a menu that can be opened by the end user by right-clicking on the background of a form, or within the border of a form control. You can implement context menus for remote forms or individual form controls by setting the $contextmenu property of the form or control to the name of a Remote menu class. Each line in a remote menu has the $commandid property, so when the user selects a line in the menu this ID can be used to trigger a specific action in your code. When a line in a remote menu is selected, an evExecuteContextMenu event is reported to the form or field with event parameters containing the Command ID of the selected line, and for fields, a reference to the field which was clicked on.

Remote forms and controls have the $disabledefaultcontextmenu property to disable default menus from opening when the end user right-clicks the form or object: the default menu for the edit control could be the clipboard menu. If true, the default context menu for the object will not be generated in response to a context click ($clib.$disabledefaultcontextmenu and $cobj.$disabledefaultcontextmenu must both be false for the default menu to be generated).

Context Menu Events

Remote forms or controls report the following events in response to a context click.

The remote menu instance itself only exists during the evOpenContextMenu event, therefore it is possible to modify the menu before it is displayed on the client, or you can discard the event to prevent the menu from being displayed.

Remote form instances have the property $remotemenu which is the name of the remote menu instance (set only when evOpenContextMenu for the field or form is being processed): for hierarchical menus, this is the item reference to the remote menu instance of the attached remote menu.

After evOpenContextMenu completes, and the user selects a remote menu item, the client sends an evExecuteContextMenu event to the form or form control that received the evOpenContextMenu, passing the event parameter pCommandID containing the value of $commandid of the selected menu line.

Control Menus

All controls with a menu, such as Tab, Popup menu, or Split button, generate the evOpenContextMenu and evExecuteContextMenu events when using their own control menus. The pControlMenu parameter can be used to distinguish between Control menus and Context menus; it is kTrue if the menu is a Control menu, or kFalse if it is a context menu.

Subform Sets

You can open a special kind of subform or group of subforms that behave like separate “floating” windows inside the main remote form in the JavaScript Client. The subforms in a Subform Set (SFS) are different to standard subforms (which are embedded in a Subform control, and described in the JavaScript Components chapter), in that they have a title bar and resizable borders, and the end user can move or resize them within the “main” or parent remote form instance running on the client. Such dynamic subforms within a subform set allow you to create highly flexible user interfaces in your apps, by allowing a high degree of interactivity for the end user.

The subforms in a subform set are created at runtime in the JavaScript Client within a remote form instance, or they can be opened within the context of a single page in a paged pane in a remote form, which are referred to as Subform panels. Each separate subform in the Subform Set is an instance of a standard Remote form class that you have previously created in your library, which is referenced and added to the Subform set on the client.

In addition to opening one or more subforms in Subform set, you can open a subform as a Subform Palette; see Subform Palettes.

­There is an example app in the Samples section in the Hub in the Studio Browser showing how you can setup and use a subform set, and the same app is available in the JavaScript Component Gallery.

image9

Subform set windows respect their container’s dimensions when opened, that is, if subforms that are larger than the available space are opened (or are too far to the right or bottom to fit the whole subform area), then they will be resized and repositioned automatically. Specifically, the left and/or top values will be reduced, If these reach 0, and there is still not enough space for the subform, the width and/or height values will also be reduced.

Stacking Order List

The subforms in a Subform Set have a “stacking order” (or Z-order) relative to one another, so the top-most form in the set will appear in front of any forms lower in the stacking order if they intersect. Clicking on a form lower in the stacking order brings it to the front. The tab order of the remote form excludes controls on the subforms in a Subform Set behind the top form in the set. There is a maximum of 256 remote form instances (including subform instances) in a remote task instance. When you have more than one Subform Set open (this is allowed but not recommended) there is no relative stacking order between the sets.

Creating Dynamic Subforms

There is a set of client commands to open and manage the subforms in a Subform Set which you can execute using the $clientcommand() method. These client commands should be executed in the context of the current remote form instance using $cinst. The $clientcommand() method requires two parameters: the cCommand to be executed and a wRow variable containing the parameters for the command, with the syntax:

Do $cinst.$clientcommand(cCommand,wRow)

where $cinst is the current remote form instance.

Subform Client Commands

The following client commands are available for creating and managing subform sets or the subforms in a subform set, including subform dialogs.

subformset_add

The subformset_add command creates a Subform Set within the current remote form instance.

Do $cinst.$clientcommand("subformset_add",row)

Where rowVariable is row(setname, parent, flags, ordervar, formlist)

Note the parent parameter is available if you want to create the subform set inside a paged pane, rather than the remote form instance. The columns for the row variable parameter are as follows:

setname: a string which is the name of the subform set, which must be unique within the current remote task.

parent: the container for the set, either:

flags: the sum of the following constants (e.g. kSFSflagMinButton+kSFSflagMaxButton), which effect the behavior of the subforms in the set:

ordervar: the name of an instance list variable in the remote form invoking the $clientcommand. The client keeps this list variable up to date with the stacking order and position information for the subforms in the set: see below.

formlist: a list which defines the subforms to be added initially to the subform set (this list can be empty), i.e. a list of remote form classes that you have previously created in your library. The order of the forms in this list represents the stacking order from top to bottom, so that once the set has been added, the top-most subform will be for line 1, and the bottom-most subform will be for the last line. The columns in the list are as follows:

When formLeft or formTop parameters are set to kSFScenter, the subform will be displayed in the center of the current viewport or the current form, whichever is the smaller of the two: note that horizontal and vertical centring work independently of each other.

Formlist for Responsive forms

When using the "subformset_add" and "subformset_formadd" client commands you can pass dimensions for the subforms for each breakpoint in a responsive remote form in the formlist parameter (instead of the single set of left, top, width, height parameters). The same method applies to both client commands, but the example below shows directly adding a form with "subformset_formadd":

Do lDimList.$define(lBreakpoint,lLeft,lTop,lWidth,lHeight)
Do lDimList.$add(310,10,10,200,200)
Do lDimList.$add(600,kSFScenter,kSFScenter,300,300)
Do lDimList.$add(1000,kSFScenter,kSFScenter,600,600)
Do $cinst.$clientcommand"subformset_formadd",row(cSetName,vUniqueID,cParams,cTitle,lDimList,iModal))

The dimensions list replaces the 4 separate parameters, and so condenses the command to a minimum of 5 parameters (6 if passing a value for iModal): this only works for responsive forms, whereas single and screen type forms must use the original set of parameters to avoid confusion.

The client will use the value passed in lBreakpoint to assign the values to the correct breakpoint for the containing form. If the breakpoints do not match, then the values will be used from the next breakpoint down. For example, if you had the list of dimensions as defined above, but your form used the following breakpoints:

310 - would use the values from 310 as they match

590 - this is smaller than the next value of 600, so would again use the values from 310

900 - this is smaller than the next value of 1000, so would use the values from 600

1200 - this is greater than the values from 1000, so uses those values.

subformset_formadd

Having created a subform set using subformset_add, you can use the subformset_formadd client command to add a form to the subform set.

Do $cinst.$clientcommand("subformset_formadd",row)

Where rowVariable is row(setname, uniqueID, classname, params, title, left, top, width, height, modal)

The row variable parameter are as follows:

setname: a string which is the name of the set to which the subform is to be added.

uniqueID: an integer which must uniquely identify this subform in the set.

classname: the name of the Omnis remote form class for the subform.

params: A comma-separated list containing literal parameters to be passed to the $construct and $init methods of the subform instance, e.g. "'Test',123". Note strings have to be quoted, and can contain spaces and commas. $init is run in serverless client subforms.

title: the title of the subform - text displayed in the title bar of the subform.

left: the left coordinate of the subform (for Desktop browsers, or portrait if a mobile device). The constant kSFScenter centers the form horizontally in its parent.

top: the top coordinate of the subform (for Desktop browsers, or portrait if a mobile device). The constant kSFScenter centers the form vertically in its parent.

width: the width of the subform. If the forms in the set are resizable, then the form cannot be made narrower than the minimum of this width and the width designed for the remote form class.

height: the height of the subform. If the forms in the set are resizable, then the form cannot be made taller than the minimum of this height and the height designed for the remote form class.

Note the 4 separate parameters (left, top, width, height) can be replaced by a list containing the dimensions for each breakpoint: see above regarding the formlist for subformset_add.

modal: zero if the subform is non-modal, or 1 if the subform is fully modal, and prevents the use of any other form or subform in the remote task’s user interface (the form is grayed out and clicks outside the subform are ignored).

image10

If the subforms are to be displayed on a mobile device, the next four columns are landscape left, top, width and height respectively. If these are omitted, the landscape values default to the portrait values.

The parameters above, starting with uniqueID, are identical to those in the formlist (for the subformset_add command), except the modal indicator is present between the two sets of coordinates.

subformset_remove

The subformset_remove command removes a set of subforms. All subforms in the set will be destructed and removed from their parent.

Do $cinst.$clientcommand("subformset_remove",row)

Where rowVariable is row(setname) where setname is set to be removed.

subformset_formremove

The subformset_formremove command removes a subform from an existing set and destructs it (removing it from its parent).

Do $cinst.$clientcommand("subformset_formremove",row)

Where rowVariable is row(setname, uniqueID, focus)

The row variable parameter are as follows:

setname: a string which is the name of the set from which the subform is to be removed.

uniqueID: an integer which identifies the subform in the set to be removed.

focus: optional (default value is kFalse). If the focus parameter is kTrue, sets focus to the new top form in the set unless it is minimized.

subformset_formtofront

The subformset_formtofront command brings a subform in a set to the top of the stacking order, and gives it the focus. You must use this command to display a subform that has previously been minimized.

Do $cinst.$clientcommand("subformset_formtofront",row)

Where rowVariable is row(setname, uniqueID)

setname: a string which is the name of the set containing the subform.

uniqueID: an integer which identifies the subform in the set to be brought to the front.

Subform Dialogs

subformdialogshow

The subformdialogshow command opens a single subform as a modal dialog.

Do $cinst.$clientcommand("subformdialogshow "row)

Where rowVariable is row(classname, params, title, width, height, closeButton, resizable, maxButton, openMax). The parameters are as follows:

Parameter Description
classname String, the name of the remoteform
params String literals to pass to the subform
title String, the title of the modal dialog
width Integer, the width of the dialog
height Integer, the height of the dialog
closeButton Boolean (Optional), defaults to true, show close button
resizable Boolean (Optional), defaults to false, if true allows resizing
maxButton Boolean (Optional), defaults to false, if true shows maximize button (resizable must be set to true)
openMax Boolean (Optional), defaults to false, if true opens dialog in a maximized state (resizable must be set to true)

This command generates a new subform set and adds one modal subform to it. The name of this set is internal only, and cannot be added to or removed from. Another modal subform dialog can be opened above the previous one by running subsequent calls, preventing access to the first one until the second is closed (using the subformdialogclose command).

subformdialogclose

The subformdialogclose command closes the topmost subform dialog. This command only works for subforms opened using the subformdialogshow command, and has no parameters as such modal dialogs must be closed in reverse order of them opening.

Using the Stacking Order Variable (ordervar)

When you use the subformset_add client command a list called ordervar is created containing a list of the subforms in the subform set. The ordervar variable allows you to manage the subforms in the set. It has the same definition as the formlist, and like the formlist it contains the subforms in the order of the top to the bottom of the stacking order. Note that if coordinates have been centered using kSFScenter, the ordervar contains their actual values rather than the value kSFScenter.

Whenever the stacking order changes, or a form is moved or resized, the client updates the values in ordervar. This results in:

You can use the ordervar list in conjunction with the subformset_formtofront $clientcommand to manage the subforms in the set, e.g. bring a form to the front by selecting a line in a popup menu (this is the only way to restore a minimized subform). For example:

# the ordervar list is assigned to iOpenForms, C1 contains the subform ID
Do $cinst.$clientcommand("subformset_formtofront",row('SubformSet',iOpenForms.[pLineNumber].C1))

If a subform has been minimized, you would you have to use such a method to display the subform again since minimized subforms are not visible in the parent remote form.

Load Finished Method

Remote forms have the $loadfinished client-executed method which is called after all the subforms that belong to the parent remote form instance have finished loading and their $init methods have been called; so you could create a client method called $loadfinished to perform any actions you want after all subforms have loaded.

Trapping the Close event

You can add a method to a subform in a subform set to trap the close event before the $destruct for the subform is run. The method should be named $sfscanclose and should be set to be client-executed (which should be enabled automatically). The method can contain whatever processing you want to run. If the return value (a Boolean) from this method is kFalse the subform cannot close. Otherwise, if the return value from this method is kTrue, the subform can close. If $sfscanclose is not present, the subform closes by default.

Dialog and Palette style subforms can call into $sfscanclose() when attempting to close via the close button (X) in a dialog subform, or clicking the background outside the palette for a palette style subform. As with other subforms, it would be possible to test a conditional statement in $sfscanclose() and if it returns kFalse the close event will be cancelled.

Scroll Position

The kSFSflagPosnScroll flag allows you to control how a subform is positioned relative to its container if the container has been scrolled. When the kSFSflagPosnScroll is set the subform in a subform set (SFS) will open relative to the current scroll position of its container. For example, on a long form which is currently scrolled to the bottom of the page, with a subform opening at left position 100 and top position 100, it will open 100 pixels in from the top of what can currently be seen in the viewport. Similar behavior would apply if it belonged to a paged pane that has been scrolled.

When the flag is not set, it will be positioned absolutely to the defined position: therefore, in a long form that has been scrolled to the bottom of the page, the subform will be placed at the top of the page if its top position is set to 0.

However, when opening a modal subform in a subform set, if its position is set to kSFSCenter, it will always be positioned relative to the current scroll position of the form, as modal subforms always belong to the form, not a paged pane (since a modal subform requires interaction and closing before any other action can be taken on the form). If kSFSCenter and kSFSflagPosnScroll are both not used, then a subform will be placed at its specified position, even if that is out of the current view of the user (which is the behavior in previous versions).

Subform Styles

The styles and colors used in subforms will be those set in the subform classes; the colors for the subform set are taken from the theme used in the main JS form.

Subform Titles

You can use $cinst.$title to change the title text for a member of a subform set.

Subform References

You can obtain a reference to any subform instance within a subform set using the $sfsmember root notation. For example:

$root.$sfsmember(cSetname,iUniqueID)

returns an item reference to the remote form instance for the subform set member with the specified unique ID in the named subform set in the current remote task. This notation can be used in server and client methods.

Subform Panels

You can open a set of subforms as a group of collapsible panels within a container, such as a paged pane control. The subform panels are arranged vertically and the end user can expand and collapse each subform by clicking or tapping on the subform title bar or the minimize icon. Subform panels cannot be nested.

There is an example app called JS Subform Set Panels in the Samples section in the Hub in the Studio Browser showing how you can setup and use subform panels, and the same app is available in the JavaScript Component Gallery.

image11

Configuring the panels

You can create a set of subform panels using the “subformset_add” client command along with the “kSFSflag...” constants, which can be found in the Catalog (F9) in the ‘Subform sets’ group. The subformset_add command creates a set of subforms within the current remote form instance or a parent, such as a paged pane.

Do $cinst.$clientcommand("subformset_add",row)

where rowVariable is row(setname, parent, flags, ordervar, formlist). The flags can be summed to specify the complete behavior of the panels in the set: see the example method below to see how to use subformset_add and the flags.

kSFSflagOpenMin

The subform panels in the set are opened in the minimized state. Normally, all subforms in the set are opened in the un-minimized state. This flag overrides this default behavior.

kSFSflagOpenMax

The subform in the set is opened in the maximised state. Sizes/positions should still be set as the subform will return to these values if it is restored.

kSFSflagMinAsTitle

When a panel (subform) in the set is minimized, just the title bar is shown. This flag overrides the default behavior which is to reduce the subform to nothing when it is minimized.

You can use the kSFSflagMinButton flag to add a minimize button to each subform to allow the end user to expand and contract the panel (in addition to clicking on the title).

kSFSflagAutoLayout

Automatically lay out the panels (subform set members) vertically within their parent, ignoring the specified left and top. Turns on kSFSflagMinAsTitle and turns off kSFSflagResize and kSFSflagMaxButton. When using kSFSflagAutoLayout, the user can drag and drop the title bar of the panels in the set, to re-order them. If you open a modal subform in a set with kSFSflagAutoLayout set, the modal form opens at the top of the parent form, and does not become part of the vertically laid out forms.

kSFSflagParentWidth

Only applies when kSFSflagAutoLayout is specified. Ignores the width parameter for each set member, and sets the width of each subform to the width of parent. This flag also sets edgefloat for each subform to kEFright. Using kSFSflagParentWidth allows you, for example, to create a paged pane page populated with panels implemented as subforms, where the panels resize when the paged pane resizes.

kSFSflagSingleOpen

Only applies when kSFSflagAutoLayout and kSFSflagMinButton are both specified. When specified ensures that at least one window is always open.

kSFSflagMinButtonIsTitle

The minimize button icon is removed and the whole title bar becomes the minimize button. Only applies when kSFSflagAutoLayout is specified.

Expanding and Collapsing Subform panels

End users can expand or collapse (open or close) subform panels using a single click (in previous versions, a double-click was required). This is enabled by making the title bar on the subform behave like the minimize button, and therefore the title accepts single clicks. The kSFSflagMinButtonIsTitle flag for the ‘subformset_add’ action needs to be set to allow this behavior, and only applies when kSFSflagAutoLayout is specified.

When in auto layout mode, and not using single open or open minimized modes, you can indicate that a form is to be opened minimized modes by prefixing its class name with the ~ (tilde) character. This means that when you open a number of subforms in a subform set, you can specify which subforms will open minimized (collapsed).

Subform Panels Example

The following example of a set of subform panels contained in a paged pane (available in the Samples section in the Hub), with both the auto layout and parent width flags set.

image11

The following method constructs the subform set and assigns it to a paged pane in the remote form. In this case, the subform only contains an edit control which receives some text to be displayed in the subform (“This is panel #”). The list of subforms is built including the text and background color which is assigned to a paged pane using a row variable and the subformset_add client command.

# create list vars lFormList and lSetRow and all columns
# create the list of subforms in lFormList
Do lFormList.$define(lFormID,lClassName,lFormParams,lFormTitle,lFormLeft,lFormTop,lFormWidth,lFormHeight)
Do lFormList.$add(1,'jsSubformSetPanelsSubForm',con(1,chr(44),rgb(221,221,255),chr(44),chr(34),"This is panel 1",chr(34)),'Panel 1',,,,160)
Do lFormList.$add(2,'jsSubformSetPanelsSubForm',con(2,chr(44),rgb(204,204,255),chr(44),chr(34),"This is panel 2",chr(34)),'Panel 2',,,,160)
Do lFormList.$add(3,'jsSubformSetPanelsSubForm',con(3,chr(44),rgb(187,187,255),chr(44),chr(34),"This is panel 3",chr(34)),'Panel 3',,,,160)
Do lFormList.$add(4,'jsSubformSetPanelsSubForm',con(4,chr(44),rgb(170,170,255),chr(44),chr(34),"This is panel 4",chr(34)),'Panel 4',,,,160)
# construct the row for the subformset_add command in lSetRow
Do lSetRow.$define(lSetName,lParent,lFlags,lOrderVar,lFormList)
Do lSetRow.$assigncols("SubformPanelsSet",'PagedPane:1',kSFSflagSingleOpen+kSFSflagMinButton+kSFSflagAutoLayout
+kSFSflagParentWidth,'iOpenForms',lFormList)
Do $cinst.$clientcommand("subformset_add",lSetRow)

In this case the flags kSFSflagSingleOpen, kSFSflagMinButton, kSFSflagAutoLayout, and kSFSflagParentWidth have been summed to create the complete properties for the set of panels.

An example containing a set of Subform Panels is available in the JavaScript Components Gallery on the Omnis website.

If you associate a subformset with a paged pane and you add a new MODAL form to the set, the new subform window will be associated with the remote form as a whole, rather than the paged pane.

Subform Set Example

The following code creates a subform set containing two subforms.

# the following setupSubformSet method could be called from $construct
# Create vars: iFormList (List), iID, iClassName, iParams, iTitle, iLeft, iTop, iWidth, iHeight
# Create local vars in setupSubformSet: lRow (Row), lSetName, lParent, lFlags, lOrderVar
# jsSub1 and jsSub2 are remote forms in the library
Do iFormList.$define(iID,iClassName,iParams,iTitle,iLeft,iTop,iWidth,iHeight)
Do iFormList.$add(1,"jsSub1",,"subform1",10,10,200,200)
Do iFormList.$add(2,"jsSub2",,"subform2",220,10,400,200)
Do lRow.$define(lSetName,lParent,lFlags,lOrderVar,iFormList)
Do lRow.$assigncols("SubformSet",,kSFSflagCloseButton+kSFSflagMaxButtonkSFSflagMinButton+kSFSflagResize,,iFormList)
Do $cinst.$clientcommand("subformset_add",lRow)

The code creates the subforms in the main remote form within the browser:

image12

The Memo sample app available in the Applets section of the Hub uses subform sets.

Using Subform Palettes

A Subform Palette is a subform that can be opened next to a specified control. Such a subform could allow the end user to set an option, or to provide some information such as a help tip. Subform palettes can be opened or closed using the client commands subformpaletteshow and subformpaletteclose, or a subform palette can be closed by clicking outside the subform.

image13

There is an example application called JS Subform Dialogs in the Samples section of the Hub in the Studio Browser showing how to use the subform palette client commands.

Showing a Subform Palette

The subformpaletteshow command shows a remote form as a subform palette:

Do $cinst.$clientcommand("subformpaletteshow",row)

Where rowVariable is row(cClass, cParams, cControl, iWidth, iHeight [,iPositionFlags] [,bShowOverlay] [,cTitle] [,bPreventClose])

The row variable parameters are as follows:

Parameter Description
cClass Character, the class name of the remote form to use in the palette.
cParams Character, parameters to pass to the remote form, e.g. you could pass a message (text) to be displayed in the subform palette, as in the example app.
cControl Character, the name of the related control to pop up the palette next to.
iWidth Integer, the width of the subform palette.
iHeight Integer, the height of the subform palette.
iPositionFlags Integer (Optional), a combination of up to 2 kSFSPalette... constants to specify the position of the palette; see description of flags below.
bShowOverlay Boolean (Optional), if kTrue, shows the form overlay while the palette is open (defaults to kFalse).
cTitle Character (Optional), the title of the subform (this is not displayed anywhere, but is used to populate the aria-label property of the palette for screen readers).
bPreventClose Boolean (Optional), if kTrue, the user cannot close the palette by clicking outside it (defaults to kFalse); in this case, you must use subformpaletteclose to close the palette.

If the control name given in the cControl parameter is not found (or you omit the name), the palette dialog will be centered in the browser window, and the arrow is not displayed since there is no control for it to point at.

The iPositionFlags parameter (positioning flags) should contain up to 1 Position flag (top, right, bottom, or left) and 1 Align flag (start, center, or end) to set the position of the subform palette relative to the control specified in cControl. The default is kSFSPalettePosFlagRight+kSFSPaletteAlignFlagCenter to position the palette window to the right and in the center of the control.

Constant Description
kSFSPalettePosFlagTop Position the palette above the related control
kSFSPalettePosFlagRight Position the palette to the right of the related control
kSFSPalettePosFlagBottom Position the palette below the related control
kSFSPalettePosFlagLeft Position the palette to the left of the related control
kSFSPaletteAlignFlagStart Aligns the palette at the start of the specified position (top/right/bottom/left)
kSFSPaletteAlignFlagCenter Aligns the palette in the center of the specified position (top/right/bottom/left)
kSFSPaletteAlignFlagEnd Aligns the palette at the end of the specified position (top/right/bottom/left)
kSFSPaletteHideArrow Additional flag to hide the arrow normally shown on the palette window

You can hide the arrow on the palette window by adding kSFSPaletteHideArrow to the iPositionFlags row parameter, in addition to the positioning flags.

If the palette were to overlap the opposite side of the control, e.g. because of the lack of space, Omnis will try to place the subform on a different edge automatically. If Omnis cannot place the subform in an acceptable position, it will fallback to using the initial state. There is also an arrow which will point to the center of the given control. However, it is restricted by the size of the subform palette, and so will be placed towards the edge of the palette closest to the center of the control, as appropriate.

In the example app (in the Hub), the following code is in the $event method for the button which opens a subform palette next to the button (iPaletteMessage is populated with a text message from the form, while iPalettePosValue and iPaletteAlignValue are taken from droplists in the form):

Do $cinst.$clientcommand("subformpaletteshow",row("jsSFDPalette",con(kDq,iPaletteMessage,kDq),"ShowPalette",220,120,
iPalettePosValue+iPaletteAlignValue,kFalse,"MyTitle"))

Closing a Subform Palette

The subformpaletteclose client command closes the top-most subform palette. No row parameter is required. Note the end user can close a subform palette by clicking outside the subform (which can be prevented using bPreventClose).

Running JavaScript in the Client

The JavaScript: command (including the colon) allows you to execute any native JavaScript in the client browser directly from your Omnis code; this can include calls to other JavaScript embedded into or linked to the HTML page containing your JavaScript remote form. Omnis does not perform any validation of the code you insert into the JavaScript: command in the method editor (you can check for errors in the JavaScript console of the browser). You cannot include any square bracket notation in the code parameter of the JavaScript: command, since the code needs to be evaluated by the server when generating the script file. A simple example would be to open an alert in the browser with the standard alert() function, as follows:

JavaScript: alert("Hello World"); 

Since this command executes native JavaScript code on the client it must be executed in a client-side method. The JavaScript: command will only appear in the Command list in a method that is enabled to execute on the client. Omnis will not allow the JavaScript: command to be present in a server method (an error occurs). If you try to execute JavaScript: on the server, by calling a client-side method from a server method, a debugger error will occur.

You can include JavaScript in the HTML page containing your remote form (inline or linked), and call code in these scripts from your remote form code using the JavaScript: command. To extend the alert() example above, you could embed a JavaScript function in your HTML page, like this:

<html>
  <head>
    <script type="text/javascript">
    function show_alert()
    {
      alert("Hello World");
    }
    </script>
  </head>
  <body>
    <!-- body including the omnisobject containing your form -->
  </body>
</html>

And call this function from your Omnis code using the JavaScript: command as follows:

JavaScript: show_alert(); 

Another example could include using the JavaScript: command to “push” events to Google Analytics to track certain actions or events in your application. To do this you would need to add the standard Web Analytics code provided by Google into your HTML page (containing your remote form) and call the gaq.push() function with the correct parameters from within your Omnis code.

Example Using the JavaScript: Command

A possible use for the JavaScript: command is for an event handler. You could use the $init method to install an event handler, such as:

JavaScript: document.getElementById("jsTEMP1_1076_client").onselect=function(event) { __form.callMethodEx("selected",0,event); };
JavaScript: window.addEventListener("keydown",function(event){ __form.callMethodEx("keydown",0,event) }true);

Note that in both of these examples you can use __form.callMethodEx to call an instance method of the remote form. The second parameter (zero in these examples) are flags which control how callMethodEx behaves – these must always be passed as zero.

You could use the $init method to assign additional style information to controls on the form. For example:

Do $cinst.$objs.$sendall($cinst.$addboxshadow($ref))

$addboxshadow is a form method with parameter pObj. The following JavaScript: command adds a box shadow if the browser supports it.

JavaScript: pObj.elem.style.boxShadow="0px 0px 5px 5px #888888";

Addressing control elements

A common requirement when using custom JavaScript in the JS Client is to get hold of an HTML element within a control on the page.

This is best achieved by first using Omnis notation in your client method to store a reference to the control in a local variable. This variable will then contain the client representation of the Control instance.

You can then use the Control's elem property to get its outer 'Frame' element. Or (more often) use its getClientElem() method to get its inner 'Client' element.

Calculate lCtrl as $cinst.$objs.myButton

JavaScript: var ctrllCtrl.getClientElem();
JavaScript: ctrl.style.backgroundColor = "#FF5555";

Most controls are relatively complex and will have further elements within the 'Client' element. You could, for example, use the native querySelector() method on your Client element to find a specific descendant element.

Styled Text

You can insert various text styles in some of the JavaScript components wherever text is displayed. For example, you can insert colors, font styles, and images into the text within the list control, the droplist control, the data grid control, and the hyperlink control.

Text styles can be inserted using the style() function, in both server and client methods. The style() function inserts a style-character represented by an Omnis constant into a calculation or a text block. The styles that can be used include some of the general constants (listed under 'Text Escapes' in the Omnis Catalog) and a few others prefixed kEscJs... supported in the JavaScript Client. The following style constants can be used:

Style Description
kEscColor In a client-side method, the color parameter can be a numeric literal, a constant such as kRed, or HTML color string enclosed in double quotes.
kEscStyle In a client-side method, the style parameter must be a numeric literal or constant.
kEscBmp In a client-side method, the icon id parameter must be either a numeric literal, or the sum of a numeric literal and an icon size constant e.g. 1710+k48x48
kEscJsNewline No additional parameters are required. Inserts a
line break tag. See *
kEscJsClose No additional parameters are required. Closes the current open style information (inserted by kEscColor or kEscStyle) in the styled text and reverts to the original color and text style. Note - kEscColor and kEscStyle insert a <span> tag to style the text. kEscJsClose closes the <span> tag.
kEscJsHtml Inserts raw HTML (the second parameter to style()).

* You can use the br() function as a short-hand to insert a new line. The br() function and kEscJsNewline can only be used with styled text for the JavaScript Client.

The parameters for style() can use any HTML color string, such as "#FF0000". For client methods that execute on the client, the color parameter must be a literal string and therefore enclosed in double quotes. For example, style(kEscColor,"#FF0000"), or style(kEscColor,"rgba(0,0,255,0.5)"). Omnis does not validate the HTML color syntax, so you should check the syntax is correct to avoid runtime errors.

The following example code produces a list line which looks like this from the styled text data in iChar:

image14
Calculate iFloatRight as style(kEscJsHtml,"<span style='float:right;'>")
Calculate iFloatLeft as style(kEscJsHtml,"<span style='float:left'>")
Calculate iSmallFont as style(kEscJsHtml,"<span style='font-size:8pt'>")
Calculate iCloseSpan as style(kEscJsHtml,"</span>")
Calculate iIcon as style(kEscBmp,1710+k32x32)
Calculate iOpenP as style(kEscJsHtml,"<p style='height:36px;margin:0px'>")
Calculate iCloseP as style(kEscJsHtml,"</p>")
Begin text block
  Text: [iOpenP][iFloatLeft]Left text[iCloseSpan]
  [iFloatRight]Right[iIcon][iCloseSpan][br()]
  [iSmallFont][style(kEscStyle,kItalic)]
  [style(kEscColor,kRed)]Line 2[iCloseSpan][iCloseP]
End text block
Get text block iChar

Animations

JavaScript remote forms have the methods $beginanimations() and $commitanimations() which allow you to control animations for some controls. The animated properties are: left, top, width, height, alpha, backcolor, backalpha, textcolor, fontsize, bordercolor, linestyle, buttoncolor (the latter is for pushbutton only).

There is a sample app called Animations in the JavaScript Component Gallery, and under the Samples option in the Hub in the Studio Browser showing how you can animate component changes such as size, position, and transparency.

The syntax for the $beginanimations() method is:

If you set the same property for an object more than once, the first property change is animated, and then the last property change is animated when the first completes. Property changes between the first and last are ignored. The evAnimationsComplete event (for remote forms) is generated after the last property change(s) have completed. This allows you to reverse the effect of an animation (which is the equivalent to the autoreverse/repeat options available on iOS).

The About form in the example app is loaded into a subform using animations, which initially has the $alpha value of zero (fully transparent) and is increased to 255 during the animation, as follows:

# method behind About button
On evClick
  Switch iScreensize
    # set aboutSubForm size for different devices
    # etc.
  End Switch
  Do $cinst.$objs.aboutSubForm.$classname.$assign("jsAbout")
  Do $cinst.$objs.aboutSubForm.$visible.$assign(kTrue)
  Do $cinst.$beginanimations(500,kJSAnimationCurveEaseIn)
  Do $cinst.$objs.aboutSubForm.$alpha.$assign(255)
  Do $cinst.$commitanimations()

Time Zones and Dates

The JavaScript Client exchanges dates and times between the server and client using UTC time, regardless of where your server is located (note that UTC is essentially the same as GMT but UTC is used globally as the standard time for web servers). You should therefore store all dates and times in UTC and use the time zone offset of the client to either determine or set the local time of the client. The $construct row variable parameter for the remote task/form has a column JStimezoneOffset, which is the timezone offset in minutes for the client relative to UTC time. For example, if the client’s local time zone is UTC+2 (or GMT+2), JStimezoneOffset will be 120. See the Construct Row Variable section for more information about the $construct row variable for tasks/forms.

Time Zone Functions

There are a number of Omnis functions that allow you to convert local dates and times to UTC since the client and server need to both use UTC time: they are listed in the ‘Date and Time’ group in the Omnis Catalog (F9/Cmnd-9).

You should note that on 32-bit Windows the TZ codes returned by the timezone (tz) functions are the long time zone names and not the short abbreviated time zone names. If you want to use the short time zone names, you can add a mapping to studio.stb, from the full name to the abbreviation you wish to use.

Local Time

The $localtime task property allows you to switch to Local time rather than UTC. If true, the JavaScript Client and the Omnis App Server exchange date-time values in local time rather than UTC time. $localtime must be set in design mode: it cannot be assigned at runtime.

Date and Time Conversion in SQLite

When converting Date and Time data in a SQLite database to dates in a remote form (i.e. in the JavaScript client), the subtype of any Date/Time data is taken into consideration. In this case, 'Short Date...' data subtypes will return a date only (no time component), and 'Time' data subtypes will return a time only (no date component).

PDF Printing

The PDF Device is a printing device (external component) to allow you to print a report from Omnis to a PDF file and display it in the JavaScript Client in the end-user’s web or mobile browser. There are two client commands (used with $clientcommand) to allow you to handle PDF reports (if the end user’s device supports PDF). See the Report Programming chapter in the Omnis Programming manual for more information about creating report classes to format your PDF reports; this section describes the PDF Device.

There is an example app called JS PDF Device in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

Supporting Files

The PDF Device component is available for Windows and macOS and is located in the ‘xcomp’ folder and is loaded automatically.

The PDF Device component is available for Windows and macOS and is loaded automatically. It is located in the ‘xcomp’ folder on Windows and the ‘PlugIns’ folder on macOS.

Node.js

Omnis uses Node.js to print reports which is installed ready to use in Omnis Studio. Note that Node.js is used for PDF printing in Omnis (as well as several other functions) subject to the MIT license from PDFKit: https://github.com/foliojs/pdfkit/blob/master/LICENSE

Note: In versions prior to Studio 11, Python (reportlab) was used for PDF printing, but this is no longer used and the python.zip file has been removed from the Omnis development tree. If you are converting to Studio 11, you do not need to adjust your application code or interface to use Node.js.

Fonts

The PDF device will only work with Reports that use TrueType fonts, and using other fonts may cause an error during PDF generation. Specifically only fonts contained in “.ttf”, “.ttc” or “.dfont” files can be used. Therefore you must choose TrueType fonts for your report if you intend to print using the new PDF device.

PDF Print Destination

The component is called OmnisPDF and the “Print to PDF” option appears in the Print Destination dialog, available to end users from the main File menu. If the end user selects PDF as the report destination, then when they print a report, it will either be sent to a report file specified in $prefs.$reportfile, or if this preference is empty Omnis will prompt the user to select the path of the output PDF file. Note that this mechanism can be overridden programmatically by using the $settemp method (see below).

PDF Folder

You can specify an alternative folder in which to place PDFs, rather than using the default “omnispdf” folder. There is an item called "omnispdfFolder" in the "pdf" section in config.json that allows you to specify the path of a folder to receive PDFs, overriding the default location. The item defaults to empty, which means Omnis will use the current “omnispdf” folder. The folder specified in "omnispdfFolder" must already exist, otherwise Omnis reverts to the default omnispdf folder.

Printing PDF Using Code

To send a report to PDF programmatically, you can use the following code:

Calculate $cdevice as kDevOmnisPDF
Set report name MyReportClass
Print report
; or
Calculate $cdevice as kDevOmnisPDF
Set reference lReportInst to $clib.$reports.NewReport.$open('*')
Do lReportInst.$printrecord()
Do lReportInst.$endprint()

In both of these cases the report will be sent to a report file specified in the $prefs.$reportfile preference. Note that there is a separate value of $prefs.$reportfile for each Omnis App Server stack (thread) and the main Omnis thread. If $prefs.$reportfile is empty, and the code is running in the main Omnis thread, Omnis will prompt the user for the destination PDF file; otherwise, if $prefs.$reportfile is empty and the code is running in another thread, Omnis will generate a runtime error.

PDF Device Functions

The PDF device has a number of functions to allow you to set up reports sent to temporary PDF files, to set up document properties, and to add security features such as passwords and encryption. See also PDF Version and Encryption and PDF/A support.

$settemp()

The $settemp function allows you to specify that the next report will print to a temporary PDF file in the omnispdf/temp folder. The function returns the name of the file that will be created in omnispdf/temp (or an empty string if bTemp is kFalse). You can specify a timeout in minutes whereupon the temporary PDF file will be deleted.

Do Omnis PDF Device.$settemp(bTemp,iTimeoutReturns cID
Parameter Description
bTemp A Boolean: kFalse means a temporary file will not be used. kTrue means the next report sent to PDF by the current task instance will be written to a temporary file in the folder “omnispdf/temp” in the data part of the Omnis Studio tree. Note that after the next report has been sent to PDF, the stored value of bTemp will revert to kFalse.
iTimeout An integer: Only used when bTemp is kTrue. If omitted defaults to 10. The time in minutes for which the next PDF file generated by the current task will remain on disk. When the time expires, the Omnis PDF device automatically deletes the file. Note that Omnis automatically deletes any files left behind in omnispdf/temp when it starts up.

Each task instance (including remote tasks) stores its own information set up using $settemp. This allows $settemp to be used in one thread on the Omnis Server without effecting other threads/clients.

$setdocinfo()

The $setdocinfo function lets you specify the author, title and subject properties for the PDF documents generated by the current task. The author, title and subject parameters are all strings, and the function returns kTrue for success.

Do Omnis PDF Device.$setdocinfo(cAuthor,cTitle,cSubjectReturns bOK

You can add keywords to the PDF file’s metadata by adding extra parameters to $setdocinfo, specified as a string of comma-separated keywords, for example:

Do Omnis PDF Device.$setdocinfo(cAuthor,cTitle,cSubject,'keyword1, keyword2, keyword3') Returns bOK

$encrypt()

The $encrypt function sets encryption (security) properties for the PDF documents generated by the current task, and the function returns kTrue for success. The full syntax is:

Do Omnis PDF Device.$encrypt(cUserPassword[,cOwnerPassword='',bCanPrint=kTrue,bCanModify=kFalse,bCanCopy=kTrue,bCanAnnotate=kFalse]) Returns bOK

The parameters are as follows:

Parameter Description
cUserPassword A character string: The user password for the document. If this is set to empty then none of the other arguments apply and the document will not be encrypted; otherwise the document will be encrypted and the user password and other properties specified by this function will be applied to it.
cOwnerPassword A character string: The owner password for the document. The default is no password is assigned.
bCanPrint A Boolean: Specifies if the user can print the PDF document. The default is kTrue.
bCanModify A Boolean: Specifies if the user can modify the PDF document. The default is kFalse.
bCanCopy A Boolean: Specifies if the user can copy from the PDF document. The default is kTrue.
bCanAnnotate A Boolean: Specifies if the user can annotate the PDF document. The default is kFalse.

Security in Third-party PDF readers

The optional security parameters will be applied to the PDF file if you include them in the $encrypt() function, but you should note that the third-party PDF viewer the end user is using may not support these settings or may just choose to ignore them. The password specified in cUserPassword should be interpreted by all PDF readers.

$embedfile()

The $embedfile() function allows you to embed a file in a PDF file, such as an XML file. If cName is omitted, the name of the file in cFilePath is used.

Do Omnis PDF Device.$embedfile(cFilePath[, cName])
Parameter Description
cFilePath The pathname of the file
cName The file name

$embeddata()

The $embeddata() function allows you to embed the data with the given name in a PDF file.

Do Omnis PDF Device.$embeddata(cDatacName)
Parameter Description
cData The data to be embedded
cName The file name

Completing PDF Printing

When a PDF report completes, the device sends a message to the task (or remote task) that printed the report. The message is $pdfcomplete, and it takes two arguments:

1. The pathname of the output report file.

2. A Boolean which is true for success, false if an error occurred generating the PDF.

Icons and Vertical Text

You can include icons in text in a report printed to PDF using the style() function and the kEscBmp escape constant. For example, you can use con(style(kEscBmp,1400),’some text’) in a report entry field calculation to display an icon on a report.

In addition, you can print vertical text in a PDF report using the kEscAngle text escape and the kAngle90 or kAngle270 constants to rotate the text, for example, con(style(kEscAngle,kAngle270),iTextLine1).

See Styled Text for more information about using the style() function and text escapes.

PDF Printing in the JavaScript Client

PDFs generated by the PDF device can be used with the JavaScript Client. The showpdf and assignpdf client commands can be used with $clientcommand to display PDF files on the client. You should avoid generating large PDF documents to use with the JavaScript Client since the generated PDFs are streamed from the Omnis App Server (i.e. via a Web Server). An alternative would be to output the PDF document into the Web Server’s file system and link to it using a URL to the PDF on the Web Server and the getpdf command to send it to the client: see Linking to PDFs.

There is an example app called JS PDF Device in the Samples section in the Hub in the Studio Browser showing how you can print reports to PDF in the JS Client.

showpdf

The showpdf client command opens the specified PDF in a new browser window or tab. There is no control over whether the PDF is opened in a new window or tab: typically, this depends on the end-user browser settings, including their setting for popups.

Do $cinst.$clientcommand("showpdf",row)

Where rowVariable is row(pdf-id, timeout, pdf-filename)

The following method generates a PDF and displays it on the client:

Calculate $cdevice as kDevOmnisPDF
Do Omnis PDF Device.$settemp(kTrue,1) Returns lID
Set report name New Report
Do Omnis PDF Device.$encrypt('bob','owner',1,0,0,0)
Do Omnis PDF Device.$setdocinfo('Bob','Title','Subject')
Print report
Do $cinst.$clientcommand("showpdf",row(lID,20))

assignpdf

The assignpdf client command opens the specified PDF in a PDF viewer control in the current remote form instance. The PDF must be assigned to an HTML control in the remote form which tries to open the PDF file using the PDF viewer installed in the end user’s browser.

Do $cinst.$clientcommand("assignpdf",row)

Where rowVariable is row(html-object-name, pdf-parameters, pdf-id, timeout, pdf-filename)

The following method creates a report and assigns it to an HTML control in the remote form.

Calculate $cdevice as kDevOmnisPDF
Do Omnis PDF Device.$settemp(kTrue,1) Returns lID
Set report name New Report
Do Omnis PDF Device.$encrypt('bob','owner',1,0,0,0)
Do Omnis PDF Device.$setdocinfo('Bob Smith','Title','Subject')
Print report
Do $cinst.$clientcommand("assignpdf",row("htm","toolbar=1&zoom=20",lID,10))

If you set the $html property of the HTML Object control to “<div %e></div>” the PDF viewer will have the same border, position and dimensions as the designed control on the remote form. Note that this command will not work on Android with the default web browser, since it does not support the application/pdf plug-in. If the application/pdf plug-in is not available on Android, it executes showpdf instead.

PDF Path Names

The character length of the path name when creating a PDF is unlimited (in versions prior to Studio 11, the limit was 255 characters). Under Windows, for very long path names, you may need to enable long paths by setting the registry key Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnable to 1 and restart.

PDF Version and Encryption

You can set the PDF version and encryption used in the PDF file using the Omnis PDF Device.$setpdfversion function, which can be one of the kDevOmnisPDFVersion... constants identifying the PDF version and encryption to be used when encrypting the PDF file. The default is kDevOmnisPDFVersion13 which specifies 40-bit RC4 encryption. The following constants are available:

Constant Description
kDevOmnisPDFVersion13 Version 1.3, 40-bit RC4 encryption
kDevOmnisPDFVersion14 Version 1.4, 128-bit RC4 encryption
kDevOmnisPDFVersion15 Version 1.5, 128-bit RC4 encryption
kDevOmnisPDFVersion16 Version 1.6, 128-bit AES encryption
kDevOmnisPDFVersion17 Version 1.7, 128-bit AES encryption
kDevOmnisPDFVersion17ext3 Version 1.7 ExtensionLevel 3, 256-bit AES encryption

PDF/A support

You can set the PDF/A subset type for a PDF file, which is used to create archival versions of documents. The standard version PDF/A-1 is supported, as well as PDF/A-2 a/b and PDF/A-3 a/b.

You can use the Omnis PDF Device.$setpdfsubset function to set the PDF/A subset type using one of the following constants:

Constant Description
kDevOmnisSubsetPDFA1a PDF/A-1a - Part 1 Level A (accessible) conformance
kDevOmnisSubsetPDFA1b PDF/A-1b - Part 1 Level B (basic) conformance
kDevOmnisSubsetPDFA2a PDF/A-2a - Part 2 Level A (accessible) conformance
kDevOmnisSubsetPDFA2b PDF/A-2b - Part 2 Level B (basic) conformance
kDevOmnisSubsetPDFA3a PDF/A-3a - Part 3 Level A (accessible) conformance
kDevOmnisSubsetPDFA3b PDF/A-3b - Part 3 Level B (basic) conformance
kDevOmnisSubsetNone Unsets the PDF subset

If you wish to unset the PDF subset, you can use the kDevOmnisSubsetNone constant with the $setpdfsubset() function.

Linking to PDFs

You can use the getpdf parameter when executing a URL such as the following to reference a PDF:

http://127.0.0.1:5912/jsclient?__OmnisCmd=getpdf,C:\myreport.pdf

To enhance security, the getpdf parameter only gets files with a “.pdf” extension, and it only works with parameters that are associated with an open remote task instance which is stamped with a creation time value.

Setting PDF Folders

To enhance security, you can limit the folders from which PDF files can be retrieved using showpdf, assignpdf, or getpdf by specifying the folders in the config.json configuration file, and thereby excluding all other folders. To do this you need to add the getpdfFolders item to the “server” member in config.json and list the folders. For example:

 "getpdfFolders": [
    "c:\\dev\\unicoderun",
    "c:\\dev\\temp"
  ]

The item can be an array of folder paths, and any subfolders of a configured folder is also allowed. Each entry is a valid folder path, without a trailing file separator.

The following methods will allow the end user to print a report to a PDF file: these methods use the built-in PDF Device methods and the client commands.

# button to open PDF report
# create var lID (Char)
On evClick
  Do $cinst.$createReport() Returns lID
  Do $cinst.$clientcommand("showpdf",row(lID,60))
# or button to display PDF report in current remote form
# create var lID (Char), oHTML is an HTML obj on the form
On evClick
  Do $cinst.$createReport() Returns lID
  Do $cinst.$clientcommand(  "assignpdf",row("oHTML","toolbar=1&zoom=20",lID,20))
  
# the code for the $createReport() remote form method:
Calculate $cdevice as kDevOmnisPDF
If iSaveCopy ;; linked to check box on the form
  Do Omnis PDF Device.$settemp(kFalseReturns lID
  Calculate lSaveLocation as left(sys(10),rpos(sys(9),sys(10)))
  Calculate lSaveLocation as
   con(lSaveLocation,"savedReports",sys(9),iFileName)
  Calculate $prefs.$reportfile as lSaveLocation
Else
  Do Omnis PDF Device.$settemp(kTrue,1) Returns lID
End If
Set report name repNice
If iEncrypt
  Do Omnis PDF Device.$encrypt(
    iUserPass,iOwnerPass,iCanPrint,iCanModify,
    iCanCopy,iCanAnnotateReturns #F
End If
Do Omnis PDF Device.$setdocinfo(iAuthor,iTitle,iSubjectReturns #F
Print report
If iSaveCopy
  Quit method lSaveLocation
Else
  Quit method lID
End If

Toast Messages

Toast messages are small notification type messages that that can be “popped up” in a remote form to alert the end user about something: the concept is derived from “toast messages” on Android. (Note this section refers to toast messages for remote forms and not desktop toast messages.)

Toast messages are activated using the “showtoast” client command ($cinst.$clientcommand) which displays a message to the user in a small popup window which disappears after a timeout, either 5000ms or specified amount.

Do $cinst.$clientcommand("showtoast",row)

Where rowVariable is row(text, [timeout, posX, posY, containerName, floating, originX, originY, speakMessage, assertive])

The toast message rowVariable parameters are:

Parameter Description
text The message text. The container’s size will scale with the amount of text. You can use ‘\n’ to insert a new line.
timeout (Optional) The length of time (ms) the message will be shown for (5000 ms by default).
posX (Optional) The horizontal position of the toast message in pixels. Centered if not specified. If containerName is specified, this position is relative to the control.
posY (Optional) The vertical position of the toast message in pixels. Positioned near the bottom of the form if not specified. If containerName is specified, this position is relative to the control.
containerName (Optional) The name of the control to position the toast message relative to. Options are limited to paged pane and subform controls.
fixed (Optional) This determines whether or not the toast message will stay in position when the container scrolls (true by default).
originX (Optional) The toast message’s origin that posX references. Possible values are: kLeftJst (default), kRightJst and kCenterJst.
originY (Optional) The toast message’s origin that posY references. Possible values are: kJstVertTop (default), kJstVertMiddle and kJstVertBottom.
speakMessage (Optional) If true, screen readers will announce the message. This is an accessibility feature to convey information to visually impaired users.
assertive (Optional) If speakMessage is true, this instructs screen readers whether or not to interrupt current speech.

The originX and originY parameters are used to set the point on the toast message that posX and posY reference. For example, if originX is kRightJst and originY is kJstVertBottom, the bottom right corner of the toast message will be at the position specified by posX and posY.