Chapter 2—JavaScript Remote Forms

To create a web or mobile application in Omnis, 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 JavaScript remote form using the “Test Form” option (press Ctrl/Cmnd-T or Right-click on the form) and the Remote form will open in the web browser on your development computer. The remote form and the components you have added to the form are embedded into a simple HTML file in the JavaScript Client object and are rendered in the browser using JavaScript and CSS.

In order 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 and any current connections to web or mobile clients. 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 described in the next section.

The App Builder

You can create an application containing JavaScript remote forms using the App Builder, which is available via the New Library option, under the Libraries option in the Studio Browser. The App Builder can create JavaScript remote forms automatically, including all the necessary JavaScript components and navigation, based on an existing SQL database, or from an imported comma- or tab-delimited file. The remote forms created by the App Builder are set up to use responsive layouts. You can build or prototype an app quickly and easily using the App Builder, which may provide you with a good starting point for creating your JavaScript remote forms.

JavaScript Client

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

Once you have set $client and added some JavaScript components to the form, the $client property is grayed out and you can no longer change the property in that form. You can only change $client when the remote form is empty, but for all new remote forms you should keep it set to kClientJavaScript.

iOS Client and WebClient Plug-ins

The kClientiOS and kClientPlugin values of $client enable remote forms for the ‘iOS Client’ plug-in and the ‘Web Client’ plug-in, respectively, however these plug-ins are no longer supported in Omnis, and are present in $client for backwards compatibility only. They should not be used for new web or mobile applications.

Remote Form Name

Like any other class in Omnis, the name of a new Remote form can be anything you like, but 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 “rf”.

However, 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 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. For example, 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.

Creating a Remote Form using a Wizard

To use the Remote Form Class Wizard you need to open a database session and your library must contain a Schema class: when you step through the wizard you will be asked to select a database session name and schema class to link to your remote form. The remote forms created using the Remote Form wizard are set up to use responsive layouts.

This section assumes you have a schema class in your library and that you have opened a database session. If not, you might like to follow the steps in the Tutorial in Chapter 1 to create a schema class and database session, including the sections: "Creating a database session", "Opening a database session", "Making a schema", and "Editing a schema". Alternatively, you could open the PICS2 library in the ‘final’ folder (also available in the download) as a starting point, e.g. you can open PICS2, rename the existing ‘PicsWebForm’ remote form and step through this section to learn how to create a new remote form using the Remote Form wizard.

To create a new JavaScript Remote Form

Assuming that you have created a schema class in your library and you have opened a database session (as described in the tutorial):

image1

image2

image3

When you create a remote form in your library you also need to create a Remote Task: this is required at runtime to handle all the remote form instances running on the clients, and without it you will not be able to test or run your remote form.

image4

For the next stage of the wizard, you can select the type of remote form created, based on a schema class (or query class) in your library. (The Parent / Child option requires two schema classes linked in a parent/child relationship.)

image5

image6

For this stage of the wizard you can select the SQL class to be linked to your remote form: this will either be a Schema class or Query class, the latter is a type of data class that lets you combine one or more schema classes or individual columns from one or more schemas.

Note that you can expand the tree list to display all the columns in your schema class which would allow you to select individual columns to be added to your remote form. If you check the schema name in the list, all the columns in that schema will be selected.

The MyPictures schema class will be in the Pics library if you have followed the appropriate sections in the tutorial (or opened one of the PICS libraries in the ‘final’ folder): if a schema class is not displayed you will have to cancel the wizard and create one, or this might be because you have not opened a SQL session.

The next stage of the wizard lets you select an open database session.

image7

The PICSESS session will be in the SQL Browser if you have followed the appropriate sections in the tutorial, or if you are using the pics2.lbs in the ‘final’ folder, the session should be opened for you automatically. If a session is not displayed in the wizard you will have to cancel the wizard and open a session in the Studio Browser.

When the wizard is completed, your remote form will be opened in Omnis in design mode.

image8

The Property Manager will appear on the right side of the Omnis IDE window, and the Component Store will open at the bottom of your screen. You can Right-click on the background of the form and select Test Form to open the remote form in a web browser, or you can press Ctrl/Cmnd-T to test a remote form.

JavaScript Components

When you edit a remote form (in design mode), the Component Store is displayed and shows a set of components for the JavaScript Client.

image9

To display the Component Store as above you can Right-click on the background of the window and select the Text option to show text labels, and then you may need to enlarge the window to display all the components. You can Right-click on the Component Store and select the Save Window Setup option to store the layout of the window.

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

Remote Tasks

In order to test or run your remote form in a web browser, your library should contain a Remote Task and the $designtaskname property of your remote form should be set to the name of a remote task in the current library. When you create a new remote form from the Studio Browser, and if your library contains a single remote task, the $designtaskname property will be set to the name of that remote task automatically. If your library does not contain a remote task, you will have to create one manually and set the $designtaskname property of your remote form to the name of the new remote task. If your library has multiple remote tasks, and you create a new remote form from the Studio Browser, the $designtaskname property will not be set, so again you will have to assign this manually before you can test the form.

Creating Remote Task Classes using Wizards

You can create an Omnis remote task from scratch or by using one of the templates or wizards provided in the Studio Browser. Alternatively, when you use one of the Remote Form wizards, you have the option to create a new remote task.

To create a remote task using a template of class wizard

Or to use a class wizard you can:

The following wizards/templates are available:

$enablesenddata Property

The remote task property $enablesenddata should be set to kFalse for all tasks controlling JavaScript remote forms since the $senddata() method is not implemented for JavaScript remote forms.

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

There is a Server Management Library, called ‘servermgmt.lbs’ and located in the clientserver/server folder under the main Omnis folder, which contains the same monitor classes that you can use to monitor an instance of the Omnis App Server.

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.

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 parameter variable contains a column for each parameter of the JavaScript Client object instantiated on the client: therefore, it will include columns for OmnisLibrary and OmnisClass (as defined in your HTML file), as well as extra columns containing additional information about the client object.

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

Column Description
OmnisLibrary <OmnisLibrayName>
OmnisClass <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. You can append extra parameters via the URL for the form which are added to URLparams, a JSON string object
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 (relevant for kLayoutTypeScreen based forms only)
JSDeviceInfo Device screen size and density, e.g. 2048x1152 (devicePixelRatio:2)
userAgent The navigator.userAgent of the client, which usually contains the browser type and version
appName The navigator.appName of the client, i.e. the browser application name, such as “Microsoft Internet Explorer” or “Netscape”
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. “120” for clients on UTC+2
ClientLocale the Locale language setting of the client, e.g. “en_GB” for clients in the UK, or “en_US” for America

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.

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can return information from the construct row.

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 in order 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, as in previous versions, 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 affect; 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.

Creating a push connection

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

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

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. There is a matching client command, closepush, which you can use to close the push connection.

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 Method

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.

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

The Remote Object is a new library class type for Studio 10. Remote Object classes 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.

Why would I use a Remote Object? You may 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 better 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.

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.

Remote Form Properties

Like other types of Omnis class, remote form classes have a number of 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 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 which is described later in this manual, while the $stringtabledata and $stringtabledesignform properties concern Localization which is also discussed later in this manual.

Responsive Forms

Responsive design is a technique used to design form layouts that cater to different devices or screen sizes, including mobile phones, tablets, and desktop screens. 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.

Remote forms in converted libraries (pre-Studio 8.1) will continue to use the $screensize property to specify the layout for different devices. 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. 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 new responsive type. (Note the existing Sync Screen tool only applies to the old $screensize based remote forms, and should not be used for responsive forms.)

Form Layout Type

JavaScript remote forms have a property, $layouttype, that specifies how the layout of the form is designed: it can be set to one of the kLayoutType... constants. This property is only assignable when the remote form is empty, i.e. it does not contain any controls. The possible values for $layouttype are:

You can return the value of $layouttype in a remote form instance, but you cannot set it in your code. 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. See the JavaScript Components chapter for details about using the $edgefloat properties for controls.

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. The remote form wizards, available under the New Class 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 a number of preset layout breakpoints: 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).

image10

You can change these 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 have taken 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).

Clicking on a layout breakpoint in the toolbar makes it the current layout; using the default theme it is highlighted in blue. 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 (the delete option is enabled only if there are two or more breakpoints).

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 two 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 new property called $layoutbreakpoints, which stores the layout breakpoints for a remote form. This is a comma-separated list of breakpoint values, which must have at least two entries, 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 initialised with the value of a new 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, and shown in design mode as a single horizontal line. When the available client height is larger than this value, controls can float to use the additional vertical space, depending on their $edgefloat properties. 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.

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 a new option called "responsiveLayoutPadding" in the "defaults" section of the Omnis configuraration file (config.json), which is set to a default value of 2.

When a remote form is accessed for the first time, e.g. in a converted library, the value of $layoutpadding is initialised 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).

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 (phones, tablets, desktops). 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 6 & 7 are 375 x 667, and the Samsung Galaxy S5 & S6 are 360 x 640, so you could set the first layout breakpoint to 360, or perhaps 350 to allow a safe margin and to accommodate form layouts for both phones.

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.

Adding Controls

You can add JavaScipt controls to a responsive form from the Component Store and set their properties, in exactly the same way as in previous versions. 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.)

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

There is a migration tool, available under the Tools>>Add-Ons menu, JS to Responsive option, that allows you to convert an existing JavaScript remote form in a converted library 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.

image11

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 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 phone.

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 with responsive class names’ 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 versions prior to Studio 8.1, which you are advised not to use for new remote forms. Any remote forms in an existing library which is converted to Studio 8.1 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 ($screensize forms only)

The Sync Screens Tool configures the components on the different fixed screen sizes stored in a single remote form: the tool is only useful for $screensize based remote forms and cannot be used for responsive forms. 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 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 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:

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 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. For this release 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:

The evFormToTop and evSubFormToTop events are discussed in the Multiple Forms section, while evAnimationsComplete is discussed in the Animations section.

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 using the Test Form option, available in the remote form either by right-clicking on the background of the form and selecting Test Form, or by pressing Ctrl-T. The 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 window or create a new separate tab if your browser supports tabs. Omnis has a built-in HTTP server to allow you to test remote forms locally in a browser.

You can switch back to Omnis and continue to change your remote form or its methods, and use Ctrl-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: if your browser is already displaying your remote form, and you have modified the form, you can switch to your browser and Refresh the browser to see the latest changes to your form.

When you test your remote form using Test Form (Ctrl-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 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.

Uaing 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.

Default Web Browser

When you test your remote form using the Test Form option (Ctrl-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 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). If this preference is empty, then the default browser on your development computer will be used for testing remote forms.

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.

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 new 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 section for details about setting up a wrapper application.

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.

$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.

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 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: please note that some commands or functions could be executed in the Web Client plug-in but may not now be executable in the JavaScript client which only allow a smaller subset of commands and functions to be run on the 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) in JavaScript 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. 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.

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.

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.

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).

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.

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.

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 Method Examples

There is an example app demonstrating Client Methods available in the Apps Gallery on the Omnis website (www.omnis.net/platform/#jsgallery), and also in the Samples section in the Hub. The app includes a simple entry form with client-side field validation, and some animated help tips – you should download the library and examine the client methods and code. A sample of the code is described here.

image12

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
  ; check other fields…

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

Animated Help tips

In the client-method example app, the form has some help buttons that you 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 browsers on desktops and phones, so these client commands should be thoroughly tested, as appropriate, for all 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 dependent on the command sent to the client. The client commands can 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 command to be executed on the client, and the wRow is a row variable containing any number of parameters to be passed to the client.

The following is a summary of all the client commands:

Client command Description
yesnomessage Opens a yes-no message box
noyesmessage Opens a no-yes message box
okcancelmessage Opens an ok-cancel message box
javamessage Shows a message box on the client
soundbell Sounds the bell (unlikely to work on mobile devices)
playsound Plays a sound on the client (unlikely to work on mobile devices)
setcustomformat Sets the default custom date format used when $customformat is empty
savepreference Saves a value (as a character string) as a named preference on the client
loadpreference Loads a named preference value from the client preferences into an instance variable
lockui Locks the client user interface
showloadingoverlay Shows or hides a loading overlay over a control or the entire form
subformset_[…] where … = add, remove, formadd, formremove, formtofront, e.g. subformset_add adds a set of subforms to the form
showpdf Opens the specified PDF in a new window or tab
assignpdf Assigns the specified PDF to the specified HTML control
clearerrors Clears all errors set with $errortext for all objects on the form
openpush Establishes a push connection to the Omnis Server for the remote task
closepush Closes an open push connection to the Omnis Server
readfile Reads and then closes file identified by file ident (supplied to evDrop)
closefile Closes a file or files supplied by the drag value of kDragFiles to evDrop
enablepushnotifications Enables or disables push notifications on the client. Only applies when running inside a JavaScript mobile app wrapper
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

The client commands that open a message box allow you to enter the message text in the first parameter. You can create a line break in the message text using //.

Message Dialogs

There is an example app 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 JS Components Gallery on the Omnis website.

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(message text, title text, name of public form server method called on yes, name of public form server method called on no, name of public form server method called on cancel (leave empty for no cancel button)).

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(message text, title text, name of public form server method called on yes, name of public form server method called on no, name of public form server method called on cancel (leave empty for no cancel button)).

Ok/Cancel Messages

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

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

Where rowVariable is row(message text, title text, name of public form server method called on ok, name of public form server method called on cancel (leave empty for no cancel button)).

Message Dialog Header Styling

You can change the styling for dialog headers by editing the CSS file omn_dlg.css. The header and body styling of the dialogs can be changed in omn_dlg.css under .omnis-wf-title.typeheader and .typebody.

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, query) and can have up to three buttons and accompanying text.

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

Where rowVariable is row(style(error, warning, success, prompt, message, query), text, title text, openatmouse(bool), butt1text:servermethodname, butt2text:servermethodname, butt3text:servermethodname).

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 can be changed in omn_dlg.css under the .typeicon classes.

Playing Sounds

The system bell

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

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

In this case, row() is empty.

Play a sound file

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

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

Where rowVariable is row(name of sound file from 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 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 $customformat is empty (defaults to D m y).

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

Where rowVariable is row(date format). 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.

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(preference name, preference value, storage-type).

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(preference name, instance variable name, stotage-type), where the instance variable is a quoted string containing the name of the variable.

There is an example app 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 on the Omnis website at: www.omnis.net. 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. 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 in the Samples section in the Hub in the Studio Browser showing how you can use the loading overlay command; in addition, the same app is in the JS Component gallery on the Omnis website at: www.omnis.net

image13

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

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

Where rowvariable is row(show, controlName, message, cssClass).

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.

The omnisLoadingOverlay class in omnis.css may be useful as a basis.

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.

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.

Push Notifications

The enablepushnotifications client command enables and disables push notifications for mobile apps: this is described in a separate doc available with the Wrapper download: www.omnis.net/download/jswrapper.jsp

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.

Remote Menus

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

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 JS Component gallery on the Omnis website at: www.omnis.net.

Creating Remote Menu Classes

When you design a Remote menu you need to create a title, specified in $title, and add individual menu lines: the text for a menu line is added to the $text property for the menu line. 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 which must be 16x16 in size and can be chosen when you create the remote menu class, along with the text for the menu line. 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).

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.

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 are different to standard subforms (which are embedded in a Subform control, and described in the Components chapter), in that they have a title bar and resizable borders, and the end user can move or resize them within the “main” remote form 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 (SFS) 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 (see Subform panels) in a remote form. Each separate subform in the Subform Set is a standard Remote form class that you have previously created in your library, which is referenced and added to the Subform Set.

­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 JS Component gallery on the Omnis website at: www.omnis.net

image14

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.

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 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 affect the behavior of the forms 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.

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_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.

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).

image15

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_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.

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.

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.

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 belongs 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).

Example

The following code creates a subform set containing two subforms.

; setupSubformSet method which could be called from £construct
; Create vars: iFormList (List), iID, iClassName, iParams, iTitle, iLeft, iTop, iWidth, iHeight
; 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:

image16

The Memo sample app available in the Welcome screen uses subform sets.

Subform Styles

The Omnis style sheet Omnis.css contains CSS classes that specify the appearance of the subform frame of the members of subform sets, as well as the images for the maximize and minimize buttons. You can modify these classes to give the subform frames your own style. Open Omnis.css and search for “subform” to locate the styles.

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 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 JS Component gallery on the Omnis website at: www.omnis.net

image17

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.

image18

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.

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";

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 existing constants (listed under ‘Text Escapes’ in the Omnis Catalog) and a few new ones, prefixed kEscJs..., introduced for the JavaScript Client. The following style constants can be used:

Style Description
kEscColor In a client-side method, the color parameter must be a numeric literal or constant.
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 <br> 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()).

* There is also a new function br() which can be used as short-hand to insert a new line. The br() function and kEscJsNewline can only be used with styled text for the JavaScript client.

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

image19

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).

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 sample apps in the Welcome window contain an About form which is loaded into a subform on the main sample app form. Animations are used to display the About subform, 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 $jslocaltime 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. $jslocaltime must be set in design mode: it cannot be assigned at runtime.

PDF Printing

There is a printing device (external component) to allow you to print a report from Omnis Studio 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 handle PDF reports in the JavaScript Client (if the end user’s device supports PDF). See the Omnis Programming manual for more information about creating report classes to format your PDF reports.

The PDF Device is available for Windows and macOS. Various supporting files are located in the ‘python’ folder within the main Omnis Studio folder, and the PDF component itself is in the ‘xcomp’ folder: these files need to be present in the Omnis App Server when you deploy your web or mobile app.

Note for pre 8.x users

The current PDF device replaces the “Custom Report Device” available in previous versions (for Linux only). The constant kDevOmnisPDF is now used for the new PDF device, therefore if you have used the “Custom Report Device” on Linux in previous versions, you must now use kDevOmnisPrintPDF on Linux to refer to the old print device. In addition, the device parameters for the Linux PDF device have been renamed to kDevOmnisPrintPDFAutoOut and kDevOmnisPrintPDFAutoCommand.

Using 64-bit Python

In some support cases it has been found that certain large reports could not be printed to PDF using PDF Device which uses the 32-bit version of Python provided with Omnis Studio. Therefore in order to print large reports to PDF using the PDF device you may need to install the 64-bit version of Python and update your Omnis configuration file. Python 2.7 supports 64-bit.

Installing 64-bit Python

Download 64-bit Python 2.7 for Windows from www.python.org and install it allowing the installer to add python.exe to the PATH.

Copy the reportlab folder from your Omnis tree (python\app\Lib\site-packages\reportlab) to the python 2.7 installation, to the folder Lib\site-packages\reportlab. Then install Pillow into the new Python installation using the command line (this needs internet access):

pip install Pillow

This assumes pip is part of the python 2.7 install - this should be fine if you only have one python install on the PATH. Pillow is a replacement for PIL and it has the same API.

Configure Omnis to use the python 2.7 by editing the Omnis configuration file ‘config.json’ in the Studio folder, and add a python entry to the windows object:

  "windows": {
    "python": "python"
  },

The value of the python entry is the executable to run python. Since python was added to the PATH during installation, you can just use “python”. If you omit this entry, or set its value to empty ("") Omnis will use the 32 bit portable python that is provided with Omnis Studio.

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.

Icons

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.

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 of the Omnis configuration file (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.

$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
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 affecting 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

$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:

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.

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 via Python.

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 if one is being used). An alternative would be to output the PDF document into the Web Server’s file system, and use a URL to the PDF on the Web Server to send it to the client.

showpdf

The showpdf client command opens the specified PDF in a new 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.

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, you can limit the folders from which PDF files can be retrieved using getpdf by specifying the folders in the config.json configuration file, and thereby excluding all other folders. To do this you can add a new member to the “server” member in config.json: any subfolder of a configured folder is also allowed. For example:

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

In addition, getpdf 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 to enhance security.

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))

Here is 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 to alert the end user about something (the concept is derived from “toast messages” on Android).

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

The toast message rowVariable parameters are:

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.