Chapter 3—JavaScript Components

The Component Store contains over 30 ready-made components for use in Remote Forms and the JavaScript Client. The components are displayed under the JavaScript Components tab in the Component Store when a remote form is open in design mode (assuming the $client property in the remote form is set to kClientJavaScript, which is the default for all new remote forms). In addition, there are a number of alternative controls available under the JavaScript Native Components tab.

You can create your own JavaScript components, defined using JSON, which will appear under the JSON Components tab in the Component Store: these are described in the JSON Components chapter.

Example Apps and Code

The JavaScript Apps Gallery on the Omnis website showcases many of the JavaScript Components and provides a sample app which you can download and run in the latest version of Omnis Studio. View the gallery here:

https://www.omnis.net/platform/#section-jsgallery

or you can use the shortcut: tinyurl.com/jsgallery10

Many of the example apps in the gallery are featured in the example code in this chapter, and many of them also appear under the Samples section in the Hub in the Studio Browser.

In addition, the Applets option under the Hub in the Studio Browser has several sample web apps that use many of the JavaScript Components, including a Contacts manager for recording information about colleagues or friends, a Holidays app for managing annual leave requests, and a Webshop app which has a product catalog and shopping cart. You can examine the remote forms and components in these example apps, and look at the code behind each component: you can double-click on a JavaScript component in design mode to see its code methods in the method editor.

Creating JavaScript Components

To create or add a JavaScript Component to a remote form, you need to open the remote form in design mode and open the Component Store: the latter should open automatically, but you can open it, or bring it to the top, from the main Omnis toolbar (CStore button), or by pressing F3. The JavaScript Components tab (group button) should be selected by default, showing the standard JavaScript Components; there are a number of JavaScript Native Components under that tab.

You can Right-click/Cmnd-click on the background of the Component Store and select Large/Small Icons and/or Text to alter the display of the component store, and you can Save the window setup from the same menu to store the layout and positioning of the Component Store.

Before adding any JavaScript components to your remote form, you may want to change the current layout breakpoint(s): in this case, you may prefer to start adding components on the larger breakpoints (768 or create a new one at 1024 pixels), and then switch to the smaller breakpoint to rearrange and/or resize the components you have added.

To create a JavaScript component, you can:

  1. Drag a component icon from the Component Store and drop onto a JavaScript remote form; the component is added at the default size

  2. Double-click on a component icon in the Component Store to add it to a form; the component is added at the default size

  3. Select the component icon in the Component Store and press Return to add it (same effect as double-clicking)

  4. Select the component icon in the Component Store, then in the remote form click and drag the cursor to draw the component the size you want; note some components have a standard size, or the size of some elements are fixed, e.g. the button icon for radio buttons.

Once you have placed the component on the remote form you can resize or re-position it, and set its properties using the Property Manager (if the Property Manager is hidden, press F6 to open it or bring it to the top). The following screen shot shows the Pie Chart example app, with the JavaScript Pie Chart component selected; the Property Manager (on the right) shows the properties of the current selected object, which could be a class, or in this case, a specific component.

Copying Components

In design mode, you can use the standard Copy/Paste menu options in the Edit menu or Ctrl-C and Ctrl-V keyboard options to copy and paste a component on the same form, or onto a different form. Alternatively, you can hold down the Ctrl key and click and drag a component to make a copy of the component. You can also drag a component from one remote form and drop it onto another remote form to make a copy of a component (for forms with the old kLayoutTypeScreen layout type, the forms must be set to the same value of $screensize to copy objects in this way).

JavaScript Components

The following components are available for JavaScript remote forms under the “JavaScript Components” tab (group button), plus there are a number of “native” components under the “JavaScript Native Components” tab (List, Slider & Switch), also listed here.

Component Description
Activity Control Animated image to display during a long process or Omnis Server activity
Background Control Object you can set to Rectangle, Line, Triangle, or Image
BarChart Control Displays a bar chart based on a list of values
Button Control Standard pushbutton which reacts to clicks
Checkbox Control Check box for on/off values
ComboBox Field combining entry box and droplist
Complex Grid Grid which can display all types of data and formatting
Data Grid Control Simple grid for text and numerical data display
Date Picker Control Data picker with touch selection
Device Control Allows access to hardware and services on mobile device
Droplist List that drops down when clicked
Edit Control Standard edit field for data entry or display
File Control Allows end users to upload or download files
HTML Object Object to display HTML content
Hyperlink Control List containing hyperlink style options
Label Object Basic label object
List Control Standard list field for displaying list variable data
Map Control Displays a Google map for specified location(s)
Native List List control with platform dependent appearance
Native Slider Slider control with platform dependent appearance
Native Switch Switch control with platform dependent appearance
Navigation Bar Control Navigation with touch selection
Navigation Menu Object Dropdown menu with hierarchical options
Page Control Allows selection of page pane using touch
Paged Pane Can contain fields on multiple panes
Picture Control Standard field for displaying images
PieChart Control Displays a pie chart based on a list of values
Popup Menu Control A menu that pops up when clicked
Progress Bar Control Shows progress of server process or calculation
RadioGroup Control Displays a group of radio buttons for exclusive selection
Rich Text Edit Control Rich text editor allowing end users to edit and format text
Segmented Control Navigation control with different buttons or “segments”
Slider Control Slider component for setting values
Subform Allows you to insert another remote form class as a subform
Switch Control Allows on/off selection; you specify an icon for on/off state
Tab Control Multiple tabs to control selection of page pane
Timer Control Timer object triggers an event at a specified interval
Toolbar Control Toolbar with custom buttons (icons and text), auto overflow and optional side menu
Transbutton Control Interactive button with alternate hover image
Tree Control List for displaying hierarchical data or list of options
Video Control Plays a YouTube or other hosted video

Native JavaScript Components

The “JavaScript Native Components” group contains components that have a more familiar or “native” appearance when they are displayed on different mobile platforms – their appearance is rendered in the JavaScript Client using CSS customized for each platform. The different appearance for each platform is handled by Omnis automatically, therefore you only need to setup the component once in design mode. The Native components currently include the Native List, Native Slider, and Native Switch.

When running on a supported device, these controls will render and work in a manner close to a device’s native versions. For example, a native Switch control will look like an iOS switch on an iOS device, an Android switch on an Android device, and so on, while using a single control and set of methods in design mode in your remote form.

JavaScript Remote forms have an Appearance property called $defaultappearance which determines both how a native control is displayed in the design window, and how it would render on non-supported clients (e.g. Desktop browsers). The property is either kAppearanceiOS or kAppearanceAndroid (kAppearanceBlackberry is no longer supported).

The $defaultappearance property can also be switched using the new ‘Native Components Display As’ context menu option of a JavaScript Remote Form (right-click on the form to open the context menu). You can also cycle through the values using the keyboard shortcut Ctrl-Shift-N on Windows or Cmd-Shift-N on macOS when the remote form is the top window.

It is recommended that you set $disablesystemfocus property to kTrue for any native controls you have used, to prevent the focus ring being drawn around a controls when it is selected – otherwise the focus ring may interfere with the native appearance.

JavaScript Component Properties

All JavaScript components have their own set of properties which you can view and set in the Property Manager (F6).

$dataname for JavaScript Controls

The variable specified in the $dataname property of a JavaScript component must be an instance variable, or in some cases a column in a row instance variable in the form VarName.ColumnName.

Naming JavaScript Controls

When you create a component in your remote form, a name is generated automatically and assigned to the $name property of the component. This is usually in the format <remoteformname>_<component-type>_<number>, such as ‘rftest_edit_1001’ for an edit control on a remote form called rftest. However, you can enter your own name for a component which may better describe the object within the context of your form; for example, an edit field to allow the end user to enter their first name could be named Firstname. You can change $name of a component in the Property Manager.

The name you assign to an object does not have to conform to any convention other than any conventions you may like to use in your forms or the application to identify different objects. However, the name of a component (specifically the value in $name) is used in the Omnis notation and throughout your library to refer to the object. Therefore, you should not use spaces and try to use alphanumeric characters only for object names to avoid any possible conflicts in your code. For example, an object name should not include the dollar sign ($) since this would cause a conflict when you reference the object using the Omnis notation which prefixes property and method names with the dollar sign.

Component Resizing and using $edgefloat

The “floating edge” ($edgefloat) capabilities for JavaScript components allow the components to be resized automatically, when the end user resizes their web browser window or when the layout changes on a breakpoint. The $edgefloat property can be set to one of the kEF… constants which determines which edges of the component, if any, will “float” or resize when the browser window is resized. The possible values for $edgefloat are:

  1. kEFall and kEFnone
    All or no edges float

  2. kEFbottom
    Bottom edge only floats

  3. kEFleftRight
    Left and right edges float; in effect, the component floats to the right or left and does not resize

  4. kEFleftRightBottom
    Left, right and bottom edges float

  5. kEFright and kEFrightBottom
    Right edge only floats, or Right and bottom edges float

  6. kEFtopBottom
    Top and bottom edges float; in effect, the component floats up or down and does not resize

  7. kEFrightTopBottom
    Right, top and bottom edges float

  8. kEFcenterLeftRight, kEFcenterTopBottom, kEFcenterAll
    means the Left & Right edges float, or the Top & Bottom edges float, or All edges will float, and the control will also be centered horizontally and/or vertically within its parent

  9. kEFposn… positioning constants
    all edgefloat constants prefixed with kEFposn… will reposition the control in the specified region of the screen; as you select one of these constants in design mode the control will snap to the chosen region, and when the form is resized at runtime the control will “stick” to this region; the kEFposnClient constant stretches the control to fit the available area within its parent or subform

You can store a different setting of the $edgefloat property for each component, for each different layout breakpoint. When setting $edgefloat in the Property Manager in design mode, you can set the value of $edgefloat for a component on all breakpoints by holding the Control key when selecting the $edgefloat value.

The setting of $edgefloat for a component is used to resize the component (or not if set to kEFnone) when the form or container field is resized at runtime, and when one or more of the following occurs:

  1. When the component is in a subform and the subform is resized (that is, its size at runtime is different to the size of the subform class)

  2. When applying a different mobile device size while running in a mobile device custom wrapper

  3. When the component is in a resizable subform in a subform set and the subform is resized

Centering Objects

There are some kEF… contstants to control how objects are centered relative to the remote form or parent: kEFruntimeLeftRightCenter, kEFruntimeTopBottomCenter and kEFruntimeAllCenter. They are only applied at runtime, and in this case, their behavior is identical to kEFleftRight, kEFtopBottom or kEFall respectively, except that the offset is divided by two, to keep an object or a number of objects centered within the parent.

In addition, the Align context menu for the remote form editor contains options to allow you to center objects vertically, horizontally (or both) in their parent.

Responsive Forms and $edgefloat

To understand what kind of edgefloat properties you can use, you can look at the PicsWebForm in the Pics2.lbs available in the tutorial download (or in the ‘welcome/tutorial/final’ folder); or you could create your own remote form using the form wizard. The PicsWebForm remote form was created using the SQL Remote Form wizard and uses edgefloat properties to control the floating edge behavior of the controls. The form has two layout breakpoints, 768 and 320, and the edgefloat properties is set differently for some of the controls on each breakpoint. The following image shows the layout for the 768 breakpoint, and the $edgefloat setting (a kEF.. constant) for each control is shown in red.

The PicsWebForm uses a Page pane containing all the data controls, e.g. Pic_Name, etc; the $edgefloat property of the Page pane is set to kEFrightBottom to ensure it stretches across to the right and down as the form is resized in a browser window or is displayed on different sized tablet screens.

The $edgefloat property for most of the controls inside the page pane is set to kEFright, so the right edge “floats” or stretches to the right, but the bottom edge is not resized; the ID field has no floating edges so it keeps its size. The $edgefloat property for the push buttons on the right of the form is set to kEFleftRight (i.e. both left and right edges), which means the buttons will “float” from right to left horizontally, but they will not resize or move vertically. The combination of all these edgefloat settings on all of the controls, means that the push buttons keep to the right-hand edge of the browser window or device screen, while the data controls will resize to accommodate any screen or device size. Now examine the layout for the 320 breakpoint:

The push buttons on the 320 layout breakpoint are positioned at the top of the form and their $edgefloat property is set to kEFnone, so they will not move or resize as the form is resized. The $edgefloat property for the data controls is set to kEFright so their right edges will stretch to accommodate different phone sizes, from 320 pixels upwards.

As the form is resized, on a web browser window or is displayed on a larger device screen, the controls will resize to fill the screen, until the next breakpoint is reached, which in this case is a screen or device width of 768 pixels, and the layout for that breakpoint is loaded.

Draggable Component Borders

End users can resize some JavaScript components dynamically at runtime in their web browser by dragging the border of the component. When the end user’s mouse is over the edge of a component that can be resized, the cursor changes to indicate that the border can be dragged and resized.

To allow this functionality, JavaScript components have the $dragborder property, which only applies when a component has its $edgefloat property set to one of the kEFposn… constants (other than kEFposnClient or kEFposnJoinHeaders). If $dragborder is set to true, and you have set $edgefloat as above, the end user will be able to resize the component in the browser by dragging the border of the component with the mouse.

You can store a different setting of the $dragborder property for each component, for each different layout breakpoint, therefore components on the same form could be resizable for web desktop browsers and not for mobile devices. When setting $dragborder in the Property Manager in design mode, you can set the value of $dragborder for all layout breakpoint values by holding the Control key when selecting the $dragborder value.

The appearance of the drag border area can be modified by editing the styles div.omnis-db-vert and div.omnis-db-horz in omnis.css.

Date and Time Formatting

You can set the formatting for Date and Time type data for some of the JavaScript components including Edit controls, Combo boxes, Data grids, Droplists, Hyperlink lists and standard Lists. These components have the properties:

  1. $jscustomformat
    a date-time format string using the characters described below. If $jsdisplayformat is kFormatCustom, and the data is of type 'Date Time', this property is used to format the data. If empty, it defaults to the format set using $clientcommand 'setcustomformat'

  2. $jsdisplayformat
    the format used to display 'Date Time' data, a kJSFormat... constant as follows:

kJSFormatNone No format
kJSFormatTime Default time format for client locale
kJSFormatShortDate Default short date format for client locale
kJSFormatShortDateTime Default short date and time format for client locale
kJSFormatMediumDate Default medium date format for client locale
kJSFormatMediumDateTime Default medium date and time format for client locale
kJSFormatLongDate Default long date format for client locale
kJSFormatLongDateTime Default long date and time format for client locale
kJSFormatFullDate Default full date format for client locale
kJSFormatFullDateTime Default full date and time format for client locale
kJSFormatCustom Use the custom format in $jscustomformat

Date formatting characters

The following standard date formatting characters are supported for $jscustomformat:

D Day (12)
V Day of week (Fri)
w Day of week (Friday)
E Day of year (1..366)
n Month (June)
M Month (06)
m Month (JUN)
y Year (1989)
Y Year (89)
A AM/PM
H Hour (0..23)
h Hour (1..12)

Some additional characters are supported for Date/Time formatting for the JavaScript Client components only, as follows:

j day with no leading zero (6)
P month with no leading zero (6)
K hour with no leading zero (0..23)
k hour with leading zero (1..12)
a am/pm
O timezone offset (+01:00)

There is an entry on the Constants tab in the Catalog (F9) called "Date codes (JavaScript Client only)" that lists the formatting characters.

Date formatting and Locale

When the client connects, the server sends it the date formats, day names and month names for the client locale (the server reads these from ICU). If you assign $ctask.$stringtablelocale in $construct of your remote task, the server sends the client the formats and so on for the assigned $stringtablelocale locale.

Number Formatting

All JavaScript controls that can display number data have the property $numberformat, which specifies how Number and Integer data is formatted or displayed in the control. The JavaScript controls affected include the Edit Control, Combo box, Data grid, Droplist, Hyperlink list and standard List control. The formatting is used when the control displaying the data does not have the focus, that is, the formatting is only applied when the end user tabs or clicks away from the number field.

The $numberformat property uses a single % format tag for the number followed by one or more elements, for example, the number format %.2F displays a number with 2 decimal places with a thousand separator. The following elements are available (in this order):

An optional "+" sign that forces to precede the result with a plus or minus sign on numeric values. By default, only the "-" sign is used on negative numbers.

An optional padding specifier used for padding (if padding is required). Possible values are 0 or any other character preceded by a '. The default is to pad with spaces.

An optional "-" sign, that causes the string to left-align the result of this placeholder. The default is to right-align the result.

An optional number that says how many characters the result should have. If the value to be returned is shorter than this number, the result will be padded.

An optional precision modifier consisting of a "." (dot) followed by a number, specifies how many digits should be displayed for floating point numbers. When used on a string, it causes the result to be truncated.

A type specifier that can be any of:

% print a literal "%" character
b print an integer as a binary number
c print an integer as the character with that ASCII value
d print an integer as a signed decimal number
D as above but include thousand separators
e print a float as scientific notation
u print an integer as an unsigned decimal number
f print a float as is
F as above but include thousand separators
o print an integer as an octal number
s print a string as is
x print an integer as a hexadecimal number (lower-case)
X print an integer as a hexadecimal number (upper-case)

Decimal and Thousand Separators

Numbers will be displayed using the default decimal and thousand separators specified by the language set in the client’s browser, so you do not need to do anything to display the correct decimal and thousand separators for a client. However, you can override the default separators by changing the thouChar and dpChar items in the jOmnis client object: you can do this using JavaScript in the $init method for a JavaScript form, for example:

# $init method, which must be client executed
JavaScript: Omnis.thouChar = ".";
JavaScript: Omnis.dpChar = ",";

Autoscrolling

You can enable automatic scrolling for Edit controls, Lists, Tree lists, Hyperlink controls, Pictures and Html controls by enabling the $autoscroll property. If this property is kTrue for the control, and the client is not a mobile device, the client automatically displays scrollbar(s) when not all of the content in a field is visible.

Setting $autoscroll to kTrue changes $horzscroll and $vertscroll to kFalse, and in doing so means you cannot set $horzscroll and $vertscroll. By default, $autoscroll is enabled for Edit controls, Lists and Tree lists, while for Hyperlink controls, Pictures and HTML controls $autoscroll is set to kFalse.

Note that in addition to controlling scroll bars, Data Grids and Lists have the $vscroll and $hscroll properties which allow you to scroll a grid or list vertically or horizontally at runtime in the client browser: the numeric value of these properties is either column or row offset for grids, or the pixel offset for lists.

Component Borders

The borders of JavaScript components are drawn within the bounds of the control, for both Windows and macOS, and have the same dimensions for both platforms. The color is controlled using $bordercolor.

Some components can have rounded borders by specifying the corner radius in pixels in the $borderradius property; for buttons this is $buttonborderradius (single value only). To set all the corners of the object to the same radius you can enter a single value, or to specify the radius for different corners you can use the syntax "n-n-n-n" which follows the same rules as CSS 3 rounded border syntax. The order for the radius parameters is top-left, top-right, bottom-right, bottom-left. If bottom-left is omitted the top-right value is used, if bottom-right is omitted the top-left value is used, if top-right is omitted the top-left value is used.

Control Classnames

All JavaScript controls have a base class name to allow you to control the appearance of controls using CSS, to allow you to apply a consistent appearance for each type of JavaScript control. The classnames listed below can be added to the ‘user.css’ and CSS properties applied to the classname to control the appearance of each type of control. Note these classnames are contained in the JavaScript controls by default and if they are added to the user.css are applied to the control automatically, that is, these classnames do not need to be included in the $cssclassname property of a control to be applied (this property is used to apply your own custom style names, see below).

JS Control Class Name Additional notes
‘Frame’ element for all controls omnis-[control]-frame
Activity Control omnis-activity
Background Control omnis-background
BarChart Control omnis-barchart
Button Control omnis-button
Checkbox Control omnis-checkbox
ComboBox Control omnis-combo

The dropped list has “ctrl-drop-list” assigned.

If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname suffixed with ”-dropped-list”

Complex Grid omnis-complexgrid

omnis-complexgrid-header and omnis-complexgrid-hheader for header and horizontal header areas.

Each row has omnis-complexgrid-row and either ‘odd’ or ‘even’ depending on their line number.

If ($cssclassname) the header/hheader will have class $cssclassname+”-header” and “-hheader”

Date Picker Control omnis-date
Data Grid Control omnis-datagrid
Droplist Control omnis-droplist

The dropped list has “ctrl-drop-list” assigned.

If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname+”-dropped-list”

Edit Control omnis-input
File Control omnis-file
HTML Object omnis-html
Hyperlink Control omnis-hyper
Label Object omnis-label
List Control omnis-list
Map Control omnis-map
Menu - used for context menus, popup menus and tab menus omnis-menu

omnis-menu-main for containing <div> omnis-menu-table for table <div> omnis-menu-row for row <div>

omnis-menu-cellcheck for check or icon element in the menu

omnis-menu-celltext for the text element

omnis-menu-cellcascade for the cascading menu element

Popup and tab menus will implement If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname+”-opened-menu”

Native List Control omnis-nativelist
Native Slider Control omnis-nativeslider
Native Switch Control omnis-nativeswitch
Navigation Bar Control omnis-navbar
Navigation Menu Object omnis-navmenu
Page Control omnis-pagectl
Paged Pane omnis-pagedpane
Picture Control omnis-picture
Popup Menu Control omnis-popup Also contains the classes from omnis-menu as it uses this object for the menu element of the control.
PieChart Control omnis-piechart
Progress Bar Control omnis-progress
RadioGroup Control omnis-radio
Rich Text Editor Control omnis-rich
Segmented Control omnis-segmented
Slider Control omnis-slider
Subform omnis-subform
Switch Control omnis-switch
Tab Control omnis-tabs Also contains the classes from omnis-menu as it uses this object for the menu element of the control.
TransButton Control omnis-trans

omnis-trans-text

To address text element of a trans button.

Video Control omnis-video

For example, to add CSS styling to all the Edit controls in your remote forms you could add the following CSS to the user.css file in the ‘html/css’ folder in the main Omnis folder: in this case, the base classname .omnis-input is used with the properties 2px solid grey border and a 6px radius.

.omnis-input {
border: 2px solid grey;
border-radius: 6px;
}

Custom CSS Styles

You can create your own CSS classes or styles (in addition to the base class names listed above) and apply them to the objects in your web and mobile apps, allowing you to have more control of the styling, coloring, and overall design of your apps.

CSS classes for Controls

All the JavaScript components have a property called $cssclassname which allows you to apply your own CSS class to the component. You can add the CSS classes to a file called ‘user.css’ which is located in the ‘html/css’ folder in the main Omnis Studio folder. A style can be applied to a control by setting its $cssclassname property to the name of a style. The properties you define for each style in user.css must be flagged as !important to override the JavaScript Client inline styles.

When you deploy your application on the Omnis App Server, you must put your custom ‘user.css’ file in the ‘html/css’ folder on the server.

Form Errors

It is possible to display form errors either to the right or under controls in a remote form. This makes it easier for end users to fill out forms in your web and mobile applications by providing them with helpful tips if they make a mistake in the form. The errors appear on the form as a text field either under a control, or to the right of a control, so you need to design your remote forms to allow space for the error text. The style of the error text and the outer HTML of the control containing the error are controlled in CSS which you can change if required.

$errortext

All JavaScript Client controls have the $errortext property which contains the text to be displayed when there is an error in the field or control. The initial value of $errortext when a form is constructed is empty.

The $errortext property is only supported for subform controls when they are not scrollable, i.e. when $vertscroll & $horzscroll are both kFalse and the subform class is not responsive.

$errortextpos

The $errortextpos property specifies the position of the error text set using $errortext. The value can be one of:

  1. kJSErrorTextPosUnder
    The error text is positioned under the control, the default.

  2. kJSErrorTextPosRight
    The error text is positioned to the right of the control.

  3. kJSErrorTextPosHidden
    hides the error text, so just the control outline indicates that there is an error (default is a red border). This might be useful where there is limited space to display the error text in the remote form, but you still want to show the end user that there was an error; the style of the error outline is set in the omnis.css style sheet as div.om-error-border

Note that Omnis stores a separate value of $errortextpos for each screen size. As a shortcut when designing a form, you can hold the control key down when assigning $errortextpos, in order to assign the value to all screen sizes.

$errorline

$errorline is a runtime property of the JavaScript Complex Grid control, used when assigning $errortext to an object in the row section of a complex grid. The line number to which $errortext will apply.

Clearing form errors

There is a new client command, “clearerrors” to allow you to clear all error text messages for the form.

Do $cinst.$clientcommand("clearerrors")

is equivalent to assigning $errortext to empty for all controls on the form which have error text.

Changing the appearance of error text

The following CSS classes control the appearance of the error text and border. These classes are stored in the omnis.css which you can edit if required.

  1. div.om-error-text
    This class styles the error text.

  2. div.om-error-border
    This class styles the outer div of a control which has error text.

Field List

The Field list provides a list of all the components on a remote form and is often useful if you need to select a specific component which is partly obscured or hidden in the form. To open the Field list, Right-click/Cmnd-click on the form or a component and select the Field List option. The currently selected component is checked in the Field list, expanding the tree nodes and scrolling the list if necessary. Conversely, you can open the Field List and check a component name in the list to select it in the form.

When the focus is in the Field List, you can use the arrow keys to navigate up and down the list and use Space bar to select a control, as required. The Shift-Space keypress allows you to select (or deselect) multiple, discontinuous controls in the list.

The Field list can be useful if you need to select the background of a form, for example to set its properties in the Property Manager, but the form is completely filled with components and no form background is available to click on, as can be the case for mobile forms. To select the form in this case, you can open the Field List and check the form name at the top of the list (which will deselect any components), or if you click on any individual component, then shift-click it to deselect it, the focus will be returned to the form background and its properties will be shown in the Property Manager.

JavaScript Component Events

Most of the JavaScript components report events which you can handle in a special method called an “event method” which is inserted behind the component. The event method for a component must be named $event. For example, when the end user clicks a button, an evClick is generated which you can trap in the $event method for the button; this method could display a message, initiate another method or determine some other action depending on the code in the event method itself. Most of the components contain a template $event method with a code stub for you to use as a starting point to handle the event.

Enabling Events

In order to report an event, the event must be enabled for the component. Many of the components have their events enabled by default, but for some you may need to enable specific events in the $events property for the component.

To enable an event

  1. Select the component and open the Property Manager (press F6)

  2. Click on the $events property in the Property Manager to drop down the list of events for that component (the property will show “No Events” when no events are selected)

  3. Check (enable) the events you wish to trigger for this component

You can select multiple objects of the same type and specify the events for all of the objects at the same time. For example, you can select a number of check boxes and enable the evClick event under the $events property to enable the event for all the selected check boxes.

Editing Event Methods

If you double-click a component in design mode, the Method Editor will open displaying the method for that individual component. For components with events, the $event method will be shown. For example, if you double-click on a button, the Method Editor will open displaying the $event method containing the code On evClick; you can add more code after this line to be run when the end user clicks the button. See the example code for each component for example $event methods.

Standard Field Events

Most JavaScript fields or controls report the evBefore and evAfter events, which are triggered when the focus is about to enter or leave the control, respectively. Note that for edit controls, if the data does not change then an evAfter is not triggered as the focus leaves the control.

You can use the On event command to detect events in your event handling methods, and for most controls the $event method will contain a template event handling method into which you can add your own code. For example, in the $event method for an Edit control you could use the following commands to detect the evBefore or evAfter event.

On evBefore
 # do something..
On evAfter
 # do something else..

Buttons and Lists

Buttons and all the list type JavaScript controls report the evClick event, as well as evBefore and evAfter; and some list types also report the evDoubleClick event. For example, the Data Grid control reports evDoubleClick which you could detect and initiate a search based on the content of the grid line clicked on.

evAfter event queue

When an event is being executed in the JavaScript client, such as a click on a button, a transparent overlay is applied to the whole remote form, to prevent user interaction anywhere else in the form and to maintain the Omnis event ordering. If the user clicks on this overlay, the click will be prevented, although most events happen almost instantaneously so in this case the overlay is not displayed.

For evAfter events that show the overlay, Omnis shows a feedback effect at the point of the click when the overlay prevents the click, to make it clear to the user that their click was not registered. The feedback effect is a No Entry icon, with “bubble” animation, that appears and disappears directly after the user click. In this case, the click will be queued and will fire once the overlay is removed.

Unfortunately, Firefox does not treat the active state of elements in the same way as other browsers. As such, it was not possible to implement these changes for that browser.

Drag Border Event

All JavaScript controls report the evDragBorder which is triggered when the border is dragged – the event is reported to the control containin the border being dragged and any that share the border area being dragged. When it is triggered it could mean that the end user has resized the field (and therefore other fields in the same parent have resized) using the drag border.

JavaScript Component Icons

Some of the JavaScript Controls allow you to add an icon, such as a Button, to create a better appearance and UI for your apps. Such controls that support icons have the $iconid property which allows you to specify an image to be used for the control. You can use images that are 16x16, 32x32, or 48x48 pixels either at a standard pixel density suitable for displaying on standard monitors, or you can create icon images that are 1.5 and 2 times the size, suitable for displaying on devices with high definition screens such as the latest Apple iPhones or Android Phones, as well as tablets and HD monitors on desktop computers.

Creating and using HD Icon Images

You can create icon images in any third-party image editing software and place the image files directly in the Omnis development tree, in the folder named ‘iconsets’ (in previous versions icons sets were stored in ‘html/icons’). The icon image files must be saved using the PNG file type and placed in a sub-folder of the ‘iconsets’ folder in the main Omnis tree (note for existing users: this is not the same icons folder in the root of the Omnis tree which contains the built-in icon datafiles). Each sub-folder represents what is called an Icon Set which is a named collection of icons (which would normally corresponed to a single library). The name of the sub-folder in the icons folder becomes the name of the icon set which is specified in the $iconset property for the library (see below) and will also appear in the icon selection dialog. Note that an icon set cannot be named ‘datafile’, ‘lib’, ‘studio’, or ‘studioide’ since those names are already in use and would cause a conflict.

Icon Data files and Icon sets

NOTE TO EXISTING USERS: The method of storing icons in #ICONS or an Icon data file (such as Omnispic) and assigning the numeric Icon ID ($iconid) to controls will continue to work, but this is only useful for icon images that are 16x16 pixel (or 32x32 for high def). In this case, if you run your application on an HD display and your library uses an icon data file or #ICONS, Omnis will try to use a 32x32 icon (if it exists and the icon page is marked as containing 32x32 icons), in place of the corresponding 16x16 icon. If a 32x32 image does not exist in your icon data file or #ICONS, the existing 16x16 image will be used which may have a very poor visual appearance on newer screens and devices. In order to support high definition 16x16 icons you will need to create a new version of each image at 32x32 pixels and import each one into the icon data file or #ICONS into the 32x32 section on the same icon page using the same icon IDs.

If you have used 32x32 or 48x48 pixel icons in your libraries (in #ICONS or an Icon data file), and you wish to display them on HD displays, then you will need to adopt the use of Icon Sets (separate image files in a folder) which support icon images up to 96x96 pixels (i.e. 2x the largest 48x48 icon size). Icon sets are supported in JavaScript Client remote form classes and on window classes in the thick client – you cannot use Icon sets with the old ‘Web Client’ or the ‘iOS Client’ plug-in (note these plug-ins are not supported in Studio 6.1 or higher).

When Omnis references an Icon ID it will first search for the icon in an icon set, then it will search #ICONS in the current library, then it will search the ‘Studio’ icon set, and then any other icon datafiles, including Omnispic and Userpic.

Image File names

Each image file within an icon set must conform to the following naming convention:

<text>_<id>_<size><state>_<resolution>.png
  1. <text> is the name of image. This string is used in the icon picker dialog when you set an object’s $iconid in the Property Manager.

  2. <id> is the positive integer id to be used as the icon id. It can be in the range 1 to 10000000.

  3. <size> is the CSS pixel size of the image, i.e. the resolution independent size of the image, meaning that for all resolutions of the same image this has the same value.

The value of <size> has the form <width>x<height>, where the values 16x16, 32x32 and 48x48 are special values since they correspond to the standard icon sizes supported by Omnis.

  1. <resolution> is the factor by which the pixel density is greater than a standard monitor and is one of the following:
    “_2x” for HD devices such as the Retina display
    “_15x” for some devices e.g. certain Android phones that have a 1.5x pixel density.
    an empty string is the default and is for standard resolution devices, equivalent to _1x

Any files (or folder names) that do not conform to the naming conventions are ignored. Example file names are:

pencil_1657_16x16.png Normal state 16x16 icon with ID 1657 for standard resolution devices
pencil_1657_16x16_2x.png Normal state 16x16 icon with ID 1657 for HD resolution devices
check_1658_32x32c_2x.png Checked state 32x32 icon with ID 1658 for HD resolution devices (see below)

Note that the image file names are case insensitive and they must be unique across all platforms and file systems (that is the case of file names is ignored).

Check Boxes Icons

As a special case you can implement icons for different states in check boxes and radio buttons.

  1. <state> is the checked, highlighted, or normal state of the icon for multi-state icons and can be one of the following:
    an empty string for the normal state of the icon
    “c” is the checked state of the icon
    “h” is the highlighted state of the icon
    “x” is the checked highlighted state of the icon

Studio IDE icons

If you are unsure about the icons you need to create and the file naming, you can examine the icons in the ‘iconsets/studioide’ folder – here you will see the different size image files and their naming required for each icon used in the Studio IDE (note you cannot use the icons in this folder without acquiring the proper license). You need to adopt the same naming scheme for your own icon images.

Image File Name Image Size & Description
catalog_1632_16x16.png 16x16 pixels; Icon ID 1632 for standard resolution devices
catalog_1632_16x16_2x.png 32x32 pixels; Icon ID 1632 for HD resolution devices
catalog_1632_32x32.png 32x32 pixels; Icon ID 1632 for standard resolution devices
catalog_1632_32x32_2x.png 64x64 pixels; Icon ID 1632 for HD resolution devices
catalog_1632_48x48.png 48x48 pixels; Icon ID 1632 for standard resolution devices
catalog_1632_48x48_2x.png 96x96 pixels; Icon ID 1632 for HD resolution devices

Image Scaling

You do not have to create an icon image for all resolutions, although it would be advisable to do this for the best appearance. Omnis will use an icon image closest to the resolution being referenced, scaling as appropriate, and as with all image scaling it is better to force Omnis to scale an image down rather than scale it up. In this case, you may like to provide the highest possible resolution image for your icons and allow Omnis to scale the images down to display an icon for lower resolutions, but the scaling may produce unexpected results.

When the JavaScript Client connects, it sends its resolution to the Omnis App Server. This allows the server to use the appropriate icon when setting iconid properties in server methods.

Non-standard Size Images

You can create images with a size other than the standard sizes (16x16, 32x32, 48x48) by creating the image at a non-standard size and including the image size in the file name when the file is saved. For example, you can create an image 100x200 pixels and name it something like “mygraphic_1688_100x200.png”, and you can create a high resolution version at 200x400 pixels and name it “mygraphic_1688_100x200_2x.png”.. (Existing users should note that this is the equivalent of an ‘Icon Page’ in the existing icon support.)

Adding icon sets to the deployment web server

When you deploy your app to a web server, you need to copy any icon sets used by your forms from /iconsets in your Omnis development tree to the /icons folder at the same location as the .htm file containing your app, that is, <location of .htm file on webserver>/icons: each icon set will appear as a subfolder of the /icons folder and contain all the PNG icon files for your app.

Setting the Icon set in your library

Libraries have a preference called $iconset ($libs.LIB.$prefs.$iconset). This is the name of the icon set to be used when resolving icon ids for the JavaScript client and the thick client in the current library. When using this library, and when looking up an icon for the thick client or JavaScript client, Omnis will search for icons within this icon set before following the current icon search path for the library. In this case icons present in the icon set will take precedence over those in #ICONS, omnispic.df1, etc.

Icon Search Path

Omnis looks in various icon set folders and icon datafiles when it looks up an icon. If an icon with the same ID is included in another folder, after it has already been found, it is ignored in subsequent folders and an error written to iconsetlog.txt. You should therefore avoid having the same or similar icons or icon sets in multiple folders to avoid any confusion. Omnis looks in the following folders or datafiles in this order:

When using a web server for deploying your application, the icon sets must still be placed in the html/icons folder in the web server tree, even if they are in one of the other folders in the Omnis tree.

Setting the Icon ID for objects

When you set the $iconid of an object using the Property Manager, the icon set for the current library will be shown in the Icon picker dialog ($iconset must be set for the library for the icon set to appear) allowing you to select one of the icons in the set. You can select the icon required and the Icon ID will be assigned to $iconid for the object.

Any errors created while setting the icon ID for JavaScript controls are sent to a file called iconsetlog.txt located in the Studio folder.

Assigning a URL for images

When you set the $iconid of a JavaScript control you can also assign a URL. In server methods, if the value being assigned is a character value that contains a “/” character then Omnis treats it as a URL generated by the iconurl function (meaning that it can contain alternative icon files for the different client resolutions, and also that the server will pick the correct icon for the client resolution).

In client methods, if the value being assigned is not an Icon ID (a literal integer or integer + icon size constant) then Omnis treats the value as a URL generated by the iconurl function on the server, and the client picks the correct icon for its resolution.

You could generate the required URLs with iconurl() (see below) in the $construct() method of your remote form, and store them in an instance variable list which could then be used in client executed code to assign the correct image to each object.

Image handling for tree lists

For the JavaScript Tree control, the iconid column is an iconurl column, and the $iconurlprefix property is redundant although existing libraries that use $iconurlprefix will continue to work. Instead, the iconurl column should be defined to be of type character, and it should be populated using a server-only function, iconurl(iconid), which returns a URL string containing the name of the image file or a semi-colon separated list of file names if an icon exists in more than one resolution. This enables the client to pick the correct icon for its resolution.

Deploying HD Icons

You need to copy your icon sets and images files to the Omnis App Server when you want to deploy your web or mobile app. If the icons are not copied to the Server tree they will appear to be missing from your app.

Standalone Client Apps

Note that for standalone apps the icons needed for your mobile app will be bundled in the SCAF. If any icons change on the Omnis App Server they will be updated on the client when the standalone application files are updated.

Exporting Icons from an Icon Datafile

You may want to use some existing icons located in an Icon Datafile and either add to or replace some of them with higher resolution versions. To enable you to export existing icons as separate files, there is a tool in the Tools>>Add Ons menu, called the ‘JS Icon Export’ tool, which is available in the ‘Web Client Tools’ dialog (scroll to the bottom of the list of Web Client tools). The ‘JS Icon Export’ tool will export all the icons in a selected Icon Datafile and place them in a folder in the ‘iconsets’ folder, applying the correct image file names. The $iconid property of a control will now reference the external image file in the icon set and not the icon datafile image, since Omnis looks in the iconset folder for the library before any icon datafiles. The Icon Export tool will only export icon images that support Alpha, i.e. the icon page containing the existing icon(s) must be set to Alpha.

Icons Folder Name

Apache often redirects a URL with "/icons/" to the /usr/share/apache2/icons folder, and you would then need to place all the icons for your app in that folder. Therefore, if you deploy your web or mobile app to an Apache server, you may want to rename the ‘icons’ folder in Omnis by editing (adding) an entry in the Omnis configuration file (config.json). The "iconsFolder":"omnis_icons" configuration item in the server group of config.json defaults to "icons" if omitted or is empty, so you can change the name by adding your own value. You are recommended to use the same value for development and runtime, since the folder name is stored in the HTML for each remote form class.

Drag and Drop Data

Drag and drop for the JavaScript Client provides the ability for end users to drag data from one JavaScript control in a remote form, and drop that data onto another JavaScript control. In addition, end users can drag files from their desktop and drop them onto a JavaScript control within a remote form displayed in their web browser.

IMPORTANT NOTE: Support for drag and drop in JavaScript remote forms is limited to desktop browsers only, including Chrome, Edge, Firefox, IE 11, and Safari – drag and drop is not supported in mobile browsers. Also note drag and drop only applies from one control to another control, or a file onto a control – you cannot drag data to or from a remote form.

To drag and drop some data, the end user can click and hold down the pointer over a JavaScript control on a remote form, then drag the highlighted control onto another control and release the pointer when the target control is highlighted. To enable drag and drop, you have to set various properties in the source and target JavaScript controls, and handle various events in each control as the drag and drop events occur.

Existing users should note that the event constants and their parameters work in a very similar manner to those for the drag and drop mechanism in the thick client, with the addition of a new constant pDropId which identifies the area of a control over which the drop is to occur (see under Events).

Example Library

There is an example library demonstrating how you can drag and drop images between JavaScript controls, and the library allows image files to be dropped onto a control from the desktop. The example library is available in the Samples section in the Hub in the Studio Browser, and in the JS Component Gallery on the Omnis website: www.omnis.net

Dragging Data

Dragging data is limited to certain data-bound JavaScript controls and is not possible for all types of JavaScript controls. JavaScript client controls that support dragging data will have the $dragmode property. This can be set to either kNoDragging or kDragData.

Note that the $dragiconid property used in the thick client is not supported for drag and drop in the JavaScript client, for a number of technical limitations in various browsers. The dragged image is typically an image of the dragged element created by the browser, using the content of the element when the drag starts – the client performs various temporary adjustments to the element to make the dragged image correspond to the dragged data as appropriate.

Dropping Data

A drop can occur on any JavaScript control, but remotes forms do not accept drops. You can specify that a control can accept dropped data by setting its $dropmode property. When a control can accept some data, the JavaScript client highlights the destination control. For JavaScript client controls, $dropmode can be one of the following constants:

  1. kAcceptControl
    Data from a JavaScript client control can be dropped onto this control.

  2. kAcceptFiles
    Files dragged from the system (desktop) can be dropped onto this control.

In addition, the list, tree and data grid controls have the $hiliteline property, indicating that data can be dropped on a specific list line or tree node rather than the entire control. This also means that rather than highlighting the entire control, the client highlights the current destination line or node when a drop can occur.

Scrolling

When the end user is dragging data, they can scroll a destination control vertically by placing and holding the pointer near the bottom or top of the control. This is useful with long lists, grids or tree controls, when the $hiliteline property is enabled.

Events

In order to process a drag and drop procedure, you have to handle some events in the $event method in the source and target controls. The drag and drop events must be enabled as required in the $events property for a control.

evDrag

The client sends evDrag when the user attempts to start a drag. evDrag must be executed in a client-executed $event method, and it has the following event parameters:

Parameter Description
pDragType Always set to the value kDragData
pDragValue Described in the Drag Values section below.

If you use Quit event handler (discard event) during evDrag, you prevent the drag from starting.

Since it is not always convenient to mark $event for a control as client-executed, the client provides an alternative mechanism. You can implement a client-executed method named $drag for the object, with two parameters (type Var): pDragType and pDragValue. $drag returns true if the drag is allowed, false if not.

The client first attempts to call $drag. If $drag exists and returns true or false, then the drag starts or is not allowed to start respectively. If $drag does not exist, or does not return a value, Omnis sends evDrag if it is selected to execute in $events, and if $event is client-executed.

The drag will only fail to start if $drag executed and returned false, or if evDrag was sent and discarded by Quit event handler.

Data grids, lists and tree controls may select a line or node when the drag starts. This will result in a click event being sent just before $drag is called or evDrag is sent. If the click is sent to the server, it will execute in parallel with evDrag or $drag.

evDragFinished

The client sends evDragFinished when the user has finished a drag (released the pointer). It has no event-specific parameters. evDragFinished can be server or client executed.

evCanDrop

The client sends evCanDrop when the pointer is over a control that can accept a drop of the current drag type (kDragData or kDragFiles). evCanDrop must be executed in a client-executed $event method, and it has the following event parameters (note that pDropId is new for Studio 8.0):

Parameter Description
pDragType kDragData if data is being dragged from a control, or kDragFiles if a file or files are being dragged from the system
pDragValue Described in the Drag Values section below. Note that if pDragType is kDragFiles, this is empty during evCanDrop, since information about the files being dragged is not provided by the browser
pDragField

If pDragType is kDragData, this contains the name of the field from which data is being dragged.

If pDragType is kDragFiles, this is empty

pDropId (new for Studio 8.0) The identifier of the area of the control over which the drop is to occur. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

If you use Quit event handler (discard event) during evCanDrop, you prevent a drop on to the current control and pDropId combination.

Since it is not always convenient to mark $event as client-executed, the client provides an alternative mechanism. You can implement a client-executed method named $candrop for the object, with four parameters (type Var): pDragType, pDragValue, pDragField and pDropId. $candrop returns true if the drop is allowed, false if not.

If pDragField=$cobj.$name
  Quit method kFalse
End If

The client first attempts to call $candrop. If $candrop exists and returns true or false, then the drop is allowed or not allowed respectively. If $candrop does not exist, or does not return a value, Omnis sends evCanDrop if it is selected to execute in $events, and if $event is client-executed.

The drop will only be denied if $candrop executed and returned false, or if evCanDrop was sent and discarded by Quit event handler.

evWillDrop

The client sends evWillDrop when a drop occurs over a control and drop id combination for which which a drop is allowed according to the can drop processing. The client sends evWillDrop to the control being dragged - therefore, evWillDrop is not sent when dragging files from the system. evWillDrop can be server or client executed. It has the following event parameters:

Parameter Desciption
pDragType kDragData
pDragValue Described in the Drag Values section below.
pDropField The name of the control where the data is being dropped.
pDropId The identifier of the area of the control over which the drop is occurring. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

Quit event handler with discard event has no effect on evWillDrop.

evDrop

The client sends evDrop when a drop occurs over a control and drop id combination for which a drop is allowed according to the can drop processing. evDrop can be server or client executed. It has the following event parameters:

Parameter Description
pDragType kDragData if data is being dragged from a control, or kDragFiles if a file or files are being dragged from the system
pDragValue Described in the Drag Values section below.
pDragField

If pDragType is kDragData, this contains the name of the field from which data is being dragged.

if pDragType is kDragFiles, this is empty

pDropId The identifier of the area of the control over which the drop is occurring. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

Quit event handler with discard event has no effect on evDrop.

The following $event method is behind an image control and processes the dropped data (this is available in the example library).

On evDrop
  If pDragType=kDragData
    If pDragField='LeftImage'
      Calculate iLeftImage as iRightImage
      # pDragValue is base64, convert to binary for consistancy
      Calculate lBase64 as mid(pDragValue,pos(',',pDragValue)+1)
      Calculate iRightImage as binfrombase64(lBase64)
    End If
  Else
    Calculate lLine as 1
  # pDragValue can contain many lines use first file only
    Calculate iRightImageIdent as pDragValue.[lLine].4
    Do $cinst.$clientcommand(
    'readfile',row(iRightImageIdent,'iReadFileBin',kTrue))
    # readfile is a client command - see below
  End If

Drag Values

This section describes both the controls for which data can be dragged, and the drag values generated for each drag.

Combo box

pDragValue is the selected text dragged from the current selection in the entry field component of the combo box. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

Data grid

pDragValue is a list. For a single select data grid, the list has one line, containing the list line being dragged. For a multiple select data grid, the list contains the selected lines being dragged.

Entry

pDragValue is the selected text dragged from the current selection in the entry field. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

List

pDragValue is a list containing the list line being dragged.

Picture

pDragValue is a character string containing the URL of the picture being dragged. If the picture is populated using a variable and $mediatype, the URL is a data URL.

Rich text

pDragValue is the selected text dragged from the current selection in the entry field component of the rich text control; note that this is the plain text without any formatting. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

Tree

The tree only supports dragging when it is in dynamic mode (i.e. when $datamode has the value kKSTreeDynamicLoad). pDragValue is a row containing information about the node being dragged. The row has 3 columns:

Column Description
ident The ident of the node
tag The tag of the node (a character string)
text The node text

If the $hiliteline property is kTrue for a tree control, and the dropmode indicates that the tree is a potential drop target, the client will expand a node when the pointer enters it while dragging.

Tab control

The tab control contains some special logic that allows you to switch tabs while dragging, if this is the functionality you require. For can drop, it sets pDropId to the tab number of the tab under the pointer (or it sets pDropId to the current tab number if the pointer is over an area of the control which is not a tab). To switch tabs, implement a client-executed $candrop method for the tab control which executes:

  Calculate $cobj.$currenttab as pDropId
  Quit method kFalse

Dragging and Dropping Files

In addition to dragging and dropping data from one control to another, end users can drag files from their desktop and drop them onto a JavaScript control in a remote form in their browser. There are two new client commands that allow you to process dropped files, using the $clientcommand method.

closefile

The client records file idents (and their JavaScript File objects) in a table. Use closefile to remove the table entry and release resources. You should really do this for every ident passed in the drag value to evDrop, unless you use readfile which removes the table entry after reading the file.

The row passed to the “closefile” $clientcommand has a single column, which is the ident of the file to remove from the table. If you pass a row where the ident is zero, the client removes all entries from the table.

readfile

The readfile client command allows you to read the contents of a file identified by its ident. After attempting to read the file, the client removes the ident from the table, so a call to closefile is not required.

The row passed to readfile has the following structure:

row(ident,instance variable name,base64)

The columns are as follows:

Column Description
ident The ident of the file
instance variable name The name of an instance variable in the form used to call $clientcommand, that will receive the contents of the file. Note that this is a character string containing the instance variable name, not the instance variable itself
base64 A Boolean. If true, the file is read as base64; otherwise the file is read as text

The JavaScript FileReader which the client uses to read the file operates asynchronously, so a call to readfile starts the file reading process. When the file read is complete, the client calls the client-executed method $filereadcomplete in the form used to call $clientcommand. $filereadcomplete has two parameters:

Parameter Description
ident The ident of the file.
error text

Empty if the file was read successfully, meaning that the named instance variable has been populated with the file contents (either as text or base64-encoded text).

If not empty, some text describing why the file read failed

Files dragged from system

For file dragging, pDragValue is only populated for evDrop. It is a list of the files dragged from the system, with columns defined as follows:

Column Description
name The file name. Note this is just a name, not the path to the file
type The MIME type of the file if this was determined by the browser before passing it to the drop event
size The size of the file in bytes
ident An integer, unique in the context of the client, that identifies this dropped file. You can use this with the new client commands described in the later section about processing files.

Drag and Drop for Thick Client

evCanDrop, evWillDrop and evDrop for the thick client have a new event parameter, pDropId. This is significant when $hiliteline for the control is true, and contains the id of the location in the control where the drop would occur or is occurring, e.g. the list line for a list.

Accessibility

This release contains several enhancements to support the Web Content Accessibility Guidelines (WCAG 2.0) which will help to make your applications more accessible, primarily for people with disabilities. These guidelines have been adopted by many government agencies and guarantee an acceptable level of access to information and services via websites and applications for people with disabilities. You can read the following pages to gain a basic understanding of the WCAG requirements:

https://www.w3.org/WAI/standards-guidelines/

The WCAG implementation in Omnis Studio calls on the ARIA specification, which according to W3.org is “Accessible Rich Internet Applications (ARIA) defines a way to make Web content and Web applications more accessible to people with disabilities. It especially helps with dynamic content and advanced user interface controls developed with [various web technologies],” which includes technologies such as the JavaScript Client in Omnis Studio.

In practice, this means we have added various ARIA compliant properties to the controls for JavaScript remote forms which you can use in your web and mobile apps to support end users with disabilities. These properties will be read automatically when the screen reader capabilities are enabled in the end user’s browser or mobile device. (For testing, we have used ChromeVox by Google, but there are many other screen readers for Chrome and other browsers.)

Accessibility Properties

Most JavaScript controls have a set of basic ARIA and other accessibility properties which are interpreted by the screen reader in the browser. The ARIA properties in Omnis map closely to their equivalent ARIA attributes in HTML.

General properties

Several of the JavaScript controls have the following ARIA properties, while some other controls have additional properties (listed below). These properties are designed to work in a similar way as their equivalent ARIA attributes in HTML.

  1. $arialabel
    the text for the aria label, which is used when a text label is not visible on the form. If there is a label for the control, use the $arialabelledby property instead

  2. $arialabelledby
    the name of a control to act as a label for this control; for example, you could enter the name of a label object to link it to the control. A value in $arialabelledby will override the value in $arialabel; you can use a space separated list of controls to assign multiple controls as labels for the component

  3. $ariadescribedby
    the name of a control used to describe this control: similar to $arialabelledby, but could be used to provide more information or a longer description about the control; you can use a space separated list of controls to assign multiple controls as labels

You should note that JavaScript controls now have an $active property which works alongside $enabled allowing you to make controls active, inactive, enabled, or disabled, which helps you control accessibility and tab order in your remote forms.

Image based controls

You can assign an Alt text value to image-based controls, such as Picture and Activity, using the $alttext property:

  1. $alttext
    a short text to describe the appearance or function of an image, and equivalent to the “alt” attribute in HTML; this property is relevant for controls that contain an image or have a significant visual appearance, such as the Picture and Activity controls.

Page panes and Landmarks

So-called “Landmark Roles” in standard accessibility guidelines allow you to identify different areas of a form to allow screen readers to describe the structure of the page to end users. You can define Landmarks in your Omnis JavaScript remote forms using Page panes and by assigning the appropriate value to a new $landmark property for each pane: the options for the new property correspond to the same keywords used for landmarks in the accessibility guidelines (Main, Navigation, Banner).

  1. $landmark
    specifies a role to make the page pane an ARIA landmark region, a kLandmark… constant with kLandmarkNone as the default.

The Landmark options are:

Landmark option Description
kLandmarkMain A “Main” landmark which identifies the primary content of the remote form
kLandmarkNavigation A “Navigation” landmark which identifies an area containing navigation type control or list of links used for navigation
kLandmarkBanner A “Banner” landmark which identifies an area usually at the top of the form, possibly containing logo, company or application name and search box
kLandmarkContentinfo A “Contentinfo” landmark which typically identifies common information at the bottom of a form
kLandmarkComplementary A “Complementary” landmark which many contain supplementary information or further links, such as a sidebar
kLandmarkForm A “Form” landmark which identifies an area containing a number of input controls or other form controls
kLandmarkSearch A “Search” landmark which typically would contain a Search field and button
kLandmarkNone No landmark definition

Label controls

You can link a Label control to a specific Edit control, or you can tag a label as one of the HTML header types, using the following properties:

  1. $labelfor
    links a label to a control. If you use this with some controls such as the Edit control, the linked control will get the focus if the label is clicked. It can be used in addition to $arialabelledby.

  2. $tagtype
    can be used to set a label’s HTML tag type to one of the header types (<h1> etc.) which would allow the end user to navigate to different sections of a form: the default value is kJSLabelTypeLabel, which is a standard untagged label, and the other values include H1 to H6 for the header types.

Control text

If a control has some text assigned (e.g. a button), the screen reader will read out the text by default, therefore it is not always necessary to assign the ARIA properties to describe such controls. For example, the text for a Button control will be read by the screen reader, if no ARIA properties are specified, however the value in $text will be overridden if you specify $arialabel or $arialabelledby.

Content tips

The Edit control has the $::contenttip property which is a text string which is displayed in the edit field when it is empty and before the end user has entered any text. This can be used in addition to the ARIA label properties, to help label the edit controls on your forms: note it is good practice to add labels to all the edit controls on your form to help with accessibility, so do not rely solely on content tips to describe edit controls.

Keyboard Accessibility

As well as the ARIA properties, the behavior when using various keys to navigate a remote form, or inside more complex controls, has been improved. For example, when the end user presses the Tab key, the focus will jump from one control to another in a remote (web) form, or for complex items such as a Tab bar, the Tab key will put the focus inside the control and the arrow keys can be used to move from one element to another. In addition, the Arrow keys can be used to interact with controls, such as dropdown menus, while Enter and Spacebar can be used to select options or items. The Page Up/Down keys can be used to scroll a form or long list which has the focus.

Tabbing Order

The $order property determines the tabbing order for the controls within a remote form. The value of $order for each control is assigned automatically as you add controls to the form in design mode, starting at 1 and increasing by 1 for each control (note the $order values do not change if you rearrange the controls on the form). You can change the $order value of a control to change its tab order: when you change the value of one control, the value of other controls on the form will shuffle automatically.

For increased accessibility in your applications, you should carefully consider the tab order of the controls in your forms. In general, it is good practice to make the tab order run consecutively, that is, from one control to the next in a logical order: this could be from left to right starting at the top of the form, but the exact order may depend on the specific functions of your app. The tabbing order of the controls in the form is also used by the screen reader to “read out” or describe the contents of the form, so it’s important how you specify the tabbing order of the fields in your form. Once you tab into a container such as a page pane, the tab order takes you through all of the fields in the container, before tabbing out of the container.

The $startfield property specifies which field in a remote form will get the focus when the form is opened, overriding the control with its $order property set to 1; $startfield takes the field number as specified in the $order property of the control. Note this property may have an impact on accessibility, insofar as the field specified in $startfield may not be the first field on the form, thereby going against most accessibility practice.

Form Example

With the ARIA labels specified and the correct tabbing order defined, the end user can navigate the controls on a form from the keyboard, and, in addition, the screen reader can describe each control or area of the form page in turn.

Consider the following JavaScript remote form. In the first image, as the end user tabs to the First Name edit field, the field border will highlight, the screen reader will say aloud: “First name, Edit text”, and if there is a value in the field, as in this case, it will read that as well: “First name, Peter, Edit text”.

Using the Tab key, the end user can move from one control or area of the form to another. Successive tab presses will enter the Tab bar at the top of the form, then the Right and Left Arrow keys can be used to move along the Tab bar, and the Return key can be used to select a tab. Once the tab is selected, the screen reader will describe the item selected: “Careers / Education Experience, Tab selected, 2 of 4”.

Alpha Colors & Transparency

Some of the Remote form class controls (and Window class controls) support alpha colors, meaning that you can set the transparency for the color of the control. The color selection dialog in the Property Manager displays an alpha selection slider if a selected control supports alpha colors (the alpha slider is hidden for controls that do not support alpha).

The controls that support alpha colors include the Line, Oval, Rect and RoundRect background objects for windows.

The rgba() function can be used to set the RGB color and alpha setting for controls. The syntax is rgba(red,green,blue,alpha) with each parameter being an integer value in the range 0-255, where an alpha value of 255 means completely transparent. For example, to set the color of a window background object, in this case 50% transparent red:

Calculate $cwind.$bobjs.1016.$forecolor as rgb(255,0,0,127)

In addition, the color selection palette for the controls that support the use of a color palette or a popup color palette, including the colorpalette control, push buttons, and toolbars, include the new alpha selection slider.

When assigned a color with no alpha the palette will automatically hide the alpha slider. If the control is assigned an alpha value, the palette will display the new alpha slider.

For example, where colorbutton is a push button with $buttonmode set as kBMcolorpicker:

Do $cwind.$objs.colorbutton.$contents.$assign(rgb(255,0,0))  ## will cause the color palette not not show an alpha value
Do $cwind.$objs.colorbutton.$contents.$assign(rgb(255,0,0,127))  ## will cause the color palette to show an alpha value

The Omnis external component interface has been updated so external components can support alpha colors. The example WASH control has been updated to demonstrate this.

The Export & Import Library to JSON options have been updated to support alpha color values for controls.

Component Transparency

The majority of the JavaScript components have the $alpha and $backalpha properties which allow you to set the transparency of the foreground and background colors of the component.

$active & $enabled Properties

As part of the work to make the JavaScript Client meet Accessibility guidelines in Studio 10, a new $active property has been added to all JavaScript controls; the $active property is set to kTrue for all new controls, except the Label Control which has $active set to kFalse. The $active property allows you to control whether a component is active (kTrue) or inactive (kFalse) – in an inactive state, a component cannot be interacted with at all, so the end user cannot tab to it, the contents cannot be selected or scrolled (in a list), and user clicks on an inactive control are ignored. Therefore, when a control is inactive, it is completely ignored in the tabbing order, so when the end user tabs the focus will jump to the next active control – in the context of accessibility, an inactive component will be ignored.

The $enabled property allows you to disable a control, and many controls have this property, including: Bar Chart, Combo Box, Data Grid, Date Picker, Edit, List, Map, Pie Chart, Rich Text, and Tree list.

Existing users should see the What’s New in Studio 10 doc/pdf for further details about the new $active property and how it relates to the existing $enabled property.

Disabled Appearance Property

All controls that have the $enabled property have the $defaultdisabledappearance property. When $enabled = kFalse the $defaultdisabledappearance property defaults to true and the 'omnis-notenabled' css class is applied to the client element of the control. If $defaultdisabledappearance = kFalse, this class is not applied, which is what sets the text colour to grey when disabled.

Adding Customized JavaScript Components

You can add your own customized JavaScript components to the Component Store under your own tab. To do this, you need to create a new remote form, copy any components you want to customize from the JSFormComponents form, and add them to your own form. This might be useful if you always want to create edit controls or buttons with certain properties (e.g. colors or fonts)

You will need to edit the Component Store library (comps.lbs) to change the contents of the Component Store. To open the Component Store library, right click on the background of the Component Store itself and select ‘Show Component Library in Browser’. We recommend that you do not change the components in the JSFormComponents form since these are the default components that appear in the Component Store, rather you should create your own customized components using the following method.

Add a new remote form class to the Component Store library; note that the name of the new remote form will be used as the tab name in the Component Store toolbar. Set the $componenttype property of the remote form to kCompStoreDesignObjects using the Notation Inspector: to do this, open the Notation Inspector, click on the Search button (the cursor changes to a spy glass), click on your remote form in the Studio Browser, and in the Property Manager set $componenttype to kCompStoreDesignObjects (note the $componenttype property will only be displayed via the Notation Inspector).

With your new remote form open, open the JSFormComponents remote form next to it. Drag any JavaScript controls you want to customize from JSFormComponents into your remote form and change their properties or appearance as required. After you hide the Component Store library, the customized JavaScript controls will be available in the new group in the Component Store.

JavaScript Component Templates

When you add a JavaScript Component to a remote form in your code at runtime, Omnis uses a template to create the object with all the required properties and methods. There is a template for every type of JavaScript Component, and the templates are located in the \studio\componenttemplates folder.

The component templates match the default components in the Component Store, and should not be edited. There are templates for report and window class components as well.

Activity Control

The Activity Control provides an animated image to show some activity on the client, for example, during a long list calculation or search operation on the Omnis Server. It has the following custom properties:

Property Description
$activitystyle The style of the indicator, one of the following constants:
kJSActivityBar: a moving bar
kJSActivityBlock: a moving block
kJSActivitySmallSpinner: a small rotating spinner
kJSActivityCustomLink: the image in $customlink is used
$customlink The path of an animated GIF which can be displayed when $activitystyle is set to kJSActivityCustomLink

The $activitystyle property specifies the style of the control, either a Bar, Block, a small Spinner, or a custom Gif specified in $customlink.

The following code assigns a custom link to the activity control:

There is an example app in the Samples section in the Hub in the Studio Browser showing the different activity controls available and how to set a custom animated Gif; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

Alternatively, you could consider using the showloadingoverlay client command to show a loading indicator (animated image) over a remote form or specific component.

Background Control

The Background Control allows you to draw various shapes in your remote forms: you assign the shape to the object by setting the $::shape property to one of the kJSBack... constants. It can be assigned one of a number of shapes including: Ellipse/Circle, Rectangle/Square, Rounded rectangle/Square, Triangle, Horizontal Line, Vertical Line, and Image.

If the object is an Image, the image source is specified in $imagepath as a URL relative to the Omnis tree during development or your web server for deployment.

You can assign a solid color or gradient fill to a background component by setting its $backpattern, $forecolor and $backcolor. You can also assign the stroke (border) thickness and color by setting $strokewidth and $bordercolor.

Animations and Changing Attributes

The Background Control has the $animation and $attr properties which allow various animations or effects to be assigned to the object, such as fading the object in or out, or for $attr various attributes of the object to be changed. The $animation and $attr properties must be assigned at runtime and accept a string containing various parameters depending on the function or attribute.

There is an example app in the Samples section in the Hub in the Studio Browser showing how can use animations to move and fade objects to create a richer UI; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

Apart from the scale attribute, the browser must support the Raphael JavaScript library to allow animations and attribute changes (more details about the parameters you can use are available from http://raphaeljs.com).

The $animation property follows the general format:

function( newvalue, time(milliseconds), ease(optional), complete_context(optional) )

The functions available in $animation are:

  1. scale
    increases and decreases the size of the object

scale( newvalue, time(milliseconds), ease(optional), complete_context(optional) )
  1. alpha
    changes the transparency of the object

alpha( newvalue, time(milliseconds), ease(optional) , complete_context(optional) )
  1. rotate
    rotates the object

rotate( newvalue, time(milliseconds), ease(optional) , complete_context(optional) )

For example:

Calculate $cinst.$objs.backgroundobject.$animation as "alpha(0,500,<>,fade_complete)"

fades the object to alpha value 0 over 500 milliseconds using a ‘slow, faster, slow’ easing method (see below) and when complete calls evAnimComplete with a parameter "complete_context".

You can use the complete event to chain the next animation, therefore to pulse an object you could use:

Calculate $cinst.$objs.backgroundobject.$animation as "alpha(0,500,<>,fade_off)"

You could use the event handling method:

On evAnimComplete
  If ( pAnimContext="fade_off" )
    Calculate $cwind.$objs.backgroundobject.$animation as       "alpha(0,500,<>,fade_on)"
  Else if ( pAnimContext="fade_on" )
    Calculate $cwind.$objs.backgroundobject.$animation as
      "alpha(0,500,<>,fade_off)"
  End if

Ease transition effects

The following ease transition effects or “eases” are supported for animations:

= linear and default if not specified
> fast then slowing
< slow then faster
<> slow, faster, slow
bounce object bounces
elastic object stretches
backIn object backs in
backOut object backs out

Changing Background Attributes

The $attr property allows you to change various attributes of the object, such as their transparency. For example, you can assign an alpha gradient to an object using the following method:

# note must be assigned at runtime
Do $cinst.$objs.backgroundobject.$attr.$assign('attr(gradient, 0-#FFFFFF:10-#FFFFFF)')
Do $cinst.$objs.backgroundobject.$attr.$assign('attr(opacity,0.0)')

Bar and Pie Chart Control

Omnis Studio provides two chart controls: a Bar Chart and a Pie Chart. The data to be represented in both these controls is contained in a list variable which is assigned to the $dataname property of the control. There is a sample app for both Bar and Pie charts in the JavaScript Apps Gallery on the Omnis website (www.omnis.net), and under the Samples option in the Hub in the Studio Browser.

There are various properties (on the Appearance tab in the Property Manager) that allow you to control the appearance of a Bar and Pie chart. The bars and segments use a set of default colors but you can specify your own colors at runtime.

For Bar charts you can set $chartdirection to vertical (the default) or horizontal bars, the style of the bar ends as the $barends property (kJSBarEndSharp is shown below), and you can display data values when the end user’s mouse hovers over the bar by setting $showvalue to True (the default).

Specific properties for Pie charts are described under the Pie Chart Control section.

List data structure

To draw a simple bar or pie chart, the list variable assigned to the $dataname property of the chart component needs to contain at least two columns. The first column contains the value for the data point, and the second column contains the label or name for the data point. For example, to construct a simple bar chart showing a list of figures for sales agents, you could use the following method:

# create vars bar_data (List), amount (Number), name (Char)
Do bar_data.$define(amount,nam)
Do bar_data.$add(120,'Steve')
Do bar_data.$add(230,'Dave')
Do bar_data.$add(245,'Anita')
Do bar_data.$add(125,'Claire')
Do bar_data.$add(280,'Ben')

With the $showvalue property enabled (a value is displayed when the end user passes the pointer over each bar), the method produces the following chart.

For Pie charts, each value is shown as a percentage of the total of all the values in your list, that is, the size of each segment (angle) is calculated as the proportion of the individual value when compared to the total of all values in the list.

Main and Axis Titles

There are a number of properties in the Bar Chart to allow you to add a main title, as well as titles for the x and y axis. In addition, there are properties to hide or show the x and y axis details or units.

$maintitle The main title for the chart
$xtitle title for the x axis
$ytitle title for the y axis
$showxaxis if kTrue the chart shows x-axis details
$showyaxis if kTrue the chart shows y-axis details

Bar & Segment Color

You can specify your own colors for the bars or segments in a Bar or Pie chart using the runtime-only property $colorlist, rather than using the default colors. You need to create a list of strings representing CSS colors and assign the list to the $colorlist property, for example:

Do iColorList.$define(iColor)
Do iColorList.$add("#CE3D3D")
Do iColorList.$add("rgb(81, 206, 61)")
Do iColorList.$add("hsl(230, 60%, 52%)")
Do iColorList.$add("Gold")
Do $cinst.$objs.PieChart.$colorlist.$assign(iColorList)

The accepted color formats are: Hex Code RGB, Decimal Code RGB, HSL, or Color Name, and the formats can be mixed throughout the list as in the example above.

If there are not enough colors available in the color list for the number of segments in the chart, then Omnis will repeat the colors in $colorlist. Therefore, if you want to avoid repeating colors, create a color list containing more colors than you will generally need to cater to the number of data points in your chart.

Events

Bar charts report the evBarClicked event with the bar clicked in the pBar parameter. Similarly, Pie charts report the evSegmentClicked event with the segment clicked reported in pPieSegment.

# event method for bar chart, message is a field on the form
On evBarClicked
  Calculate message as con("Bar clicked: ",pBar
# event method for pie chart
On evSegmentClicked
  Calculate message as con("Segment clicked: ",pPieSegment)

Button Control

The Button control is a basic pushbutton that the end user can click to confirm something or initiate a process, such as an OK or Cancel button, or a Send button.

The button can display an icon, specified in the $iconid property (a URL pointing to an image file in the ‘html/icons’ folder), and/or a single line of plain text specified in $text. The Button has the following custom properties:

Property Description
$buttonbackiconid The icon id of background image for the button. To use the default system button, set $buttonbackiconid to zero and $buttoncolor to kColorDefault
$buttoncolor The color of the button. To use the default system button, set $buttonbackiconid to zero and $buttoncolor to kColorDefault
$textbeforeicon If true, and the control has both text and an icon, and the text is displayed to the left of the icon
$textishtml Specifies that the text entered in $text is treated as HTML
$::vertical If true, the text and icon are arranged vertically

HTML Button Text

When set to kTrue the $textishtml property specifies that the text for the button (entered in $text) is treated as HTML, therefore any HTML can be used to style the text. For example, you can insert a line break by setting this new property to kTrue, and using <br> in $text for the button wherever a line break is required.

The $textishtml property also allows other styling of the button text using various character and color attributes. Note that design mode does not render the HTML (the raw HTML code is displayed), and if you use attributes in the HTML they must be enclosed in single quotes.

Events

When a Button is clicked an evClick event is triggered which you can handle in the event handling method behind the button.

On evClick
  Do something…

Example

For example, the sample apps in the Applets section in the Hub have an About window which is loaded into a subform and displayed using an animation; see the Animations section for the About button code. The Close button on the About windows simply closes the About form by sending a message to the main remote form to run a method; it has the following code:

On evClick
  Do $cwind.$closeAbout()

In this case, $cwind is a reference to the main parent form which contains a method called $closeAbout which contains code to fade out the About form and reset various buttons on the main form.

Checkbox Control

The Checkbox control can represent On / Off or Yes / No values and is typically used to allow the end user to turn an option on or off, or accept or decline a preference. The variable you specify in the $dataname property of a Checkbox should be a Number or Boolean variable. The $text property specifies the label text for the Checkbox.

When a Checkbox is clicked an evClick event is triggered with the current value reported in the pNewVal parameter.

Example

There is an example app in the Samples section in the Hub in the Studio Browser to show how you can use a check box (and a Radiogroup); the same app is in the JS Component gallery on the Omnis website at: www.omnis.net. The example uses a series of check boxes and a radio button group to filter a list of people based on their gender and age group. The group of controls on the remote form could look like this:

The $dataname for each of the check boxes is iAgeRange1, iAgeRange2, and iAgeRange3 respectively. These are all Boolean variables defined in the remote form, and the $dataname of the Radio button group is iFilter, which is defined as a Short integer. Each separate check box and the Radio group has a simple event method, which is:

On evClick
  Do method filter

which will call the ‘filter’ class method when any of these objects is clicked. The filter method filters the contents of the list called iList based on the selection of the check boxes and radio buttons, and has the following code:

Do iList.$unfilter(0)

If not(iAgeRange1)
 Do iList.$filter(not(iAge<=20))
End If
If not(iAgeRange2)
  Do iList.$filter(not(iAge>=21&iAge<=40))
End If
If not(iAgeRange3)
 Do iList.$filter(not(iAge>40))
End If
Switch iFilter
  Case 1
    Do iList.$filter(iGender='F')
  Case 2
    Do iList.$filter(iGender='M')
End Switch
  

Note the ‘Smart list’ capability has to be enabled on the iList variable to allow the built-in filtering using the $filter method; this is done in the $construct method of the form in the example, using the following code:

Do iList.$smartlist.$assign(kTrue)
  

Combo Box

The ComboBox control is a combination of a data field and a dropdown list from which the end user can make a selection or enter their own value into the field. There is an example app in the Samples section in the Hub in the Studio Browser, and in the JS Component gallery on the Omins website: www.omnis.net.

The variable for the data field part is specified in the $dataname property. You can specify a default list of options in the $defaulttext property, which is a comma-separated list of options, or build the list dynamically (with $::listname, see below). When $defaulttext is specified, $defaultline specifies the list line which is selected when the form is opened (set to 1 by default). The $::listheight property specifies the height of the droplist. The Combo Box has the $negallowed property which means it can display negative numbers.

Rather than using a default list specified in $defaulttext, you can assign the name of a list variable to the $::listname property to assign the contents of the list to the droplist part of the combo box; $listcolumn specifies which column of the list variable is used to populate the droplist part of the combo box.

When the list in a ComboBox is clicked an evClick is generated with the selected list line reported in the pLineNumber parameter.

Content Tips

The Combo box control has the $::contenttip property which is a text string which is displayed in the edit field part of the combo box when it is empty to help the user understand what content should be entered into the field. For example, for a Last name field you could enter ‘Enter your last name’ into $::contenttip to prompt the end user for their last name.

Auto correction and capitalization

Combo boxes have the $autocorrect and $autocapitalize properties, which when enabled means that any text entered into the edit field section of the control is corrected for spelling and capitalization automatically.

Example

The maintenance screen in the Webshop sample app allows the user to enter new products or delete existing ones: specifically, the data in the Webshop app contains food and drink items, but it could be any type of products. When the user enters a new product, they can select the product type from a Combo control; this allows the user to select from a list of given product types or enter a new one.

The $dataname of the combo control is set to iDataRow.product_group, and the $::listname is iGroupList. The evAfter event is enabled in the $events property of the control. In the $construct method of the form, the iDataRow row variable is defined from the T_Products table class, as follows:

# $construct of jsMaintenance form
# sets up form sizes, etc, then…
Do iDataRow.$definefromsqlclass($tables.T_Products)
Do $cinst.$objs.$sendall($ref.$construct())

The last line of code triggers all the field specific $construct methods which in this case includes the Combo box control; the code defines the iGroupList from the product_group column in the T_Products table class, performs a select on the data, and fetches all the data back into the iGroupList variable.

Do iGroupList.$definefromsqlclass($tables.T_Products,'product_group')
Do iGroupList.$selectdistinct()
Do iGroupList.$fetch(kFetchAll)

When the user selects an item in the list or enters a new item into the entry part of the combo box, an evAfter event is triggered and the $event method behind the combo control is called, as follows:

On evAfter
 Do method newItem
 Do $cinst.$setcurfield('product_name'## puts the focus in the product_name field

The newItem method is placed behind the Combo box control itself and contains the following code:

Do iGroupList.$search(
  $ref.product_group=iDataRow.product_group,kTrue,kFalse,
  kFalse,kFalse## test iGroupList for group/type entered
If iGroupList.$line=0 ## if not found in the group list
  Do iGroupList.$add().product_group.$assign(
  iDataRow.product_group## add a new group to the list
End If

Complex Grid

A Complex Grid can display multiple rows and columns of data taken from a list variable specified in the $dataname property of the control. You can use a $construct method behind the grid control itself to build the list data to populate the fields in the complex grid. To create a complex grid, you can place other controls in the row and header sections of the grid control, including standard entry fields, droplists, buttons, and check boxes: these controls are duplicated for every row in the grid, displaying each row of data from the data list. The $dataname of each component you place in the grid must correspond to a column in your list variable supplying the data to the grid. A complex grid is a container field having its own $objs group containing the objects inside the grid control.

There is a Complex Grid example app in the Samples section in the Hub in the Studio Browser, plus there is a Webshop app that uses complex grids in the Applets section; the webshop app is described later in this section.

Events

You can place event methods behind the embedded controls to react to user input and clicks within individual fields/cells in the grid. For example, you can have a button in each row of the grid which when clicked triggers an evClick event which runs the $event method for the button that performs an action based on the row clicked.

The Complex Grid itself can have evClick & evDoubleClick events. When clicking on the background of a complex grid row, or a control within the grid which does not have a click event enabled, the evClick or evDoubleClick will be fired. Both of these events receive pLineNumber parameters indicating the line number which was clicked. If no line was clicked (the end user has clicked on empty space), pLineNumber will be 0.

Object position in the grid

Every field or object in a Complex grid has the $gridsection property which tells you the section the object is in, while $gridcolumn which tells you its column. The $gridsection property is shown in the Notation Inspector so you can inspect its value for an object in a grid section at runtime.

List Pager

The Complex Grid control has the $pagesize property that allows you to display the lines in the grid as separate pages: see the List Control section for more details.

Scrolling

The complex grid has the properties $vscroll and $hscroll to allow you to scroll a grid dynamically. The $vscroll property takes the row number in the grid to scroll to. The $hscroll property takes the absolute horizontal pixel position to scroll to in relation to the left edge of the grid control, that is, the grid will not scroll by a specified amount, rather the grid will scroll to the absolute position in the grid specified by $hscroll.

Scroll Tips

You can use the property $vscrolltips to display a scroll tip when a complex grid scrolls vertically. If $vscrolltips is kTrue, the default scroll tip is the contents of column 1 of the list for the first fully displayed row. To override this default scroll tip, implement a client-executed method for the complex grid object, called $getscrolltip. $getscrolltip accepts a single parameter (the row number for which the scroll tip is required), and returns the scroll tip text.

Dropping data onto a grid

The end user can drag data from a remote form field and drop it onto a cell in the grid. Complex grids have the evCanDrop and evDrop events, and the $dropmode property to enable drop support. The pDropRow event parameter is available for evCanDrop, evWillDrop and evDrop events, and reports the row of the complex grid on which the drop is to occur (zero if the control does not belong to a complex grid).

It is possible to drop data onto a single control in the grid (a cell) in any row in the grid, as long as it has its $dropmode enabled. If not, the complex grid itself will receive the drop.

Exceptions

You can format individual cells in a complex grid by applying “exceptions” to those cells: you can then apply different formatting to those cells. For example:

Calculate $cinst.$objs.Products.$objs.Product.6.$backcolor as kBlue

or using indirection:

Calculate lNum as 4
Calculate lProp as "$backcolor"
Calculate $cinst.$objs.Products.$objs.Product.[lNum].[lPropas kBlue

You can attempt to set an exception for any property, although in practice this may not be satisfactory for some properties. Appearance properties, and button text for example should however all work as expected.

You can set exceptions in both server and client executed code.

In addition, the method $clearexceptions() can be used to clear exceptions. For example (Products is a complex grid object):

# Clear all exceptions for the Product object on all lines where it has exceptions
Do $cinst.$objs.Products.$objs.Product.$clearexceptions()
# Clear all exceptions for the Product object on line 4
$cinst.$objs.Products.$objs.Product.$clearexceptions(4)
# Clear all exceptions set in the complex grid
Do $cinst.$objs.Products.$clearexceptions()
# Clear all exceptions set on line 4 of the complex grid
Do $cinst.$objs.Products.$clearexceptions(4)

You can execute $clearexceptions() in both server and client executed code.

Existing users should note: Prior to the implementation of exceptions, objects in the row section could lose property values set at runtime, when updating the grid data. This issue has been resolved as part of the exception implementation.

Complex Grid Restrictions

A complex grid cannot contain another complex grid as a member, in any section. A complex grid cannot contain a subform in the row section. These restrictions apply to controls that would be direct members of the section, or indirect members that are children of a paged pane. Omnis enforces this by preventing you from dropping these controls into the relevant section(s).

Note: the $add() method for remote form class objects has not been updated to enforce this restriction, therefore using $add() to place controls in a section which does not support them could lead to undesirable results.

Example

The Webshop sample app, available in the Hub in the Studio Browser, uses a Complex grid in the main product remote form to display a list of products. Individual fields for the picture, name, description, price/size of the product are added to the first line of the complex grid; when the form is opened on the client and the data is loaded into the grid, these fields and are repeated for each row in the data list (one row per product).

The $dataname of the complex grid is set to iProductList which is built from a table class T_Products which is linked to a schema class sProducts. A $construct method is placed behind the complex grid that builds the list needed for the complex grid data.

# $construct of complex grid control in jsShop form
Do iProductList.$definefromsqlclass($tables.T_Products)
Calculate whereClause as con('WHERE product_group = ',kSq,'Appetizers',kSq)
Do $cfield.$build(whereClause## calls $build
# $build method also behind complex grid control in jsShop form
Do iProductList.$select(pWhereClause,' ORDER BY product_isfood desc')
Do iProductList.$fetch(kFetchAll)

When the form is opened, the $construct method is run and the product list is built from the database, while the data itself is displayed in the various fields embedded in the complex grid with each product shown on a separate line in the complex grid.

There are three order buttons placed in the row of the complex grid; they are repeated for each product in the list and allow the end user to order different sizes of product, such as a small, medium, or large drink or pizza. Each of the buttons has a simple method behind it that passes a number to the process_order class method; the first button sends value 1, the second button value 2, and the third button value 3.

# ‘Order now’ button method
On evClick
  Do method process_order (1)

See the Data Grid section for the process_order method which updates the iOrderList and the Orders data grid accordingly.

Data Grid Control

The Data Grid is a powerful and versatile control that can display character and numeric data in a grid like structure, much like a table or spreadsheet format, allowing you to create compact, data-rich UIs for your web and mobile applications. There is an example app in the Samples section in the Hub in the Studio Browser, showing how to use Data grids, including how to use custom cell formatting: in addition, the Webshop example under the Applets section uses a data grid which is described later in this section.

The content for a data grid is supplied from a list variable specified in the $dataname property. The number of columns in your grid would normally correspond to the number of columns in your data list, while the number of columns in the grid object itself in set by $designcols. For each column in the grid (under the Column Tab in the Property Manager) you need to assign $columndatacol to map the grid column to a column in your data list: you can use the column name or number in $columndatacol.

The $hasheader property specifies whether or not the grid has a main header, while $headertext specifies the text for the header and $::boldheader lets you specify a bold header. The $columnnames property lets you specify the heading text for each column in the grid (a comma separated list of names) which do not have to be the same names as the column names in your data list variable.

The $currentcolumn property is the current grid column for which properties are being displayed under the Column tab in the Property Manager. The $movecolumn property allows you to move a column to the specified position in the grid during design mode.

The end user can enter data into the cells of the grid if $enterable is enabled, and the grid can grow by adding more lines to accommodate more data if $extendable is enabled. The height of the rows in a data grid adjusts to fit the data automatically, unless you specify a height in pixels in $::rowheight.

List Pager

The Data Grid control has the $pagesize property that allows you to display the lines in the grid as separate pages: see the List Control section for more details about the List Pager.

Column Width

The $::columnwidths property allows you to set up the widths of the columns, which is a comma separated list of integer values representing each column width in pixels. In order for the data grid to cater for multiple screen sizes, the $columnwidthsarepercentage property allows you to switch to using a percentage in the $::columnwidths property. If true, the column widths in the data grid specify a percentage of the width of the control rather than a specific number of pixels. This affects the properties $columnwidth, $::columnwidths, and $columnminwidth.

Pick List

You can add a dropdown list or “picklist” to one of the columns in your data grid to allow the end user to select a value from a list of preset values. You must create another list containing the list of preset values and specify its name in the $columnpicklist property for the column in which you want to add the picklist. The datatype of the column in your main data list variable corresponding to the picklist column must be an integer, and $columnmode for the grid column itself must be set to kJSDataGridModeDropList. The integer value stored in this column will correspond to the line number of the selected line in the picklist.

For example, if you want to list a product in your main grid field that has only four possible colors, you could create a sublist containing those color values and assign this sublist to a column in your grid field corresponding to an integer column in your main data list: this would allow the end user to choose a color from a preset list of colors.

Cell Formatting

You can apply your own formatting to individual cells in a Data Grid. For user-defined Data Grids (where $userdefined is set to true) and where a column has its columnmode set to kJSDataGridModeCustomFormat, you can customize the HTML used to layout or format an individual cell in the grid.

When the grid is rendered (this occurs on demand e.g. when scrolling to make new data visible), it calls the object client method:

$formatcell(list line number, designed grid column number) 

which you implement to return html for the formatted cell contents. This HTML can, within reason, be anything you like: you can also just return a text string. To assist this, there are two new calls you can make:

  1. styledtohtml(text)
    the styledtohtml(text) function returns the HTML representing the text string containing embedded styles inserted using style() function. This is a built-in function, under the General tab of the Catalog, which must be run in a client-executed method in the JavaScript Client only.

  2. $addcolorcss(cClassName,iRgbColor,iAlpha)
    is a method of the data grid object (as such it can only be executed in client-executed methods). Call this in $init to add your own background color class to use with the html returned by kJSDataGridModeCustomFormat.This class takes browser specific issues with transparency into account.

For example, you can use the following method:

Do $cinst.$objs.dat.$addcolorcss("myclass",rgb(255,0,0),128)

in $init, and then do the following in $formatcell:

Calculate columnvalue as iList.[row].[col]
if (columnvalue == "bad")
  Quit method con(
    '<div class="myclass"
    style="padding:0;margin:0;height:16px">
    ',columnvalue,'&nbsp;','</div>')
  Quit method columnvalue

Using transparency in the CSS background allows the selection color to show through the formatted cell.

There is an example app in the Samples section in the Hub in the Studio Browser to show how you can use the grid formatting; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

Data Grid Filter

You can add a filter to a data grid by enabling the $hasfilerarea property. When true, the grid has a filter area which can be opened by clicking on a ‘spyglass’ button in the data grid header; the search filter will be applied to the current column (the Product column in the screen shown below). The end user can type into the filter entry box to filter the contents displayed in the column. The following image shows the filter enabled for column 1:

The other properties to set up the filter include:

  1. $filtercol
    The grid column to which the filter will apply; this can be changed at runtime in a client method, see below

  2. $filterareaheight
    The height of the filter area (when $hasfilerarea is enabled); if zero, the height is calculated automatically

  3. $filterlabel
    The text label for the filter entry field

  4. $filtervalue
    The name of an instance variable that contains the value used for filtering

The following code is the $event method for a data grid, set to execute on the client:

On evCellChanged
 Calculate iHorzCell as pHorzCell
 Calculate iVertCell as pVertCell
On evHeaderClick
 Calculate $cobj.$filtercol as pHorzCell
 # assigns the filter to the selected column
 Calculate lColNames as $cobj.$columnnames
 Calculate lColIndex as pHorzCell-1
 # Find the display name of the column clicked:
 JavaScript: FilterName = lColNames.split(",")[lColIndex];
 Calculate $cobj.$filterlabel as con(lFilterName,": ")

In addition to being able to set a single filter for any column, you can enable a filter for all the columns in the grid by enabling the $multifilters property (in this case $filtercol is ignored). When $multifilters is enabled, a default filter is added to each column in the grid (when the spyglass is clicked).

The filter has a number of operators to determine the search type. When a search type is selected, a search field is displayed allowing the end user to add a search string; for date columns a date picker is also displayed.

Filter control method

You can implement a control method on a data grid, which will be called whenever the user types text into the data grid's filter (if enabled). The method should be named $filtergrid and set to execute on the client.

$filtergrid(Column dat, Filter String) 

The $filtergrid method receives two parameters: ColumnData & FilterString, the data in the filtered column for the row in question and the current filter string.

You can return true to say that the row should be included, or false to exclude it. If you return null (or nothing), the default handling will be applied to determine if the row should be shown.

Row Formatting

The $setlineheight property allows you to center text vertically in the rows in the data grid. If true, the grid sets the line height so that text is vertically centered in each row (the default is kFalse).

Header Formatting

You can create your own formatting for column headers by adding a client-side method called $formatheader which takes two parameters:

  1. Parameter 1: the text for the column header

  2. Parameter 2: the design grid column number (1-n)

The return value is HTML to use for the header, for example, for a bold header:

<b>Param 1</b>

For red text:

<span style="color:red">Param 1</span>

For right justified text (using float so that sort indicators still appear):

<div style="float:right;">Param 1</div>

You can reassign the column name to force a call to recalculate the HTML for the column header, even if the text has not changed.

Row Styles

The $rowcsscol property allows you to specify CSS styles for a row in a data grid. The $rowcsscol property specifies the column number in the $dataname list for specifying custom CSS class names to apply to individual rows. Multiple class names can be assigned with a space separated list.

The CSS rules for classes can be added to user.css: it may be necessary to use !important to override existing styles. For example, in user.css:

.omnis-datagrid .highlight {
background: red !important;
color: white !important;
}

Column Data Type Formatting

When you set $columnmode to kJSDataGridModeFormatted, the mode acts like kJSDataGridModeAuto, in that the data grid automatically handles the data based on its type. However, the grid formats the data using the properties $columndateformat, $columndateformatcustom, and $columnnumberformat, rather than the $js...format... properties.

You can use an integer column data type to represent a checkbox. To do this set $columnmode to kJSDataGridModeFormatted and set the $columnnumberformat to “bool”. This will cause integer data to be treated as Boolean, where non-zero means true, and zero means false. If the end user updates the grid using the check box, 1 will be stored in the list for true, and zero for false.

Highlighting Cells

The properties $hilitefocusedcell and $cellhilitecolor allow you to highlight the cell that has the focus.

  1. $hilitefocusedcell
    If true, the focused cell will be outlined in the color specified by $cellhilitecolor

  2. $cellhilitecolor
    The color of the focused cell's outline, provided $hilitefocusedcell is kTrue

Grid Scrolling

JavaScript Data Grids have $vscroll and $hscroll properties which allow you to scroll a grid vertically or horizontally at runtime in the client browser; note these properties are write-only meaning that you cannot return their values at runtime.

The vertical scroll value assigned using $vscroll is the position of the scroll bar according to row number in the control. The horizontal scroll value assigned using $hscroll is the designed grid column number for a data grid.

Auto Correction and Capitalization

Datagrids have the $autocorrect and $autocapitalize properties which means that text entered into the cells of a data grid are corrected for spelling and capitalization automatically.

Validating data

The $validate method allows you to validate the data entered into any cell in the grid. If present, the method is called when an edit is made to a grid cell, with the parameters pRow, pCol, pNewValue being passed to the method. The method returns true to indicate that the change is valid, depending on the validation code you add to the method, otherwise the value in the cell will revert to the previous value.

Numeric Data Validation

Data entered in grid columns with the numeric data type will be validated automatically, as it is entered. When the end user tries to enter invalid data into the grid column field, such as an alphabetic character, the data is rejected, and the field is highlighted momentarily to indicate an error (the default action is to show a red border).

When leaving the entry field, the value is normalized, that is, integer data is constrained to the valid range or for other numbers it is rounded to the correct number of decimal places; also, leading zeroes are removed, and so on.

Initial Row Values

When a Data grid has $enterable & $extendable enabled, the user can add a new row by entering data into the empty 'extendable' row at the bottom, and the remainder of the columns in that row are given default values.

However, if you want to override these defaults, you can now implement a method named $initextendrow on the data grid control. This method should return a row with column values set to the appropriate defaults you wish to use. The order and the data type of the columns must match the order and types of the columns of the list defining the Datagrid and specified in $dataname.

Inserting Dates as null values

Data Grid columns have the property $columnallownulldateinput to allow a null value to be added to a row of data when the end user tabs out of the last line of the grid to create a new line automatically.

If $columnallownulldateinput is true, and the datatype of the column is Date, cells in the column will default to a value of null when added through the UI. Additionally, if this property is enabled, the end user can change a date to be null by pressing Backspace or Delete while the cell has focus.

If false (the default), the behaviour is unchanged from previous versions. Note it is not possible for the end user to input null values into the grid, via the popup date picker, for example.

Using the Date Picker

The Data Grid uses the appropriate Date Picker according to the constant specified in $dateformat or $columndateformat. If this is set to kJSFormatCustom, then $dateformatcustom or $customdateformatcustom is used as above. If set to kJSFormatNone, then it will attempt to use the data subtype applied to the dataname of the column to determine which picker to use.

Entering Dates Manually

The properties $editdatetext and $columnallownulldateinput allow end users to enter a date manually via the keyboard rather than having to use the date picker. When set to true, $editdatetext (and $columneditdatetext when $userdefined=kTrue), allows keyboard entry of a date/time. If a date that cannot be parsed is entered, it will revert to the previously stored date, unless $columnallownulldateinput=kTrue, in which case the field data will become null.

Note this has no effect on the date picker popup control, so if you don’t want to use the picker you need to apply the following css rule to hide the picker:

.datetimepopup-button {
visibility: hidden;
}
 

Copying data

The end user can copy data from selected rows. Data grids return the copied rows as tab-separated values. You can add a client executed method named "$clipboardcopy" to the control to handle the clipboard content. The method can return character data or a list. If it is a list, column 1 must be the MIME type and column 2 must be the content.

For example:

# $clipboardcopy client method
Do lList.$define(lMime,lContent)
Do lList.$add("text/plain","Copy this as plain text")
Do lList.$add("text/html","Copy this as <b><u>HTML</u></b> instead")
Quit method lList

evCellValueChanged event

The evCellValueChanged event reports when the user has changed the value of a cell, while there has been a small change to the existing evCellChanged event.

  1. evCellValueChanged (pHorzCell, pVertCell)
    sent when the user has changed the value of a cell.
    pHorzCell - The column number of the cell that has changed.
    pVertCell - The row number of the cell that has changed.

  2. evCellChanged (pHorzCell, pVertCell)
    sent when the current cell has changed, e.g. when navigating between cells with the arrow keys or clicking a cell that isn't the current cell.
    pHorzCell - The column number of the new current cell.
    pVertCell - The row number of the new current cell.

Fixed Columns

The $frozencolumns property allows you to fix or “freeze” a number of columns to the left of the grid, so they do not scroll when the other columns in the grid are scrolled horizontally. The property takes a number value from 1 upwards corresponding to the first column on the left of the grid. For example, you could specify a value of 1 to create row headings that are fixed to the left of the grid.

Column Header Justification

The following properties allow you to justify content in data grid column headers.

  1. $headerjst
    A kJSDataGridJst… constant that sets the alignment of the data grid header

  2. $columnheadersjst
    A kJSDataGridJst… constant that sets the alignment of all the column headers; overrides $columnheaderjst

  3. $columnheaderjst
    A kJSDataGridJst… constant that sets the alignment of all the current column’s header; $columnheadersjst must be set to kJSDataGridJstDefault

Color Picker

The kJSDataGridModeColorPicker column type displays a color picker in the data grid cell allowing the end user to select a color. A numeric color value is returned from the picker, or a color functions can be used to set the color of the column, such as truergb(kDarkGreen), or rgb(255,0,0).

For example, to set the colors for the first 3 lines in the third column, use the code:

 Do iList.$add('Bag','21/02/12',truergb(kDarkGreen),'19.00',kTrue,'')
 Do iList.$add('Balls','20/02/12',rgb(255,0,0),'4.55',kFalse,'Delivery next week')
 Do iList.$add('Clubs','20/12/11',rgb(0,0,255),'299.99',kTrue,'')

You can specify the text for the OK and Cancel buttons on the color picker using $colorpickeroktext and $colorpickercanceltext.

An entry field has been added to the color picker which accepts colors in the hex (the default), rgb or color name formats. Localisable strings have been added for the color entry field for the aria-label and aria-describedby accessibility properties, "ctl_dgrd_color_input" and "ctl_dgrd_color_input_desc" respectively. In addition, end users should be able to navigate the color picker from the keyboard without the picker losing the focus.

Number Columns

Data grid columns with type Number have a the property $columnzeroshownempty which specifies that values of zero are shown empty rather than displaying a 0 digit.

Hiding a column

The $columnhidden property allows you to hide the specified column at runtime. The default is false, meaning the column is visible.

Example

The Webshop sample app, available under the Applets section in the Hub, uses a data grid to display a list of products that have been ordered in the main product jsShop remote form. The data grid control is called ‘orderGrid’ and is seen here in design mode:

The $dataname of the data grid is set to iOrderList which is defined from a table class T_qOrders which is linked to a query class qOrders. When the product form is opened, the $construct method behind the data grid defines the list from the table class.

# $construct behind the data grid
Do iOrderList.$definefromsqlclass($tables.T_qOrders)

When the end user clicks the ‘Order Now’ button in the product window, the data for the selected product and size/type is passed to the process_order method (as value 1, 2, or 3), which inserts the data into the list (after a check to see if the user has already ordered the same product) and the list is redrawn. The process_order method is as follows:

# process_order class method in the jsShop form
# contains pButtonNumber parameter (Short Int) to receive the value of the product button clicked
If iProductList.product_price_[pButtonNumber]>0 ## price must be greater zero
  Do iOrderList.$search(
    $ref.order_product_id=iProductList.product_id
    &$ref.order_size=iProductList.product_size_[pButtonNumber],
    kTrue,kFalse,kFalse,kFalse)
  If iOrderList.$line ## found one so increment existing order
    Calculate iOrderList.order_amount as iOrderList.order_amount+1
  Else ## new one so add to iOrderList
    Do iOrderList.$add#NULL,#D,iProductList.product_id,iProductList.product_name,
      iProductList.product_size_[pButtonNumber],
    1,0,iProductList.product_price_[pButtonNumber])
    Do iOrderList.$line.$assign(iOrderList.$linecount())
  End If
  Calculate iOrderList.to al_price as
    iProductList.product_price_[pButtonNumber]
    *iOrderList.order_amount
  Do $cinst.$objs.checkOutBtn.$enabled.$assign(
    iOrderList.$linecount()>0)
    Do $cinst.$objs.orderGrid.$redraw()
Else
  Do $cinst.$clientcommand('yesnomessage',row(con('Would you like     to order >',iProductList.product_size_1,'< instead?'),'Not     available','$orderYes'))
End If

The Apps Gallery on the Omnis website has a further example showing how you can use the Data grid component.

Date Picker Control

The Date Picker control allows the end user to select a date and/or time by clicking on the up or down arrows for each part of the date or time; from Studio 10.0.1 a date range can be selected, see below. You can assign a Date/Time instance variable to the $dataname property to load the date/time selected by the user, or you can assign a two column instance row variable to contain the date/time and time zone offset of the client in the respective columns (see below for info on the time zone offset).

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can use the Date picker to allow the end user to select a date; in addition, the Holidays example app under the Applets option in the Hub uses the Date picker, which is described later in this section.

The $datestyle property specifies the style or date/time content of the date picker control, which can be a combination of date & time, date only, time only, or a calendar view, as specified by a constant:

Constant Description
kJSDatePickerStyleDate a date display only
kJSDatePickerStyleDateTime a date and time are displayed (right below)
kJSDatePickerStyleTime a time display only
kJSDatePickerStyleCalendar a calendar is displayed (left)
kJSDatePickerStyleCustomr a custom format, see below

The color of the Date Picker is specified with $datefacecolor while $datefacealpha sets the transparency (value 0-255).

Calendar Style Picker

The Date Picker control can be switched to display a calendar style date picker, by setting $datestyle to kJSDatePickerStyleCalendar. There are a number of properties that apply to the control when the date style is set to calendar.

Picker style on mobile devices

When $datestyle is set to kJSDatePickerStyleCalendar desktop browsers will display the calendar as expected. However on mobile devices, even when $datestyle is set to kJSDatePickerStyleCalendar, a calendar will be replaced with a date picker (same as kJSDatePickerStyleDate), since a picker style date selector is the preferred style on mobile devices. This can be overridden by setting the property $datestyleusepickeronmobile to kFalse.

Custom Date Style

The $datestylecustom property can be used in conjunction with setting $datestyle to kJSDatePickerStyleCustom to set the style or format of the date shown. You can enter a string of characters to represent the columns required as per the Omnis date/time format strings, for example, "mdy" to specify Month, Day, Year columns in that order.

In addition, you can specify a grouped column by enclosing the date characters in parenthesis, for example, "(wdm)" will specify a single coumn containing Weekday, Day, Month. Note: this column will always alter the day by one by increasing or decreasing it, so it only makes sense to use this type of column if it includes a day or weekday. Time elements entered into a grouped column will be ignored. Repeated characters are ignored and only one group can be used (further groups are ignored). Groups take precedence over individual columns, therefore "d(wdm)y" will be treated as "(wdm)y".

Date pickers (other than custom) pick up the locale of the client and display the picker in their standard format. For example, the date picker will display Day, Month, Year in the UK, and Month, Day, Year in the USA (assuming their location settings are set correctly).

Selecting a Date Range

When specified, the properties $rangeselection and $rangeenddataname allow the end user to select a date range, that is, a start date and an end date. The first being a boolean to put the calendar into range selection mode. When true, the end user can select a range of dates by selecting one date after another. The $rangeenddataname property is the name of an instance variable to store the end of the data range and should be of type Date. The variable in $dataname will always hold the start date in range selection mode.

A boolean parameter, pInRangeSelection, will be passed as true with evDateClick when the end user has selected the first date, and false once they have selected the second. If $rangeselection is kFalse, this parameter is not passed, and therefore will return NULL if tested on evDateClick.

The evDateRangeChange fires every time a date range selection has been completed (and $rangeselection is kTrue). This passes two parameters: pStartDate and pEndDate. This means you can obtain a date range without using instance variables if you just need to react to the date range selected. evDateChange does not fire when $rangeselection is kTrue.

The $currdaycolor property applies to inside the current day indicator ring and not the whole cell. This ensures the type of cell is still understood by the end user. E.g. When $todayscolor is different to $daycolor, the end user can still see that it is today, even when they have selected it as the current day.

Events

The following events are generated when the end user clicks on a date picker and/or selects a date: you can create an event handling method on the control allowing you to load the selected date.

  1. evDateChange
    Sent to the control when the current date is changed (not fired when $rangeselection is kTrue)

  2. evDateClick
    Sent to the control when the user clicks on a date; only applicable to Calendar type date pickers.

  3. evDateDClick
    Sent to the control when the end user double clicks on a date (not fired when $rangeselection is kTrue)

  4. evDateRangeChange
    Sent to the control when a date range has changed (only fired when $rangeselection is kTrue)

Example

In the Holidays sample app uses the Date picker control set to kJSDatePickerStyleCalendar to allow users to select the dates for the holiday applications. The jsUserForm in the Holidays app has two buttons to allow the end user to select a “From” date or “To” date to specify the Begin and End dates for their holiday request. The “From” button has the following code:

On evClick
  Calculate iUsingCalendar as kTrue
  Calculate iSelectFrom as kTrue ## this is the From button
  Do method openCalendar

The openCalendar class method moves the calendarPane into view on the main form and has the following code:

Do method enableFields (kFalse## enables the calendar pane & disables the name pane
Do $cinst.$objs.calendarPane.$top.$assign(90)
Do $cinst.$objs.calendarPane.$left.$assign(150)
Do $cinst.$objs.calendarPane.$visible.$assign(kTrue)

If you examine the Holidays app to look at the Date picker note that it is on a page pane field called calendarPane located on the jsUserForm. The $left property for the calendarPane is set to 990, to hide it from view, therefore you’ll need to select it using the Field List (right-click the remote form, select Field List and check the calendarPane) and set its $left property to 200 in the Property Manager in order to see it.

The $dataname of the Date picker control itself is set to iCalendarDate, an instance variable of type Date Time and subtype ‘D m y’; when the end user selects a date this variable is set to the selected date automatically.

The Date picker has a simple event method to detect when the end user double-clicks on a date cell; it has the following code:

On evDateDClick
  Do method closeCalendar

The closeCalendar class method passes the date from iCalendarDate into either the iFromDate or iToDate variable defined in the form; it has the following code:

If iSelectFrom ## if the From button
  Calculate iFromDate as iCalendarDate
Else ## it must be the To button
  Calculate iToDate as iCalendarDate
End If
Do $cinst.$objs.calendarPane.$left.$assign(1250)
Do method enableFields (kTrue)

The final two lines of the method move the calendarPane off to the right and enables the fields on the Name pane.

Time Zone Offset

You can return the time zone offset of a date value when it is passed back from the client by using a two column row variable in $dataname; the first column should be defined as a Date Time variable and the second of type Number. If the server passes a new value to the client, then only the first column is significant and should specify the new date to be sent to the client.

When evDateChange signals that there has been a change on the client then the updated date is passed back to the server in the first column of the row variable as a UTC/GMT date value and the time zone offset of that value in the client's current time zone is passed back in the second column. The time zone offset is the number of minutes from UTC/GMT, e.g. GMT+2 the time zone offset is 120. This can be used to calculate the date in the time zone of the client.

If time zone offset information is not required, $dataname can be specified as a Date Time instance variable only.

Date Picker Localization

The following strings are available in the JS localization string table to allow you to localize strings for the Date Picker. Note that some of the strings are now arrays of strings to simplify localization (e.g. for months, days of the week, etc).

Date picker specific strings

The following are specific to the date picker control:

"ctrl_date_increase": "Increase"
"ctrl_date_decrease": "Decrease,
"ctrl_date_time_button": "Open time picker"
"ctrl_date_calendar_button": "Open date picker"
"ctrl_date_header": ["Select a Month", "Select a Year", "Select a Decade", "Select a Time"]

Generic strings

The following strings are available for controls that refer to dates, including the date picker:

"month_names": ["January", "February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"]
"month_names_short": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"]
"day_names": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday"]
"day_names_short": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
"date_units": ["Day", "Month", "Year", "Decade"]
"time_units": ["Hour", "Minute", "Second", "Millisecond"]

The following example applies Spanish text to the Calendar:

<script type="text/javascript">
jOmnisStrings.es = {
"month_names": ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
"month_names_short": ["enero", "feb.", "marzo", "abr.", "mayo", "jun.", "jul.", "agosto", "sept.", "oct.", "nov.", "dic."],
"day_names": ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
"day_names_short": ["DOM", "LUN", "MAR", "MIÉ", "JUE", "VIE", "SÁB"],
"date_units": ["Día", "Mes", "Año", "Década"],
"time_units": ["Horas", "Minutos", "Segundos"],
"ctrl_date_header": ["Selecciona un mes", "Seleccione un año", "Seleccione un década", "Seleccione una hora"]
};
</script>

See the Localization chapter in the Creaing Web & Mobile Apps manual for more information about setting the strings in the jOmnisStrings object.

Device Control

The Device Control allows access to mobile device features such as getting the location of the end user’s device using GPS, retrieving the contacts information from the device, or returning images from either the camera or photo library on the device. Depending on the type of application you are creating, some or all of these features may be useful to enhance the interactivity and functionality of your app for end users when they run your app on a mobile device, such as a smartphone or tablet computer.

The Device control itself is invisible and to enable access to the device functionality you need to add the Device Control to your remote form and assign an action to the $action property of the control at runtime using methods.

Running the Device Control and Compatibility

Important Note: in all but a few specific cases, the actions enabled via the Device Control only work in an application that is running within one of the JavaScript Wrappers or Omnis App Manager on a mobile device. Therefore, you will need to compile your app into a wrapper, and test it in a simulator or directly on a mobile device by running the native app, for the majority of the actions in the Device control to work; or test it in the App Manager. The only exceptions to this are the Email, Call, and SMS actions which will attempt to work if the app is running in a standard web browser: see those actions later in this section.

The Device control supports a number of hardware functions, some of which may not be available on particular devices. You should test your app thoroughly on the specific devices you wish to support with each of the device functions that you want end users to access.

For some of the hardware features, Omnis can detect if they are not present on the current mobile device running the app. For example, if a device does not have a hardware camera then the action kJSDeviceActionTakePhoto will report an evPhotoFailed message.

Properties

Note the Device control is invisible, therefore some of the visual properties normally associated with JavaScript components may not be relevant, such as $alpha.

Property Description
$action The “action” for the Device control which specifies which function on the client mobile device is accessed; this is assigned as a kJSDevice… constant: see below
$communicationaddress

Character value determining the phone number when the Make Call and Send SMS device actions are used, or email address when the Send Email device action is used.

Can only be assigned at runtime.

$communicationdata

Character data to be sent as the message body when the Send SMS or Send Email device actions are used.

Can only be assigned at runtime.

$communicationsubject

Character data to be sent as the subject when the Send Email device action is used.

Can only be assigned at runtime.

$dataname The name of a List instance variable for the Device control. It will be populated with contact details when using the Get Contacts device action.
$deviceimage Contains a Character/Binary instance variable name used for holding the image returned from the device. The image will be in base64 format.
$imagejpeglevel The JPEG quality of images returned (0-100). 100 being max quality, 0 being max compression.
$imagemegapixel A float value indicating the maximum Megapixel resolution of images returned. 0 means no limit.
$imagesizemenu If true, a dialog will be opened when using the device image actions, to allow the user to pick a size for the image, respecting $imagemegapixel.
$soundname Name of the sound sample to be played when the Beep device action is called.
$contact… The $contact… properties determine whether particular pieces of contact information are returned when using the Get Contacts device action, e.g. disabling $contactphotos can significantly reduce the time taken to fetch contacts.

Contact properties

There are a number of properties that are only relevant when the device action is set to kJSDeviceActionGetContacts which allows you to obtain information from the contacts database on the device. By setting these properties you can control what information is returned from the Contacts data on the device. For example, if $contactname is set to kTrue the contact request will include name info, and so on.

Setting the Action Property

The following list summarizes the actions available and the constant needed for the $action property:

  1. kJSDeviceActionBeep – Beep Device
    forces the device to play the default beep

  2. kJSDeviceActionGetBarcode – Get a Barcode or QR code
    returns the output from Barcode/QR-code scanning function on the device (if available); the output is usually a string which can be a URL

  3. kJSDeviceActionGetContacts – Get contact info
    returns contact information from the device; note there are other properties to determine the content or extent of the contact information returned

  4. kJSDeviceActionGetGps – Get the device location
    returns the location data using the GPS function on the device

  5. kJSDeviceActionGetImage – Get an Image
    returns an image from the device’s image gallery

  6. kJSDeviceActionTakePhoto – Take a Photo
    forces the device to take a photo (if a camera is available)

  7. kJSDeviceActionVibrate – Vibrate the Device
    forces the device to vibrate (if available)

  8. kJSDeviceActionMakeCall – Make a Phone Call
    forces the device to make a phone call (if available)

  9. kJSDeviceActionSendEmail | kJSDeviceActionSendSms – Send an Email or SMS
    forces the device to send an Email or SMS / text message (if available)

The basic method to assign an action to the Device control is as follows:

Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceAction…)
# where oDevice is the name of the Device control

Events

Event Description
evBarcodeFailed

Sent when no Barcode could be obtained from the device.
Parameters

pEventCode The event code
evBarcodeReturned

Sent to the device control when a Barcode is ready for processing.
Parameters

pDeviceBarcode The Barcode data
pEventCode The event code
evContactsFailed

Sent when no contacts could be obtained from the device.
Parameters

pEventCode The event code
evContactsReturned

Sent to the device control when contacts info is ready for processing.
Parameters

pEventCode The event code
evGpsReturned

Sent to the device control when Location Data is ready for processing.
Parameters

pDeviceGps The GPS location
pEventCode The event code
evImageFailed

Sent when the device failed to return an image.
Parameters

pEventCode The event code
evImageReturned

Sent to the device control when an image is ready for processing.
Parameters

pEventCode The event code
evPhotoFailed

Sent when the device failed to take a photo.
Parameters

pEventCode The event code
evPhotoReturned

Sent when an image is returned from camera ready for processing.
Parameters

pEventCode The event code
Standard evExecuteContextMenu evOpenContextMenu

Beep Device Action

To make the device play a given sound sample, you need to assign the constant kJSDeviceActionBeep to the $action property. This is one-way communication with the device which will result in the device playing a sound sample. To specify which sound to play, you need to set the $soundname property to the name of the sound sample to be played which must be compiled into the wrapper application. The wrapper contains a default sound called “notify”.

Example
On evClick
  Calculate $cinst.$objs.oDevice.$soundname as "notify"
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionBeep)

Get Barcode Device Action

You can return a Barcode or QR code by assigning the constant kJSDeviceActionGetBarcode to the $action property. If the action is successful an evBarcodeReturned event is sent to the Device Control and the barcode data is returned in the pDeviceBarcode event parameter; the barcode data is usually a string containing Alphanumeric characters, such as a product number or name, or in the case of a QR code it could be a website URL.

Example
# event method for “Scan” button
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionGetBarcode)

The event method for the Device Control could be:

On evBarcodeReturned
  Do iProducts.$search(iProducts.iProdQrCode=pDeviceBarcode,kTrue,kFalse,kFalse,kFalse)
  If iProducts.$line=0
    Do iProducts.$line.$assign(iProducts.$linecount## other
  End If
  Do iProducts.$loadcols()
  Calculate iAmount as 1
  If iProdName='Other'
    Calculate iProdName as pDeviceBarcode ## show the value of the barcode
  End If

Vibrate Device Action

To make the device vibrate you need to assign the constant kJSDeviceActionVibrate to the $action property. This is one way communication with the device which will result in the device vibrating for a short period of time.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionVibrate)

Get GPS Device Action

To receive location (GPS) data from the device you need to assign the constant kJSDeviceActionGetGps to the $action property. The evGpsReturned event is sent when the location data has successfully been returned. The event parameter pDeviceGps will contain the returned data which is formatted as a string containing longitude and latitude data separated by a colon “:”. If the device fails to obtain location data or the device does not support location tracking, the returned data will be a longitude and latitude of zero, i.e. “0.0:0.0”.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionGetGps)
On evGpsReturned
  Calculate $cinst.$objs.oMap.$latlong as pDeviceGps

Take Photo / Get Image Device Action

To take a photo with the device (if a camera is present) or to return an image from the device’s gallery the kJSDeviceActionTakePhoto or kJSDeviceActionGetImage constants need to be assigned to the $action property. The $deviceimage property of the Device component needs to be assigned to an Instance Variable of type Binary or Character to hold the incoming image data from the device. If the device is successful in returning an image, the event evPhotoReturned or evImageReturned will be called to indicate that an image was returned, whereupon the instance variable specified in $deviceimage will be populated with the base64 encoded image data. In the event of the device failing to return an image or the user cancels the request, the event evPhotoFailed or evImageFailed will be sent.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionTakePhoto)

In this case the instance variable iImage is a Binary variable. The $deviceimage property is set to iImage. There is another Binary variable called ipic which is associated to a picture component. By copying the returned image in iImage into the picture component variable you can display the image returned from the device.

On evPhotoReturned
  Calculate iPic as iImage

Get Contacts Device Action

To obtain information from the contacts database on the device the kJSDeviceActionGetContacts constant must be assigned to the $action property. To accommodate the contact database the $dataname property needs to be assigned to an Instance Variable of type List. The properties starting with $contact... determine which contact fields will be obtained from the device: setting these properties to true or false will determine if that specific field is returned from the device.

The evContactsReturned event is triggered when the contact database has been returned, and in the case of the device failing to obtain the contact database the evContactsFailed event is triggered.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(
      kJSDeviceActionGetContacts)
# retrieve info from the Contact list
On evContactsReturned
  Set reference lNameRow to iDeviceList.nam.1
  Calculate iNameRow.FirstName as lNameRow.givenName
  Calculate iNameRow.MiddleName as lNameRow.mid
  Calculate iNameRow.Surname as lNameRow.familyName
  Calculate iNameRow.Prefix as lNameRow.honorificPrefix
  Calculate iNameRow.Suffix as lNameRow.honorificSuffix
  Calculate iNameRow.Nickname as iDeviceList.nickName

Contacts data structure

  1. displayName: The name of this Contact, suitable for display to end-users (String).

  2. name: A row containing all components of a contact’s name.
    formatted: The complete name of the contact (String).
    familyName: The contact’s family name (String).
    givenName: The contact’s given/first name (String).
    middleName: The contact’s middle name (String).
    honorificPrefix: The contact’s prefix (example Mr. or Dr.) (String).
    honorificSuffix: The contact’s suffix (example Esq.) (String).

  3. nickname: A casual name to address the contact by (String).

  4. phoneNumbers: A list of all the contact's phone numbers.
    type: A string that tells you what type of phone number this is
    (example: 'home') (String).
    value: The phone number (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  5. emails: A list of all the contact's email addresses.
    type: A string that tells you what type of email this is (example: 'home') (String).
    value: The email address (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  6. addresses: A list of all the contact's addresses.
    pref: Set to true if this is the user's preferred value (Boolean).
    type: A string that tells you what type of address this is (example: 'home') (String).
    formatted: The full address formatted for display (String).
    streetAddress: The full street address (String).
    locality: The city or locality (String).
    region: The state or region (String).
    postalCode: The zip code or postal code (String).
    country: The country name (String).

  7. ims: A list of all the contact's IM addresses.
    type: A string that tells you what type of IM this is (example: 'home') (String).
    value: The IM username (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  8. organizations: A list of all the contact's organizations.
    pref: Set to true if this is the user's preferred value (Boolean).
    type: A string that tells you what type of organization this is
    (example: ‘work’) (String).
    name: The name of the organization (String).
    department: The department the contact works for (String).
    title: The contacts title at the organization (String).

  9. birthday: The birthday of the contact (Character).

  10. note: A note about the contact (String).

  11. photos: A list of the contact's photos. In general, there will be only one row.
    type: A string that tells you what type of field this is (example: 'home') (String).
    value: The photo data, encoded as base64. These are small, thumbnail photos.
    (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  12. categories: A list of all the contacts user defined categories.
    type: A string that tells you what type of category this is
    (example: 'home') (String).
    value: The value of the field (such as a phone number or email address) (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  13. urls: A list of web pages associated with the contact.
    type: A string that tells you what type of web page this is
    (example: 'home') (String).
    value: The website URL (String).
    pref: Set to true if this is the user's preferred value (Boolean).

Make a Call Device Action

To make a phone call from the device the kJSDeviceActionMakeCall constant is used. Before assigning this action the phone number for the call should be specified in the $communicationaddress property.

Example
Do $cinst.$objs.oDevice.$communicationaddress.$assign("0123456789")
Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionMakeCall)

Send an SMS or Email Device Action

To send an SMS (text message) or Email from the device the kJSDeviceActionSendSMS or kJSDeviceActionSendEmail constant is used. Before assigning this action the phone number (for the SMS) or the Email address should be specified in the $communicationaddress property. The message body of the SMS or email can be specified in $communicationdata. The subject of the email can be specified in $communicationsubject.

Example
Do $cinst.$objs.oDevice.$communicationaddress.$assign("0123456789")
Do $cinst.$objs.oDevice.$communicationdata.$assign("A message")
Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionSendSMS)

Running Device Actions in the Browser

Some of the Device actions (those listed below) may work in your application when running in a normal web browser, that is, outside a wrapper. However, the results of running any of these actions in a web browser are very unpredictable, mainly due to the great variation among different web browsers and operating systems, therefore we do not recommend or support apps using these actions in a web browser. If you do use them however, you should test these actions thoroughly.

Call, SMS, and Email actions

You can use the Call, SMS, and Email actions in an application running in a browser, and not in a wrapper, and the web browser on the client will attempt to execute the relevant action (this only applies to these actions: all other actions have to be executed inside the wrapper). For example, if you run the Email action in a web browser it will attempt to initiate an email in the email program on the client.

Vibrate and Location actions

When run outside the wrapper the Vibrate action is not currently supported on iOS Safari, and hence other iOS browsers, as they all have to based on Apple's WebKit.

The Location action only works over HTTPS in recent browsers.

Droplist Control

The Droplist control displays a dropdown list from which the end user can make a selection; the contents of the list can be supplied from a default list or a list variable which can be built dynamically. There is an example app in the Samples section in the Hub in the Studio Browser.

You can specify a default list of options in the $defaulttext property, which is a comma-separated list of options; $defaultline is the default line (set to 1) which is selected when the form is opened (only when $defaulttext is used). Alternatively, you can assign the name of a list instance variable to $dataname to populate the list; $listcolumn specifies which column of the list variable is used to display the list. The $::listheight property specifies the height of the droplist.

When a line in the droplist is selected an evClick is generated with the selected list line reported in pLineNumber.

Horizontal Padding

The Droplist and Combo Box controls have the property $horzpadding to allow you to add extra horizontal padding, in pixels, to the text in the list part of the control. This property has also been added to Combo boxes.

Selected Value

The $seldataname property allows you to specify the name of an instance variable, which will be populated automatically with the selected value from the droplist.

Example

The jsUserForm in the Holidays sample app uses a droplist to allow users to select an employee to view their holiday leave requests. The $dataname of the empList Droplist control is set to iEmployeeList which is built via the $construct method when the form is opened.

# buildEmpList class method in the jsUserForm
Do iEmployeeList.$definefromsqlclass('sEmployee'## the schema
Do iEmployeeList.$sessionobject.$assign(iSQLObjRef)
Do iEmployeeList.$select()
Do iEmployeeList.$fetch(kFetchAll)
Do iEmployeeList.$cols.$add(iEmpFullName)
Calculate lTotal as iEmployeeList.$linecount
For lNum from 1 to iEmployeeList.$linecount step 1
  Calculate iEmpFullName as con(
    iEmployeeList.[lNum].FirstName,kSp,
    iEmployeeList.[lNum].LastName)
  Do iEmployeeList.[lNum].$assigncols(,,,,,iEmpFullName)
End For
Do iEmployeeList.$line.$assign(1)
Calculate iName as iEmployeeList.iEmpFullName

The droplist control contains a $event method which is triggered when the user selects a line in the list; the code in the event method redraws the holiday list for the selected employee:

On evClick
 Do method buildHolidayList
 Calculate iName as iEmployeeList.[pLineNumber].iEmpFullName
 Do $cinst.$objs.pagePane.$objs.holidayList.$redraw()
 Do $cinst.$objs.pagePane.$objs.empName.$redraw()

The buildHolidayList class method builds the list of holiday requests for the selected employee and redraws the form.

Edit Control

The JavaScript Edit control is a standard single line edit field which you can use to display data or allow the end user to enter data into, such as in a Contact form; in this case you would normally add a label to each edit or entry field on the form, or you can add a ‘content tip’ ($::contenttip) to each edit control to help the end user.

The Edit control can handle all types of character or numeric data stored in the instance variable specified in $dataname: the type of data the edit control can handle will depend on the data type of the variable assigned to the control. When kTrue (the default), $issingleline makes the edit control only allow data entry on a single line, otherwise when kFalse the field can be extended downward to allow data entry on multiple lines. When kTrue, the $ispassword property ensures a place-holder character is displayed when the end user enters something in the field (only applies when $issingleline is kTrue).

Text or Font Style

The style of the text or font of an Edit control is controlled by the $fieldstyle property under the Appearance tab in the Property Manager. The field styles are set up in the #STYLES system table in the library and are available for many control types. You can set the $fieldstyle to <None> and assign your own font and style properties under the Text tab, including the $align, $font, $fontsize, $fontstyle, and $textcolor properties.

Linked Lists

The $linkedobject property allows you to link a list control to the edit control to create a special type of list called a “Linked List” which updates itself automatically as the user types into the edit control: see the List Control section for more information.

Events

The Edit Control reports the evBefore and evAfter events, so you can detect when the focus is about to enter or leave a field in the $event method and process the event accordingly: note evAfter is only reported if the data in the control has changed. You must enable any of the events for the Edit control in its $events property before any of the events are reported.

In addition, the evKeyPress event is reported allowing you, amongst other things, to create a “Linked List”: see the List Control section for more information about linked lists.

Borders

The $effect property lets you set the type of border for the edit control and its value is one of the kJSborder… constants. The kJSborderDefault setting means the control has the default border type as specified by the current client operating system and browser type. For some clients the border may change when the state of the control changes.

The $borderradius property lets you add rounded corners to the edit control. It can be set to up to four-pixel values separated by -, in the order topleft, topright, bottomright, bottomleft. If bottomleft is omitted, the topright value is used. If bottomright is omitted, the topleft value is used. If topright is omitted, the topleft value is used.

Soft Keypad Input Type

Many iOS and Android devices have different software keypad layouts which are displayed depending on the type of data required, that is, the keypad content and layout adapts to the content required. For example, if numeric content is required, a numeric keypad is displayed. The $inputtype property allows you to specify which keypad is displayed on touch devices depending on what type of content you wish the end user to enter into the edit control. This property only applies to touch devices and in this case $inputtypetouchonly is set to kTrue by default, and it only applies if $ispassword is false (if true the default keypad is shown).

  1. $inputtypetouchonly
    When true (the default for touch devices) the specified $inputtype is applied on touch devices, otherwise it is ignored

  2. $inputtype
    The HTML input type used by the edit field. The browser may give this special handling, e.g. by popping up a specific software keypad. (The property is ignored if $ispassword is enabled.) The input type is specified using a constant:
    kJSInputTypeDefault: the standard Qwerty keypad (in most cases)
    kJSInputTypeNumber: the standard Qwerty keypad flipped to numbers
    kJSInputTypeTelephone: the telephone number keypad
    kJSInputTypeEmail: the Qwerty keypad plus the @ and dot keys
    kJSInputTypeUrl: the Qwerty keypad plus dot, forward-slash, and ‘.com’ keys

Content Tips

The Edit control has the $::contenttip property which is a text string which is displayed in the edit field when it is empty and before the end user has entered any text. Using content tips may help the user understand what content should be entered into fields in the forms in your application. For example, for a Last name field you could enter ‘Enter your last name’ into $::contenttip to prompt the end user for their last name. As soon as the end user starts to type something into the field the content tip will disappear.

Selecting Dates

The constant kJSInputTypeDate can be assigned to the $inputtype property to allow the end user to select a date using the Date Picker. When $inputtype is set to kJSInputTypeDate, and $inputtypetouchonly is set to false, a date/time picker will be used to pick the value for the Edit control. $dataname must be set when using kJSInputTypeDate and other input types such as kJSInputTypeNumber.

The format of the date picker should be calculated from $dateformat ($dateformatcustom if $dateformat == kJSFormatCustom). If $dateformat is kJSFormatNone, then the control attempts to fall back to the dataname subtype.

Custom Date Formats

You can specify multiple date formats in the $dateformatcustom property for entry fields in a remote form, which allows end users to input a date using one of a number of possible formats, rather than being limited to a single date format. The multiple date formats can be entered into $dateformatcustom separated using “|” (the pipe character), for example:

D/M/y|D m y|d-m-y|D/M/Y|D/m/y|D-M-y|D M y

When parsing data entered by the user, the client uses each format in order, until one successfully matches the user input. The client uses the first format in the list to format the data for display.

Numeric Data Entry Validation

Entry fields (and data grids) validate numeric data as it is entered, for JavaScript remote form variables with a numeric data type. When the end user tries to enter invalid data into the field, such as an alphabetic character, the data is rejected, i.e. it cannot be entered into the field, and the field is highlighted momentarily to indicate an error (the default action is to show a red border).

When leaving the entry field, the value is normalized: so for integer data it is constrained to the valid range or for other numbers it is rounded to the correct number of decimal places; also, leading zeroes are removed, and so on.

Negative Numbers and Uppercase

The $negallowed property for Edit controls allows for the display of negative number values. If this is kFalse and the end user tries to enter a negative sign, the sign will be rejected. When set to kTrue, the $uppercase property forces uppercase for character data.

Horizontal Padding

The property $horzpadding allows you to add extra horizontal padding, in pixels, inside the control; when applied this property adds padding on the left and right of the text within the edit control.

Multiline Edit Scrolling

Text wrapping for the Multiline Edit field is prevented if the $horzscroll property is enabled (kTrue). However, if $autoscroll is true, then text wrapping does occur (since $autoscroll is on by default).

Shortcut Keys

There are a number of shortcut keys defined in the Edit control that allow end users to select text and move the insertion point within the control (the shortcuts also apply to Window class Entry fields).

The shortcut keys are stored in the Omnis preference $keys which can be edited in the Property Manager (click on the Prefs option in the top level of the Studio Browser). The shortcut keys for Edit controls are stored in a configuration file called ‘keys.json’ and located in the Studio folder (this is the same file containing the shortcut keys for the Method Editor). The file is created the first time you edit the shortcuts in the Property Manager and click OK.

Shortcut key Action
Alt+End End of Text Alternative
Alt+Home Start of Text Alternative
Ctrl+Alt+DownArrow Scroll Down
Ctrl+Alt+LeftArrow Scroll Left
Ctrl+Alt+RightArrow Scroll Right
Ctrl+Alt+UpArrow Scroll Up
Ctrl+DownArrow Paragraph Down
Ctrl+End End of Text
Ctrl+Home Start of Text
Ctrl+LeftArrow Backwards Word
Ctrl+RightArrow Forwards Word
Ctrl+UpArrow Paragraph Up
End End of Line
Home Start of Line
PageDown Page Down
PageUp Page Up

Auto Correction, Capitalization, Completion

You can control the Automatic Correction, Capitalization And Completion of text entered by the end user into an edit control. This functionality is built into the browser whereby text is ‘corrected’ or updated automatically: note that not all browsers support all of these functions, so you should check support in individual browsers on different platforms.

You should note that Auto correction, Auto capitalization and Auto completion (the properties $autocorrect, $autocapitalize & $autocomplete) only work in Omnis when they are enabled on the client Mac computer. Note also that $autocapitalize only applies when using a virtual keyboard on a device.

Auto Correction

If true, the $autocorrect property specifies that text entered into a JavaScript Edit control is auto-corrected, as the end user types into the field. Currently this feature is only implemented in Safari and iOS browsers (note some browsers, such as Chrome, will highlight incorrectly spelled words, but not correct them automatically). This property defaults to kTrue for backwards compatibility.

Auto Capitalization

The $autocapitalize property controls whether or not text typed into an edit field is capitalized, as appropriate, automatically. Possible values include:

  1. kJSAutoCapitalizeSentences
    Automatically capitalise the first character of new sentences (default and previous behaviour)

  2. kJSAutoCapitalizeWords
    Automatically capitalise the first character of each word

  3. kJSAutoCapitalizeNone
    No automatic capitalization

Auto Completion

The $autocomplete property controls whether or not text is completed automatically. If true, the browser will attempt to complete text based on content previously entered into this type of field (e.g. name type fields will display a list of names based on the first letter typed): the browser will display a list of suggested text for the end user to select from. There may be many possible values for some types of field, which will be based on values previously entered into any website for a field with the same 'autocomplete' value, e.g. 'email'.

Content Selection

The $setselection method allows you to select a range of characters within the Edit control.

  1. $setselection(iFirstSel[,iLastsel]))
    Sets the focus on and selection range of the content in the Edit control. If iLastSel is omitted selection will occur to the end of the edit field. Returns the selected text.

$setselection has two parameters, both Integer, iFirstSel and iLastSel to set position of the characters to be selected within the edit control. iLastSel selects up to, but not including, the character specified, and if omitted the content in the edit field is selected to the end. The method returns the content selected.

Dictation Text Entry

You can enter text into an edit field using the built-in Dictation feature on macOS, which tries to convert audible speech into meaningful text. To allow dictation to occur the focus must be in the edit field, which must itself be editable, i.e. not disabled, and dictation must be enabled on the client computer. Dictation is available in Single- and Multi-line edit fields, the edit part of Combo boxes, and edit fields in Complex grids in remote forms (and window classes), that is, wherever text input is required.

Enabling Dictation

Support for Dictation is turned on in Omnis by default, but you can change it in the config.json file. There is a “useDictation" option in a new “macOS" member in config.json, which is set to true to enable dictation; note you have to quit Omnis to change the config.json file, and any change will be effective when you restart Omnis.


"macOS": {
        "useDictation": true
    }

Using Dictation in Edit fields

To enter dictation mode, place the cursor in the edit field and select the Start Dictation option from the Edit menu on macOS, or press the Function (Fn) key twice. This will open the dictation popup (usually in the center of the screen, depending on space) and put the computer in listening mode. Dictation can be stopped or cancelled by clicking on Done in the popup, or using the Stop Dictation menu option.

Dictation Levels

There are two levels of dictation provided by macOS: Standard or Enhanced. These can be enabled from System Preferences->Keyboard->Dictation, or on older systems System Preferences->Dictation & Speech.

Standard dictation (the default) requires an internet connection and provides speech to text translation using Apple’s servers. On older systems, the text is not translated until the Done button is pressed on the popup. On newer systems text is translated and placed into the field while the end user is speaking. Dictation will end automatically when text is entered from the keyboard or the field loses the focus.

Enhanced dictation requires the enhanced dictation engine to be downloaded, which is approximately 500MB for each language pack. This will then provide local machine based translation. Features of enhanced dictation are live feedback and offline support. With live feedback the text is rewritten while speaking. Enhanced dictation also provides spoken dictation commands such as “Select All”, “Cut that”, “Move left”, and so on. When enhanced dictation has been started it is possible to change the currently focused edit field and move the popup to the new field and continue to dictate. It is also possible to type and dictate at the same time.

Tooltips and Carriage Return

Text in tooltips will wrap if it contains a carriage return character or other wrapping characters when the text width of the tip would exceed a third of the screen width. In previous versions, tooltips only used CR to line wrap when the width of the tip was greater than half the screen width.

In addition, the CR character is no longer displayed. However, any other control characters (characters less than space, or the character 0x7f) are displayed using the Unicode control character page.

This change also applies to tooltips for window class controls.

File Control

The File Control allows end users to upload or download files inside a remote form: from Studio 10 the control allows multiple files to be uploaded. The control itself is invisible and to enable the upload or download functions, you need to assign an action at runtime, to the $action property. The Upload and Download actions are represented by the constants kJSFileActionUpload and kJSFileActionDownload. There is an example app in the Samples section in the Hub in the Studio Browser showing how you can upload and download files; in addition, the Contacts example app uses the file control, which is described below.

When in Upload mode the File control opens a standard Upload dialog to allow the end user to select a local file to upload. There are various properties to allow you to change the text and error messages on the Upload dialog.

For downloads, the File control can provide a standard hyperlink pointing to the file to be downloaded, or you can assign a row variable to the $dataname of the control containing the binary data of the file to download, or a list for multiple file downloads. The download function is supported for mobile devices, and if the browser can interpret the contents of the file it is shown in a new browser window or tab.

Using Timer and File controls

Note that if a Timer control is present on the page, timer events will not occur while a file upload dialog is open, or while file download is in progress.

Mobile limitations or issues

Support for the Upload or Download function on mobile devices depends very much on the device itself and the mobile operating system. Therefore, if you intend to include an upload or download function in your app, you should test your app thoroughly on all devices you wish to support. With this in mind, we are aware of the following limitations or issues regarding different mobile operating systems.

Upload does not work on iOS because the input element to select a file does not become enabled since iOS does not support it. Download works via the hyperlink because mobile Safari has been implemented to support hyperlinks. However, the other download mechanism does not work: on iOS for example, the download actually transfers the data to the client, but then the browser does not carry out any action with the data, so the downloaded file is lost.

Uploading Files

To enable the upload function, you must set the $dataname property of the File component to a two-column row variable: Column1 should be of type List, and column2 should be of type Character ($dataname should be set before the upload action if triggered). The value assigned to column2 should be the name of a task variable of Binary type which will receive the binary data when the upload is complete. Column1 will receive MIME header list information when the upload is complete.

To trigger the upload dialog, you need to assign kJSFileActionUpload to the $action property. This action opens a file upload dialog which has two formats: one for up to date browsers, and the other for browsers which do not support XMLHttpRequest2, i.e. Internet Explorer and Opera. When a file has uploaded an evFileUploaded event is generated and the List and Binary task variable assigned to $dataname are populated. When the dialog closes the control generates evFileUploadDialogClosed.

The $maxfileuploadsize specifies the maximum size in bytes of a file to be uploaded to the server. Zero means no limit. Some clients (IE and Opera) cannot enforce this limit. See example below for details on how to upload a file.

While the Upload dialog is open, you can close it by assigning kJSFileActionCloseUpload to the $action property (note this does not generate evFileUploadDialogClosed).

On the upload dialog the file name is displayed above the progress bar, to the left, the percentage is shown above to the right, and file upload size information shown below as before. File sizes displayed to the user are in shown in the appropriate unit so when 1000 bytes is exceeded it changes to kB, 1000 kB changes to MB and 1000 MB changes to GB.

Upload File Type

The $uploadtypes property allows you to filter the file types that can be uploaded. The property accepts a comma-separated list of file extensions or MIME types, for example, the string '.png, .jpg, .jpeg' would allow PNG or JPG files, or 'image/*' to allow any image files.

Uploading Multiple Files

The File control allows multiple files to be selected for uploading by setting $allowmultiple to kTrue. It is not supported by some browsers, just like $maxfileuploadsize (IE9 and below, Opera).

The properties $maxbatchuploadsize and $maxbatchuploadsizeerrortext work similarly to $maxfileuploadsize to impose a limit of the total amount of data to be uploaded. This works independently of $maxfileuploadsize so you can impose a limit on single or multiple file uploads. In addition, $uploadedprogresstextbatch has been added to show the progress of the batch of files, and works similarly to $uploadprogresstext.

Error messages shown when file sizes are exceeded, for single or batches of files, give the user feedback on what the size limits are and lists the offending files exceeding the limit.

Multiple file upload dialogs display the same information for each single file, while another progress bar shows progress through the batch of files, including how many files have uploaded out of the total.

Localization

All the text and labels in the File control can be translated via the jOmnisStrings object in the JavaScript client. See the main Localization section for more info.

Downloading Files

URL downloads

In its simplest form, the File control can provide a hyperlink to allow the user to download a file located on the internet. In this case, you would set the $visible property of the control set to kTrue, set $hyperlinkurl to the URL of the file, and $hyperlinktext to the text for the hyperlink. The URL does not have to be a file download URL, it can be any file on the internet and will open in a new browser window or tab. The File control will display the download as a standard hyperlink on the remote form.

Single File downloads

You can also use the File control to download a file from a binary file or one stored in your database. To enable this functionality, you need to assign kJSFileActionDownload to the $action property. To download a single file, the $dataname property of the File control is set to a row variable, with Column1 as the file name, Column2 the media type (e.g. text/plain;charset=utf8), Column3 the name of a remote task variable which should be a binary containing the file data or character containing a file path, and Column4 is an 'Identifier' column (Character type) containing a name for the file.

Multiple File downloads

You can specify a list in $dataname, instead of a row, to provide a list of files to be downloaded. The definition of this list is identical to the row, with each line on the line representing each file to be downloaded. The fourth 'Identifier' column can contain a unique name for each file.

evDownloadSent Event

The File control has an event, evDownloadSent, which indicates if the download was successful, and identifies the file that was downloaded. The event receives two parameters:

  1. pSuccess
    Whether or not the download was successsfully sent.

  2. pIdentifier
    The value of the Identifier column (the fourth column, if provided) in the download list/row which was assigned to $dataname to initiate the download which has now been sent.

The evDownloadSent event will be triggered when the server has sent all of the data for a file to the client. Note that Omnis sends the data in a single chunk, so the client may still be processing the data at this point. However, at the point that the event is fired, the server has sent all of the data, and the task variable containing the binary data (or file path) can now be re-used.

Example

A File control is used in the jsContacts form in the Contacts sample app to allow end users to upload a photo of their contacts. The File control is placed somewhere on the form, its $dataname is set to iFileRow, an instance row variable, and the evFileUploaded and evFileUploadDialogClosed events are enabled in the $events property of the control. The iFileRow variable is setup in the $construct method of the form, as follows:

Do iFileRow.$define(MimeList,"Binary Variable")
Calculate iFileRow.C2 as "tData"

MimeList is a local list variable, and tData is a task variable of type Binary – it’s important to note that the second column of iFileRow is of type Character, and is set to the Name of the binary task variable. Elsewhere on the form is a picture control to display the photo, its $dataname is iPicture, and a button to allow the end user to select an image file and initiate the upload process. The code for the button is:

On evClick
  Do $cinst.$objs.fileControl.$action.$assign(kJSFileActionUpload)

This assigns the kJSFileActionUpload action to the fileControl object which opens the Browse/Upload dialog. The File control has an $event method which detects when a file has been uploaded and the upload dialog has been closed:

On evFileUploaded
  Calculate iPicture as tData
# transfer the pic data to iPicture
On evFileUploadDialogClosed
  Do method setPicBtnTitle (kHavePic) ## changes the button text

When an image is selected by the end user and the file is uploaded the image data is loaded into the tData task variable, as defined in the second column of the iFileRow row variable, which is then transferred to the iPicture variable assigned to the picture field on the form. The Save button saves the contact record including the image file uploaded by the user.

HTML Object

The HTML Object lets you display an HTML page or fragment in a remote form. The $html property contains the HTML content for the control. The HTML content for the control must start with an element declaration such as <div...> or <style>. The $ctrlname is the name of the control. The $wraptext property is set to true by default meaning that the content in the control will wrap (set it to kFalse to stop wrapping). This property sets white-space for the control to 'normal' if true, and 'no-wrap' if false.

There is an example app 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.

There are also two examples in the Samples section in the Hub to display a Twitter button and a Twitter Timeline that use the HTML component to embed the necessary HTML into a remote form.

The following HTML is used to create the initial Twitter button:

<div><a href="https://twitter.com/intent/tweet?screen_name=omnisstudio&text=I love Omnis" class="twitter-mention-button" data-size="large">Tweet to @omnisstudio</a></div>

Building an HTML block

You can use the Sta: command to build up the HTML content. The following method constructs some HTML and assigns it to $html of an HTML control called HTML.

# lHTML is a local var of Character type
Begin statement
# ===== Styles =====
Sta: <style>
Sta: p {color: #00F; margin: 0 2em; padding: 1em; background-color: #fff; border: #DDD solid 2px;}
Sta: h1, h2 { color: #666; margin-left: 0.5em;}
Sta: img {margin: 5px 0 5px 50px;}
Sta: </style
# ===== Content =====
Sta: <div>
Sta: <h1>HTML Control</h1>
Sta: <p>
Sta: You can display HTML in the HTML con.<br />
Sta: This is the Second line of con.<br /><br />
Sta: <i>And you can do italic etc!</i>
Sta: </p>
Sta: <h2>Pictures</h2>
Sta: <p>You can embed pictures.</p>
Sta: <img src="/images/cat.jpg" width="200" height="176" alt="cat" />
Sta: </div>
End statement
Get statement lHTML
# the html form object is called HTML
Calculate $cinst.$objs.HTML.$html as lHTML

You can embed any of the standard HTML tags into the $html property, including links, styles, and tables. The following text could be added to an HTML control which is placed next to a check box control on a remote form to allow end users to popup a window containing competition rules that are stored in a static html page:

<p>I have read and agree to the <a href="rules.html" target="_blank">competition rules</a></p>

Events

The HTML Control reports the evBefore and evAfter events, as well as evClick and evDoubleClick.

Style and Attribute Placeholders

You can inherit the effects and font attributes that you set for the HTML object in the Property Manager in design mode by inserting various placeholders in the $html property. The placeholders take the format %<letter>, for example, insert %f to inherit the font specified in $font, or %t to inherit the text color set in $textcolor. Most of the placeholders should be inserted into an html element using the style tag, while others are attributes and can be inserted directly into an HTML element.

Placeholder Type Description Property or desc
%b attribute back color and alpha $backcolor and $alpha
%f style font $font
%z style font size $fontsize
%s style font style $fontstyle
%j style font align $align
%t style text color $textcolor
%e attribute effect $effect
%p style position coordinates of omnisobject
%v style vert scroll $vertscroll must be kTrue
%h style horz scroll $horzscroll must be kTrue

For example, you can set $html to <div %e></div> and the text in the control will take on the effect from $effect (or $linestyle or $bordercolor, as these are effect properties).

To use the font specified in the HTML object in a paragraph in your HTML insert: <div><p style="%f">SOME TEXT</p></div>. For example, the following HTML produces some text rendered in plain or default HTML paragraph style and second paragraph of text that uses the font setting specified in $font in the HTML object, which in this case is set to “Verdana,Arial,Helvetica,Sans-serif”:

<div><p>PLAIN TEXT</p><p style="%f”>STYLED TEXT</p></div>

HTML object in Paged Panes and Subforms

If the HTML object appears in a Paged Pane or Subform (that is, inside any container field), you will need to add the “white-space:normal” parameter to the <div> tag containing your Html to allow the text to wrap correctly inside the object. For example, the following <div> tag will contain text etc within a 300px width:

<div style="width:300px; white-space:normal">
# your HTML
</div>

The Hyperlink Control allows you to present a list of options to the end user, where each option in the list is displayed as a web-style hyperlink; each link option corresponds to a line in the underlying list variable used to populate the list. If the whole list does not fit inside the control, the list will “pop up” when the end user passes the mouse over the control. The $extraspace property specifies extra spacing between links. The Hyperlink control is used in the Studio Browser and is very similar to the JavaScript version of the control.

The options or list contents in the Hyperlink control are based on the contents of a list variable specified in $dataname. The first column in the list should be the text displayed for each option listed in the control, unless $listcolumn is specified which is the column of the list variable used to populate the control. Subsequent columns in the list can be used to specify other values.

When the end user clicks on the list an evClick is triggered with the selected line reported in pLineNumber. You can use the value of pLineNumber in your event method to trigger an action. You can create an empty line by putting ”-“ (hyphen) in the first column.

If $isvertical is kTrue the list pops up vertically, and if $shouldunderline is kTrue the links are underlined. The $selectedtextcolor property specifies the color of the text when the mouse is over it.

Example

There is an example library showing how you can build a dynamic hierarchical list using the Hyperlink control in the Samples section in the Hub in the Studio Browser; in addition, the same app is in the JS Component gallery on the Omnis website at: www.omnis.net

The following method is the $event() method for the Hyperlink control:

# Do iHyperLinks.$define(iHyperName,iHyperGrp,iHyperCmd)
On evClick
 Do iHyperLinks.$line.$assign(pLineNumber)
 Do iHyperLinks.$loadcols()
 If iHyperGrp=0
 Else
 If iHyperCmd=99
 Else
 End If
 End If

Label Object

The Label object lets you add standard text labels to your remote form. The text for the label is entered into the $text property in the Property Manager, or you can double-click on the text for the label to edit it. Alternatively, you can assign some text to the $text property in your code.

The font and alignment of the label is setup under the Text tab in the Property Manager. You can use the style() function to style parts of the text assigned to $text, for example:

Calculate $cinst.$objs.label1.$text as con('Mellow ',style(kEscColor,kYellow),"Yellow")

Styled text is only supported if $textishtml is false. When set to true, the $textishtml property means the text in $text is interpreted as HTML, so in this case you can use any HTML tags and styling to format the text. For example:

Calculate $cinst.$objs.labelhtml1.$text as 'This is <span style="color:#ff0000;">RED</span>'

Labels have the $dataname property which means you can assign the text from a variable. In this case, the value in $dataname overrides the value in the $text property, and actually sets $text. You can assign a Date variable to $dataname, in which case the label takes its display format from #FDT, #FD, or #FT depending on whether the variable has a date/time component.

List Control

The standard List control allows you to display a single column list on your remote form allowing end users to select a particular line.

For lists with many columns, you may prefer to use a Data Grid control, or for a more compact single-column list you can use a Droplist control. If you want to include an icon next to the text in each list line you can use a Tree list by including your data and icon references at the top-level of the list data without using any child data. For a further alternative to the standard List box you can use the Native List to display list data.

If $ischecklist is kTrue in the standard List control each list line has a checkbox which allows the end user to select or de-select the line.

There are a number of example apps showing different types of list control in the Samples section in the Hub in the Studio Browser; in addition, the same apps are available in the JS Component gallery on the Omnis website at: www.omnis.net.

List data variable

The contents of a standard List is taken from the instance variable (of List type) specified in the $dataname of the control. In this case, the first column of the list contents is used to populate the list control; you can specify an alternative column for the data in $listcolumn. You can build the list via the $construct method of the remote form so it is available to all instances; the list can be built from your database or from a number of static values.

The example app in the Hub uses a simple check list ($ischecklist = kTrue) and a standard List control; the check list is built in the $construct method of the form:

Do iCheckList.$define(iCheckListValue## defines the list
Do iCheckList.$add('Milk'## add the values
Do iCheckList.$add('Tea')
Do iCheckList.$add('Coffee')
Do iCheckList.$add('Sugar')
Do iCheckList.$sort(iCheckListValue## sorts the list
# in addition you can select a line if required
Do iListvar.$line.$assign(1) ## selects the first line

The example app provides a button to merge the selected lines in the check list into the other list. The code behind the button is:

On evClick
 Do iList.$merge(iCheckList,kFalse,kTrue,kTrue)
 # merges the selected lines only

See the ‘Programming Lists’ chapter in the Omnis Programming manual for more information about using list variables in your code.

Selected Line Color

You can control the color for selected lines by setting $selectedlinecolor; use kColorDefault for the default selected line color for the client OS. The $evenrowcolor property sets the background color of even numbered rows displayed in the list; kColorDefault means use the same color as the odd numbered rows ($backcolor).

List Events

When the user selects a line the evClick event is reported with the pLineNumber parameter reporting the selected line number. You can also set the evDoubleClick event for a list control to detect when the end user double clicks on a list line. List events will retuen the pLineNumber parameter containing the number of the line clicked, and you can use this in your event method behind the list to trigger an action.

A double-click event is sent to a List control if the Enter or Space key is pressed while the focus is in the List and if evDoubleClick is enabled on the list. Otherwise, if the control has an evClick event enabled, Enter/Space sends an evClick. If the control does not have the evClick or evDoubleClick enabled, then Enter triggers the okkeyobject (if there is one), as long as the state of the list has not changed, i.e. the current line has not changed, and no checkbox has been toggled.

Lists and Client Methods

Searching Lists

You need to prefix the column name with $ref for a search to work in a client method. For example:

Do iList.$search($ref.iCol="ABC")

Smart Lists and the JavaScript Client

The JavaScript Client does not support smart lists in client executed methods, insofar as if you change the list in some way on the client, it will no longer be a smart list when the updated data is sent from the client back to the server. Smart lists work as expected in server executed methods.

List Scrolling

Data Grids have $vscroll and $hscroll properties which allow you to scroll a list vertically or horizontally at runtime in the client browser; note these properties are write-only meaning that you cannot return their values at runtime. The vertical or horizontal scroll value assigned using $vscroll or $hscroll is the pixel offset for a list.

Changing Current Line from the Keyboard

When set to true, the $keyboardchangesline property means that navigating the list with the keyboard also sets the current line, so when the list is not in a multiple select state, there is not a separate focused line. The evClick event is fired when the current line changes. This property is available in standard Lists, Native lists, Tree lists, and Data grids.

When set to false, navigating the list with the keyboard always uses a focus line and the user has to manually select a current line with the Space or Enter key, at which point evClick is fired.

Linked Lists

You can link a List control to an Edit control to create a “Linked List”, so that when the end user types into the edit field the contents of the list is updated dynamically. There is an example app in the Samples section in the Hub in the Studio Browser to show the use of a Linked list; in addition, the same app is in the JS Component gallery on the Omnis website at: www.omnis.net

The combination of an Edit control with key presses enabled and a List control allow you to create a dynamic list that has the ability to update in response to what the end user types into the edit box. A Linked List is in effect like a Combo box, but with the extra ability to update itself as the user types. To enable this feature, edit controls can detect certain key presses and can be linked to a list control, while for lists themselves there is a property to display selected lines only.

Creating Linked Lists

The Edit Control has the $linkedobject property which is the name of a list control on the current remote form used to display suggestions to the user if the Edit control enables the evKeyPress event. You need to add the code to populate the list in response to evKeyPress, based on the current value of the instance variable specified for the Edit control.

When the end user types into the Edit control, the linked list will appear automatically. It is not necessary to process any events for the list control, since the dynamic list behavior is determined automatically by being linked in this way. Therefore, you would expect the following to happen when end users are using a dynamic linked list:

  1. Clicking on a line in the open list will set the edit control to the value of the clicked line.

  2. Pressing up or down arrow when the focus is on the list control will set the value of the edit control to the new current line of the list.

  3. Pressing the down or up arrow when the edit control has the focus and when the list is not visible will open the list, set the edit control value to the selected line in the list, and move focus to the list.

  4. Typing into the edit control when the list is closed will open the list and keep focus on the edit control.

  5. All the following will close the list: pressing return when the list has focus; pressing escape, or clicking away from the list or the edit control.

Optimizing the Linked List

The list property $selectedlinesonly specifies that only the selected lines in a list will be displayed (this only applies when $ischecklist is false), which in the context of Linked lists allows you to filter the content of a list that is linked to an Edit control. You should optimize the $event method for the edit control in the following way:

  1. Make the $event method for the Edit control execute on the client.

  2. On evKeyPress, if the list of suggestions is empty (or no longer suitable for the data), call a server method to build the list (with lines selected based on the value of the edit control).

  3. In subsequent evKeyPress events that can use the pre-built list, perform a list $search to change the selected lines to the ones which are suitable for the new value of the edit control.

In this way, the list of suggestions is cached on the client, and updates simply by changing the selected lines with a search in your code.

When $selectedlinesonly is true, the processing involving the usual click events and so on all use the line number of the data in the list, not the lines displayed in the list.

Note that if you use the $evenrowcolor property when $selectedlinesonly is true, the even row color applies to the numbers obtained by counting the displayed lines, rather than using the line numbers of the data in the list.

Detecting Key Presses

Edit controls have an event called evKeyPress; the Key press detection was added to support Linked Lists, but it could be used by itself for other purposes. The evKeyPress event has a single event parameter, pKeyList, which is a three column list containing the keys entered since the last evKeyPress event (or since typing started) with a row for each key in the order the keys were pressed.

Each key in the list is either a data character or one of a limited set of system keys (note that not all keyboard keys are supported, such as function keys are not supported). Transitions in shift state, ctrl state, and so on, do not result in a key in the list, so if the user types Shift+a, the character in the list will be A. The supported system keys are:

  1. Backspace

  2. Tab

  3. Escape

  4. Insert and Delete

  5. Up, Down, Left, and Right arrow key

  6. Page Up and Page Down

  7. Home and End

  8. Return

The columns in the list are as follows:

  1. Colum 1: If the key is a system key, column 1 is the keyboard constant value representing the key, such as kEscape. Otherwise column 1 is #NULL.

  2. Colum 2: If the key is a data key, column 2 is the character data for the key. Otherwise column 1 is #NULL.

  3. Colum 3: Is the sum of the following keyboard modifier constants, representing the state of these modifiers at the point the key was added to the list: kJSModShift, kJSModCtrl, kJSModAltOrOption, kJSModCmd.

In addition, there are some properties which control when evKeyPress events are generated. The Omnis preference $keyeventdelay is the minimum number of milliseconds (0-2000) between evKeyPress events. The first evKeyPress will also be delayed for this duration. This allows you to throttle keyboard events in the case where they will be executed on the server, and therefore reduce the load on the server. If true, the preference $systemkeys specifies that evKeyPress events include system keys which do not change the value of the data. If false, only system keys such as backspace are included as they potentially change the data.

While the user is typing, the edit control in the user interface remains enabled (unlike normal event processing where the entire user interface is usually disabled). The value of the instance variable associated with the edit control reflects the current content of the entry field when evKeyPress is generated.

The following method is the $event() method for the Edit field linked to a list of names (from the example app in the Hub):

On evKeyPress
 Calculate iKeyList as pKeyList
 Do iLinkedList.$search(mid(low(iLinkedListCol),1,len(iEditVar))=low(iEditVar))

List Pager

The $pagesize property allows you to display the lines in a list or data grid as separate pages, to improve the user experience when navigating lists or grids with a large number of lines; the default value is zero which means no list pager is displayed. The $pagesize property is available for the JS List, Data Grid, Complex Grid, and Native List (when not using grouped lists). There is an example app showing the List pager for all these list types in the Samples section in the Hub in the Studio Browser.

When assigned an integer value, the $pagesize property forces the contents of the list or grid to be sub-divided into a number of scrollable pages, and a set of page number buttons (as well as forward and back buttons) are displayed under the list or grid box, which allows the end user to “page through” each group of lines in the list or grid.

The value assigned to $pagesize specifies the number of list lines displayed in each page, and therefore the total number of lines in the list, divided by the value of $pagesize determines the number of pages in the list or grid field, as well as the number of buttons displayed in the pager panel. The $pagerpage property allows you to set the page to be displayed, with the first page as the default.

Note that setting $pagesize does not reduce the amount of data sent to or fetched from the server – the full list data is sent to the client, and the setting of $pagesize is only used for displaying the list or grid with the pager element.

Changing the Pager’s Appearance

The appearance of the pager, such as the color of the buttons, numbers, and arrows, cannot be controlled using standard component properties. However, if you wish to customize the appearance of the pager, you can do so by overriding the associated CSS classes. These classes are named ‘omnis.pager<-xxx>’ and are listed in the omnis.css file. Do not edit the classes in omnis.css, rather you should override the classes by adding your own version in the user.css file found in the html\css folder in your Omnis development tree.

Map Control

The Map Control allows you to place a Google Map® on your remote form; this provides many of the functions available in a Google map and as provided by their API. There is an example app in the Samples section in the Hub in the Studio Browser showing the full capability of the Map control; in addition, the same app is in the JS Component gallery on the Omnis website at: www.omnis.net

Registration and API Key

In order to use the Map control, you need to register with Google to obtain a map API key, which can be entered in the $apikey property of the control; the Map control will not work without the API key. Specifically, you need to obtain a Google “Maps JavaScript API” key (previously called a Browser API key). In addition, if you want to use the Geocode function you need to obtain a separate “Geocoding API” key.

Important Note: By signing up to Google Maps and using the maps in your deployed Omnis application, you and your end users must agree to the general “Terms of Use” for Google Maps: there is a link to these Terms of use on the map displayed in the Map control. Omnis cannot be held responsible for any third-party products or services and will not be liable for any damage or loss resulting from your use of the Google Maps content or the products.

Apart from the $apikey property, there is no further configuration needed to display a basic Google map in your remote form, however, to make the map really useful you will probably want to display specific locations, add markers on the map, or allow end user interaction with the map: all of these are possible with the JS Map control and are described below.

Map Location and Zoom Level

The $latlong property allows you to specify the center location of the map as “latitude:longitude”, for example, a value of 40.749305:-73.985775 will center the map on New York. If you do not set $latlong initially (by setting the property in the Property Manager in design mode or in the $construct method of the form), the map will open at some unspecified location, usually the default location setup in Google on the client device.

The $::zoom property lets you set the zoom level of the map: the range is 0 to 21, with zero showing the largest area (the whole world) and 21 the smallest possible area. The default zoom level is 8 which shows a reasonable amount of detail for the current center location of the map.

Finding the Latitude:Longitude

The Map component supports Google Geocoding which allows you to convert a street address into a geographic coordinate like latitude and longitude, which you can use to place a marker on a map, or center the map.

To use the Geocoding function you need to access the Geocoding API which itself requires a separate API Key, in addition to the Maps API key, which you can obtain from Google.

A Search button has been added to the JS Map example available in the Hub to show how you can convert a street address to a latitude:longitude coordinate which can be applied to the $latlong map property. Note the example app places the Geocoding API key in the $userinfo property which is then sent to Google.

Alternatively, you can find the latitude:longitude coordinate manually. To do this, Right-click somewhere on a standard browser-based Google map (not the Omnis map control), select the ‘What’s here’ option and the latitude:longitude value of that position is shown on the popup. You need to replace the comma with a colon to be used as a parameter in Omnis, e.g. 52.223460:1.492379.

Map Type and Controls

The $maptype property lets you set the type of map – this can be set to a constant: kJSMapTypeRoad (default), kJSMapTypeSatellite, kJSMapTypeHybrid, and kJSMapTypeTerrain. The end user can change the map type using the map type control shown on the map, assuming the $maptypecontrol property is enabled.

The other standard map controls, including the pan control, scale control, and the street view control are enabled using the properties $pancontrol, $scalecontrol, and $streetviewcontrol, respectively (these are all enabled by default): note you can only change these properties at runtime if the map control itself is enabled ($enable = kTrue).

The zoom control can be further controlled by setting the $zoomcontrol property: it can be set to kJSMapZoomOff, kJSMapZoomDefault (the default), kJSMapZoomSmall, and kJSMapZoomLarge. The latter two settings correspond to a simple Plus|Minus button (Small) or the same button with a vertical slider control (Large) for finer adjustment of the map zoom level.

Map Markers

You can place a marker or set of markers on the map by assigning a row or list containing marker information to the $mapmarkers property. For each marker you must define the latitude and longitude of the marker location in the first column of the setup list in the format latitude:longitude (e.g. “40.749305:-73.985775”), and in subsequent columns you can specify the marker title (shown when you hover over the marker), the tag or title for the popup (shown when you click on the marker), and html content for the popup. An optional fifth parameter can specify an icon for the marker to replace the default map marker (see below). If the third and fourth columns are empty for any marker defined in the list, the marker will not popup when clicked. (See the Events section about how to add markers via user clicks.)

The following code adds markers to a map indicating the Empire State Building and Central Park in New York, it then centers the map on the Empire State Building, and sets a zoom level of 12 which shows a reasonable level of detail in this case:

# create vars map_markers (List), marker_latlong, marker_title, marker_tag, marker_html (Chars)
Do map_markers.$define(
marker_latlong,marker_title,marker_tag,marker_html)
Do map_markers.$add(
"40.749305:-73.985775","Empire State Building","Empire State Building","<div id='content'><h3 id='firstHeading'>Empire State Building</h3><div id='bodyContent'><p><b><img src='http://nyc-architecture.com/MID/esb1.jpg'></b></p></div></div>")
Do map_markers.$add(
"40.766225:-73.972514","Central Park","NY Central Park","<div id='content'><h3 id='firstHeading'>Central Park</h3><div id='bodyContent'><p><b>Central Park Info</b></p></div></div>")
Do $cinst.$objs.map.$mapmarkers.$assign("map_markers")
Do $cinst.$objs.map.$latlong.$assign("40.749305:-73.985775")
Do $cinst.$objs.map.$::zoom.$assign(12)

Map Marker Icons

The marker list assigned to $mapmarkers can have an optional fifth column which you can use to specify the icon URL for an image for the map marker. An empty string in this column (or a missing column altogether) means that the marker will use the default marker icon. The value for the marker icon is an icon URL which you set using the iconurl() function. Since the marker image has to be set for each row in your list you can specify a different image for each marker in the marker list, but if you want the same image for each map marker you still have to set the marker image for every row in your marker list.

Custom Markers

You can assign an alternative marker icon or symbol, including map markers from the Google maps API, by adding a sixth column to the marker list: in this case the fifth column should be omitted.

The definition for the markers list in the JavaScript Map control can be:

Do iMapMarkers.$define(
iMarkerLatLong,iMarkerTitle,iMarkerTag,iMarkerHtml,iMarkerIcon,iMarkerCustom)

where iMarkerCustom is a new string column (column 6) specifying a custom marker. When a marker is defined in the marker list, and the iMarkerIcon (column 5) is empty, iMarkerCustom can be included with the following attributes, separated with a ‘|’ character (you only need to specify the attributes required). An example custom string would be:

"path:google.maps.SymbolPath.BACKWARD_CLOSED_ARROW | fillColor: red | fillOpacity:0.8 | scale: 4 | strokeColor:black | strokeWeight: 1"

Or to draw a five-pointed star marker:

"path:M 125,5 155,90 245,90 175,145 200,230 125,180 50,230 75,145 5,90 95,90 z | fillColor: red | fillOpacity:0.8 |  scale: 0.1|strokeColor:black | strokeWeight: 1 | anchor:122,115"

Or to draw a circle marker:

"path:google.maps.SymbolPath.CIRCLE | fillColor: red | fillOpacity:0.8 | scale: 4"

Where the custom marker parameters are defined as:

  1. path can either be a map symbol, or an SVG notation path, as defined below

  2. fillColor the color used to fill the marker object, an html css color name or value e.g. #FF0000

  3. fillOpacity the opacity of the fill color, a value from 0 to 1, e.g. 0.5 is 50% transparent fill

  4. scale a scaling factor for the object

  5. strokeColor the color used to outline the object, an html css color name or value e.g. #FF0000

  6. strokeWeight the thickness of the stroke line

  7. anchor allows you to set the anchor position or offset the shape. By default, shapes are aligned to the top left of the marker relative to its lat:long

Marker Symbol – prefixed google.maps.SymbolPath. Description
CIRCLE A circle.
BACKWARD_CLOSED_ARROW A backward-pointing arrow that is closed on all sides.
FORWARD_CLOSED_ARROW A forward-pointing arrow that is closed on all sides.
BACKWARD_OPEN_ARROW A backward-pointing arrow that is open on one side.
FORWARD_OPEN_ARROW A forward-pointing arrow that is open on one side.

For example:

Do iMapMarkers.$define(
iMarkerLatLong,iMarkerTitle,iMarkerTag,iMarkerHtml, ,iMarkerCustom)
Do iMapMarkers.$add(
"52.223460:1.492379","Omnis UK","Omnis UK","","","path:google.maps.SymbolPath.BACKWARD_CLOSED_ARROW|fillColor: red|fillOpacity:0.8| scale: 8|strokeColor:black|strokeWeight: 1")
# the JS Map app uses similar code to show the Omnis offices

The JS Map example app has been updated and includes some of the new markers and polygons, and can viewed or downloaded via the Omnis website (www.omnis.net) from the JavaScript Component Gallery. The following image shows the location of the European Omnis offices using the “Backward-pointing Closed Arrow”.

The map control has a property $fitmaptomarkers that can be assigned value 1 at runtime to force the map to zoom in or out to allow all the map markers to be shown.

Polygon Objects

In addition to icons and standard map markers, you can add polygon objects or irregular shapes to maps in the JavaScript Map control. The $mappolys property specifes the data name of a list which contains the definition of each polygon or shape as follows:

Do iPolyMarkers.$define(
iPolyLatLong,iPolyStroke,iPolyOpacity,iPolyWeight,iPolyFill,iPolyFillOpacity,iPolyTag)
  1. iPolyLatLong the latitude:longitude values for each of the the points of the polygon, so a triangle would have 3 points: the lat:long settings are separated with the ‘|’ character, e.g. 25.774,-80.190|18.466,-66.118|32.321,-64.757|25.774,-80.190

  2. iPolyStroke the color used to outline the polygon, which is an html css color name or value e.g. #FF0000

  3. iPolyOpacity the opacity of the stroke color, a value from 0 to 1, e.g. 0.5 is 50% transparent

  4. iPolyWeight the thickness of the stroke line

  5. iPolyFill the fill color of the polygon object, an html css color name or value e.g. #FF0000

  6. iPolyFillOpacity the opacity of the fill color, a value from 0 to 1, e.g. 0.5 is 50% transparent

  7. iPolyTag the tag name or label for the polygon, which is sent to the evPolygonClicked event method in pPoly

For example, the following code draws the Bermuda Triangle on the map (see the JS Map example app):

Do iPolyMarkers.$add(
"25.774,-80.190|18.466,-66.118|32.321,-64.757|25.774,-80.190","#FF0000","0.8","3","#FF0000","0.35","Bermuda Triangle")

The evPolygonClicked event with the parameter pPoly is called when a polygon on the map is clicked, and pPoly will be set to the polygon tag as defined in the list.

Events

There are various events available in the map control to allow you to detect when and where the map was clicked (evMapClicked, reports latitude and longitude of the click), when the map is dragged by the end user (evMapMoved, reports the latitude and longitude of the new center location), when the map is zoomed using the zoom control (evMapZoomed), or when a map marker is clicked (evMarkerClicked). None of these events are enabled by default, so you have to enable them in the $events property for the control using the Property Manager.

The following $event method could be placed behind a map control to detect when the map is clicked, or when a marker is clicked (assuming a marker has been added), or if the map is moved or zoomed. The add_markers Boolean variable is linked to a checkbox on the window to allow the end user to enable or disable the ability to add markers. When the map is clicked, the evMapClicked event reports the position in pLatlong, and a marker definition is added to the map_markers list. The message variable is assigned to a field on the form to show either the new center of the map, the new zoom level, or which marker has been clicked.

# $event method for map control
# define vars map_markers (List), marker_latlong, marker_title, marker_tag, marker_html, message (Chars), add_markers (Bool), marker_no (Long int = 0)
On evMapClicked
  If add_markers ## linked to checkbox on window
    Calculate marker_no as marker_no+1
    Do map_markers.$define(
    marker_latlong,marker_title,marker_tag,marker_html)
    Do map_markers.$add(
      pLatlong,con("Marker ",marker_no),
      con("Marker ",marker_no),con("This is marker ",marker_no))
    Do $cinst.$objs.map.$mapmarkers.$assign("map_markers")
  End If
  Calculate message as con(
    pick(add_markers,"Map clicked here: ",
    "Marker added here: "),pLatlong)
On evMapMoved
  Calculate message as con("Center is now: ",pNewCenter)
On evMapZoomed
  Calculate message as con("New zoom level: ",pNewZoom)
On evMarkerClicked
  Calculate message as con("Marker clicked: ",pMarker)

Native List

The Native List control appears in the ‘JavaScript Native Components’group in the Component Store, and it provides a list control that looks familiar on different platforms. You can customize the accessories in the list by adding your own HTML content and CSS styling, and therefore provide a very rich UI in a single list format.

In keeping with this philosophy, the JS Native List exposes many appearance properties to allow you to customize the list how you wish. If you leave any of the values as kColorDefault, they will revert to the platform-specific default.

The native list has been designed along the same lines as the iTableView component of iOS forms. The list can either be a standard flat list or a grouped list, using nested lists.

To increase efficiency, the list only draws the displayed rows, along with several more in a buffer zone around them, at any one time. This provides smooth scrolling, and means that the size of the list has very little impact on performance. As a side-effect of this, when scrolling quickly, you will see that the rows may not be rendered immediately.

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can customize the accessories in a native list; the same app is in the JS Component gallery on the Omnis website at: www.omnis.net.

Defining the $dataname list

The structure of the List instance variable used for the $dataname of the native List control differs based on how you wish the list to display.

The Data tab in the Property Manager allows you to assign column numbers for each row part, i.e. $text1col allows you to specify which column in your list contains the the data to display as the main text of the row. If you do not wish to make use of a particular row part, leave its column set to 0.

You need to define and populate your list in accordance with the column numbers you have set in the Data tab of the Property Manager. The content of these columns should be as follows:

  1. text1col: This should be Character data, to display as the main text for the row.

  2. text2col: This should be Character data, to display as the secondary text for the row.

  3. imagecol: This should be Character data - a URL to an image to display.
    The image will be scaled to fit the size of the row’s image (customized using $imageheight & $imagewidth).
    The URL can make use of Omnis’ support for pixel-density-aware image selection by passing the URL in the format: “<URL to 1x image>;<Name of 1.5x image>;<Name of 2x image>” (where all 3 images are in the same location). This means that on a Retina device it will use the 2x image, but on a standard display device it will use the 1x image. As the image is scaled anyway, you could just always use the 2x image, but this method reduces unnecessary bandwidth usage and processing of larger images

  4. accessorytypecol: This should be a kJSNativeListAccessoryType… integer value. It determines the type of accessory to display on the right edge of the row.
    Use a value of 0 for no accessory. A kJSNativeListAccessoryTypeNone constant will be added in the future.

  5. accessoryvaluecol: Contains the current value of the row’s accessory.
    This is currently only used by the Checklist accessory, to represent the checkbox’s state

  6. accessorycontentcol: This should be Character data, and should describe the content for some accesssory types. The Accessory types which make use of this are:
    Button: For rows with a button accessory, the content should be the text for the button.
    Custom: For rows with a custom accessory, this should be HTML to describe the contents of your custom accessory.
    CustomWithEvent: see below.

Custom Accessories

You can add your own custom row accessories by setting the accessorycontentcol list column to kJSNativeListAccessoryTypeCustom or kJSNativeListAccessoryTypeCustomWithEvent.

kJSNativeListAccessoryTypeCustomWithEvent works in the same way as kJSNativeListAccessoryTypeCustom but will trigger a different click event when you click on the accessory (evClick will be called with pWhat equal to kJSNativeListPartAccessory instead of kJSNativeListPartRow).

When accessorycontentcol is set to a custom accessory, its value should be the HTML content of your custom accessory, encapsulated within a single parent element.

You can set your accessory to a particular size (rather than fill the available space in the row) by providing width & height values in the style tag of your top-level HTML element.

If a size is defined in this way, the native list control will attempt to center the accessory. If this does not work, you may also need to set "position: absolute;" in your style tag. For example:

'<div style="position: absolute; width: 50px; height:25px; background-color: #FF0000;" />'

Creating a Grouped list

If you wish your Native List control to display its data as a Grouped list, you need to change the structure of the list assigned to $dataname. The main list should comprise two columns:

  1. Column 1: Should be defined as being of type “List”, and each row should contain a list structured as defined above (adhering to the columns specified in the Datatab of the property inspector). All of the rows defined in this sub-list become part of a single group.

  2. Column 2: A Character column, defining the name of the group.

Properties

The Native List component has many properties to allow you to customize its appearance. Most of these are self-explanatory and/or are described by their Property Manager tooltips. The following may need futher explanation:

  1. $rowdisplaystyle: Determines how the row is displayed. Value should be a kJSNativeListDisplayXXX constant. Current values allow you to change between displaying the two text fields in a vertical or horizontal fashion.

Advanced Customization

If you wish to alter the default appearance for a particular platform, or wish to change something which is not exposed as a property, you would need to do so using CSS. This is only recommended if you have experience of customizing CSS.

The classes used (when defaulting to platform-specific appearances) are defined in native_list.css.

Rather than altering these classes here, it is recommended that you extend them in your user.css file, to prevent you needing to make these changes each time you update Omnis.

As always, when editing the CSS used by Omnis’ controls, there is the possibility that you may change how a control appears or behaves (especially if you alter sizes), so you do so at your own risk.

Native Slider

The Native Slider control appears in the ‘JavaScript Native Components’group in the Component Store, and it works, for the most part, in the same way as the standard JavaScript Slider component but has a more familiar appearance when running on different platforms. There is an example app in the Samples section in the Hub in the Studio Browser.

The current value of the slider is reported in the property $val according to where the slider is positioned. You can specify the range for the slider in the $::min and $::max properties. The $usessteps property is a Boolean determining whether or not the slider should snap to discrete step values specified in $step.

The Slider reports three events: evStartSlider (when the control is starting to track), evEndSlider (when the control has finished tracking), and evNewValue (when the value has changed). You can detect these events in the $event method for the component. These events all pass the current value of the Slider in the pSliderValue parameter. As the user drags the Slider thumb the evNewValue event is triggered and pSliderValue is sent to the $event method for the Slider.

If you do use evNewValue, you should mark your $event method as client-executed and consider enabling the $usessteps property and setting $step to limit the number of events being triggered as the user moves the slider. Alternatively, you could use the evEndSlider event to report the final value since for most purposes this will be the value selected by the user.

Native Switch

The Native Switch control appears in the ‘JavaScript Native Components’group in the Component Store, and it works, for the most part, in the same way as the standard JavaScript Switch component but has a more familiar appearance when running on different platforms. There is an example app in the Samples section in the Hub in the Studio Browser.

iOS Android

The Switch has a $dataname property, to which you can assign a Boolean instance variable. This will be kept up to date with the state of the switch, as the end user clicks or taps on the control.

The Switch has $justifyhoriz and $justifyvert properties. For some platforms (e.g. iOS) the switch maintains a specific aspect ratio. These properties determine how the switch is positioned inside the control in these circumstances.

The text displayed on the Native Switch is controlled by two members in the built-in strings object jOmnisStrings in the JavaScript Client. You can use the members "switch_on" and "switch_off" to replace the default text with your own text, for example, if you wish to provide different language equivalents to the default text.

Information about how to change or localise these strings can be found in this manual, under "Localizing Built-in Strings".

If you wish to override the base text, you could use the following code in a separate JavaScript file loaded in your form's html file after omjsclnt.js:

    jOmnisStrings.base.switch_on = "I";
    jOmnisStrings.base.switch_off = "0";

The Navigation Bar Control (or Nav bar) provides a standard navigation bar which end users can use to navigate to different parts of your application. There is an example app in the Samples section in the Hub in the Studio Browser.

The Navigation Bar has a main title in the middle of the control, and it can have a left and/or right button which respond(s) to user clicks. The Nav bar can be linked to a Paged Pane via the $linkedobject property to allow you to display different panes in your form in response to clicks in the Nav bar. Actions for the Nav bar can be stacked up using the $push property: see the example below.

The Nav Bar has a number of properties for setting the color, fonts and style of the bar and buttons ($button.. properties), together with the following properties:

Property Description
$disableanimation Disables the animation when moving between pages. This property can only be set in design mode (not at runtime using the notation)
$initiallefticonid If this is not zero, and $initiallefttext is empty, the first navigation bar item has a button on the left hand side, displaying this icon
$initiallefttext If this is not empty, the first navigation bar item has a button on the left hand side, displaying this text
$initialrighticonid The icon for the initial navigation bar button on the right
$initialrighttext The text for the initial navigation bar button on the right
$initialtitle The initial title displayed on the navigation bar
$lefthidden If true, the left hand (back) button is hidden for the current navigation bar stack item
$linkedobject The name a paged pane on the current remote form, used in conjunction with the $push property
$push At runtime, allows you to assign a 2-6 column row to the paged pane referenced in $linkedobject: col1 is the page number of the paged pane, col2 is the title for pushed item, col3 is the text for right button (pass empty for no right button), col4 is the or icon id for the image for right button, and col5 can be non-zero to hide the left button, col6 is the text for left or ’Back’ button (pass empty to display the title of the previous pane by default). The path to the icon referenced in col4 must be obtained in a server method using the iconurl(icon-id) function since icon ids cannot be resolved on the client
$pop Removes a specified number of items off the navigation stack: see below
$righticonid If this is not zero, and $righttext is empty, the current navigation bar item has a button on the right hand side, displaying this icon
$righttext If this is not empty, the current navigation bar item has a button on the right hand side, displaying this text
$::title The title for the current navigation bar stack item

Setting $disableanimation to kTrue disables the animation when moving between pages: this property was added to fix a problem when using the built-in VoiceOver screen reader on an iPad in conjunction with a Nav Bar linked to Page Pane: the problem is avoided by disabling the animation effect on the Nav Bar.

You can use the $pop property to “pop” or remove a specified number of items off the navigation stack: it is analogous to clicking on the left or back button, since it allows you to step back in the navigation stack a specified number of times.

The $pop property can only be assigned at runtime. If you try to pop more items off the stack than exist, it will pop everything except the first item. If you assign to $pop, note that the evUserChangedPage event of a linked paged pane will not be triggered.

In addition, you can set the text or title for the left (back) button for a navbar. If provided, the 6th col in the row assigned to $push allows you to specify the left button text. This can be set to an empty string to default to the previous page's title.

Events

The Nav Bar reports evClickInitialLeftButton when the initial left button has been clicked, and evClickRightButton when the right button has been clicked.

The events evPushFinished and evPopFinished are triggered when the push or pop animations complete. Both events have one event parameter which is the associated page number that has been pushed or popped.

Example

The following Navigation Bar has a main title and a button on the right which is used to display some information on the second pane of a paged pane.

The Nav Bar is placed across the top of the form and its various properties under the General and Appearance tabs in the Property Manager are set, as follows:

$events set to receive evClickRightButton events
$linkedobject set to pPane, the name of the paged pane
$push can only be assigned at runtime; see below
$initialtitle set to “Main Page”
$initialrighticonid set to 1794, the id of an icon in Omnispic
$initialrighttext set to “Info”

The $event method for the Nav Bar ($name = oNav) traps a user click on the right button, and has the following event code:

On evClickRightButton
  Do $cinst.$doPush(2,'Info','','','')

The $doPush method is a class method in the remote form and has the following parameters, variables, and code.

# PaneNo (Short Int)
# Title, RightBtnText, RightBtnIcon (must be an icon url), NoLeftBtn (all Character)
# lRow is local var of type Row
Do lRow.$define(
    'New class','Title','text for right btn',
    'icon url for right btn','no left btn','text for left btn')
Do lRow.$assigncols(
    PaneNo,Title,RightBtnText,RightBtnIcon,NoLeftBtn,LeftBtnText)
Do $cinst.$objs.oNav.$push.$assign(lRow)

The effect of assigning to the $push property is to change the pane number in the paged pane specified in the $linkedobject property which, in this case, displays some information for the end user on the second pane. Assigning to $push adds a left or ‘Back’ button to the navbar which the end user can use to go back to the previous pane; the default text for this button is the name of the previous pane, or you can pass your own text in the 6th column of the row passed to $push.

The Navigation Menu control (or Nav menu) allows you to build interactive cascading menus within your remote forms, providing a navigation method similar to that found on many websites. Such menus typically comprise a number of hot text links, which cause further menus to open below the top level. In addition, each menu option can have an image as a background or link. The nav menu can also operate as a breadcrumb, with a hierarchical set of text links, similar to the folder selection mechanism found in Windows Explorer.

The Nav Menu control has been implemented for both the JavaScript client (remote form class) and the fat client (window class), and the two controls have almost identical properties, with the same look and feel. Unless otherwise stated, the descriptions here apply to both the JavaScript Client and fat client types of control.

There is an example app in the Samples section in the Hub in the Studio Browser.

The Navigation Menu control uses a list specified by $dataname to define its content. The list should have seven columns with each line of the list corresponding to a single entry in the menu. The columns in the list are defined as follows:

Column Type Description
Type Integer The menu entry type, a kNavMenuType… constant. See below.
Text Char The text for the menu entry. This can include styles embedded using the style() function, and embedded kCr characters in order to split the text over multiple lines.
Desc Char Optional text describing the menu entry. This can include styles embedded using the style() function, and embedded kCr characters in order to split the description over multiple lines.
Flags Integer Sum of one or more constants that indicate how the menu entry behaves. See table below.
Ident Integer A unique integer value that identifies the menu entry. Note that the control does not enforce uniqueness.
Tag Char A unique string value that identifies the menu entry. Note that the control does not enforce uniqueness. In fact, developers may choose to just use the tag or just use the ident, or make the combination of tag and ident unique.
Info Row A row that contains further information required for the menu entry. Not used for all entry types. E.g. contains the content for a cascaded menu, see kNavMenuTypeCascade.

The flags column can be zero, or a sum of one or more of the following flag values and specifies how the menu entry behaves:

Flag Description
kNavMenuFlag
HorizontalLayout
Only applies to the first line of a menu (or cascaded menu) list. If not set, entries are laid out vertically; if set, entries are laid out horizontally.
kNavMenuFlag
EndOfRowOrColumn
If set, the menu entry for this line is the last entry in the current row or column in the layout for the menu (row or column depends on whether layout is horizontal or vertical respectively)
kNavMenuFlag
Disabled
If set, the menu entry is disabled. This means it will not accept clicks, and it will not hot-track.
kNavMenuFlag
Breadcrumb
Only applies to line 1 of the $dataname menu list. If set, the menu is a breadcrumb control, and for the $dataname list, kNavMenuFlagHorizontalLayout is turned on and kNavMenuFlagEndOfRowOrColumn is ignored.
kNavMenuFlag
BreadcrumbSeparator
If set and kNavMenuFlagBreadcrumb is set and applies to line 1, the entry draws the breadcrumb separator. Note that the control uses the description text color ($descriptiontextcolor ) as the color of the separator.

The first column of your data list sets the type of menu control, using one of the following kNavMenuType... constants:

kNavMenuTypeHeading

Used as a heading to group other menu entries. Typically, this would be a disabled entry, but it can accept clicks if desired. The info column is not used for this type.

kNavMenuTypeEntry

A normal menu entry, typically used to accept a click and generate an event.

kNavMenuTypeImage

A menu (or cascaded menu) list can only have a single image entry (others are ignored). You use the info column to provide an image that will be displayed as a background of the menu, and which will also accept clicks. The control will place the image at the “end” of the menu, irrespective of where the entry is placed in the list. The info column for an image entry is a row with the following columns. Note that only the icon column is mandatory.

Column Type Description
Icon Character or Integer For the JavaScript Client, the character URL of the image, generated by calling iconurl(iconid). For the fat client, the integer icon id of the image.
Horizontal offset Integer You can adjust the horizontal position of the image in the menu by supplying a value here. Defaults to zero.
Vertical offset Integer You can adjust the vertical position of the image in the menu by supplying a value here. Defaults to zero.

kNavMenuTypeCascade

An entry representing another menu which cascades from the entry when either the mouse is over the entry, or when the entry is clicked (this depends on the $openwhenmouseover property described below). Note that the control supports a cascade nesting depth of 15.

The info column for a cascaded menu entry is a row with the following columns (note: when you understand how the properties and events for the control work, you will see that the info row does not always need to be fully specified for a cascaded menu - in many cases only column 1 is required, and in fact, in some cases, the info row is not required at all for a cascaded menu):

Column Type Description
List List A menu list defining the entries in the cascaded menu.
Cascade flags Integer Zero, or a sum of kNavMenuCascadeFlag… flags, see below. Defaults to $defaultcascadeflags.
Open side Integer The side from which the cascaded menu will open. Either kNavMenuSideLeft, kMenuSideRight, kMenuSideBottom or kMenuSideTop. Defaults to $defaultcascadeopenside.
Border edges Integer A sum of kNavMenuSide… constants that specifies the edges of the cascaded menu that are to have a border. Defaults to $defaultcascadeborderedges.
Border color Integer The color of the border of the cascaded menu. Defaults to $defaultcascadebordercolor. For the JavaScript Client control, you must set this column to the result of truergb(color) if the color you are using is a color constant.
Border width Integer The width of the border of the cascaded menu (1-16). Defaults to $defaultcascadeborderwidth.
Background color Integer The background color of the cascaded menu. Defaults to $defaultcascadebackcolor. For the JavaScript Client control, you must set this column to the result of truergb(color) if the color you are using is a color constant.
Background alpha or foreground color Integer For the JavaScript Client, the background alpha value for the cascaded menu (0-255). Defaults to $defaultcascadebackalpha. For the fat client, the foreground color of the cascaded menu. Defaults to $defaultcascadeforecolor.
Background pattern Integer Only applies to the fat client. The background pattern of the cascaded menu. One of the standard pattern constants. Defaults to $defaultcascadebackpattern.

Cascade Flags

The cascade flags are as follows:

Flag Description
KNavMenuCascadeFlag
UseEventToPopulate
If set, the control sends evLoadCascade in order to populate the cascaded menu
KNavMenuCascadeFlag
UseEventWhenRequired
If set, and kNavMenuCascadeFlagUseEventToPopulate is also set, only send evLoadCascade when data is required again for some reason,rather than each time the menu opens
KNavMenuCascadeFlag
OpenOnParentEdge
If set,the cascaded menu opens on the relevant edge of the parent menu, rather than opening on the relevant edge of the parent entry.
KNavMenuCascadeFlag
Expand
If set, and kNavMenuCascadeFlagOpenOnParentEdge is also set, the cascaded menu expands if necessary to the width or height of the parent.
KNavMenuCascadeFlag
UseDefault
If set, use the default cascaded menu flags for the control ($defaultcascadeflags) and ignore any other flags. This allows you to use default cascade flags, and then override other properties using the info row.

In addition to the standard control properties, the Nav Menu control has the following properties:

Property Description
$borderedges A sum of kNavMenuSide… constants that specifies the edges of the control that are to have a border.
$borderwidth The width of the border of the control (1-16).
$closeboxiconid

The icon id of the close box for cascaded menus (only relevant when $openwhenmouseover is kFalse, and the control is not in breadcrumb mode). Note that when $openwhenmouseover is kFalse, on a non-touch device, menus still close automatically when the mouse leaves the control or its open cascaded menus. If you do not want a close box, set this to zero.

On a touch device you can close all open cascaded menus by touching an area away from the control and its open cascaded menus.

$defaultcascade… Default properties for cascaded menus (see the description of the info row for cascaded menus). These eliminate the need to repeat this information for every cascaded menu.
$horizontalcascadeiconid The id of the icon used to represent an entry that cascades to the left or right.
$horizontalspacing Horizontal spacing used when laying out entries.
$hotcloseboxiconid The icon id of the close box for cascaded menus, used when $openwhenmouseover is kFalse, and the mouse is over the close box.
$verticalcascadeiconid The id of the icon used to represent an entry that cascades to the top or bottom.
$verticalspacing Vertical spacing used when laying out entries.
$font… properties Used to control the font and colour of entry text: $font, $fontsize, $fontstyle, $textcolor, $hotfontstyle, $hottextcolor
$descriptionfont… properties Used to control the font and colour of description text: $descriptionfont, $descriptionfontsize, $descriptionfontstyle, $descriptiontextcolor
$headingfont… properties Used to control the font and colour of heading text: $headingfont, $headingfontsize, $headingfontstyle, $headingtextcolor, $hotheadingfontstyle, $hotheadingtextcolor
$openwhenmouseover If true, cascaded menus open when the mouse is over the relevant part of the control. Otherwise, the user needs to click in order to open a cascaded menu. On a mobile device, the value of this property is ignored and treated as kFalse, because there is no mouse.

When an entry is selected in the Nav Menu an event is triggered, one of the the following events:

Event Description
evLoadCascade The control sends this event when it needs to populate a cascaded menu (i.e. kNavMenuCascadeFlagUseEventToPopulate is set for the menu). The application code processing this event builds a list for the cascaded menu, and assigns it to the runtime-only property $cascadecontents.
evMenuEntryClicked The control sends this event when the user clicks on a menu entry.
evEmptySpaceClicked The user has clicked in empty space to the right or bottom of the menu (generated for top-level menu page only).

evLoadCascade and evMenuEntryClicked have 2 event parameters, pLineIdent and pLineTag, which are the ident and tag of the menu list line for which the event was generated. These events and their parameters can be trapped in the $event method for the control.

Scrolling

If the initial menu (set with the list content in $dataname) is too wide to fit the control, the control uses scroll arrows at the left and right to allow its content to be scrolled – ideally you should fit your content to the width of the control so no scroll arrows are required. The scroll arrows are displayed in this case to support the breadcrumb mode which uses a single row of entries for the initial page.

On a touch device, the scroll arrows are not displayed but you can scroll the control horizontally by touch-dragging. The scroll arrows are the same ones used for the tab control which are specified in omnis.css and the images folder, so you can change their appearance if required.

The following methods define the Nav Menu for a fictional online shop (they are contained in an object class and called via an object variable in the remote form). An example containing a similar Nav menu is available in the JavaScript Components Gallery on the Omnis website, and in the Hub.

First the content list for the Nav Menu is defined (with seven columns), then the second-level items are created, in this case the shop departments, and the top-level for the menu is added. The list built here is added to the list specified in $dataname for the Nav Menu object in a remote form.

Do method defineMenuList (lDepartmentList)
Do lDepartmentList.$add(kNavMenuTypeCascade"Books""", 0, 100, "books")
Do lDepartmentList.$add(kNavMenuTypeCascade"CDs""", 0, 101, "cds")
Do lDepartmentList.$add(kNavMenuTypeCascade"Digital music""", 0, 102, "digimusic")
Do method defineMenuList (lOmniShop)
Do lOmniShop.$add(kNavMenuTypeCascadecon("Shop by",kCr,"Department"),"",0,1,"",
row(lDepartmentList,kNavMenuCascadeFlagOpenOnParentEdge +
kNavMenuCascadeFlagExpand,kNavMenuSideBottomkNavMenuSideTop+
kNavMenuSideBottomkNavMenuSideRight))
Quit method lOmniShop

The defineMenuList method is a generic method to define the list of the menu content:

Do pMenuList.$define(lType,lText,lDescText,lFlags,lIdent,lTag,lInfo)

The $events property for the Nav Menu object has two events specified: evLoadCascade and evMenuEntryClicked. The menu object itself has the following event method:

On evLoadCascade
  Do iNavMenuObject.$shopLoadCascade($cfield,pLineTag)
On evMenuEntryClicked
  If not(iNavMenuObject.$handleclick($cfield,pLineTag))
End If

The $shopLoadCascade method builds the content for the cascaded menu:

Do method defineMenuList (lCascadeList)
Switch pTag
  Case "books"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"Books","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
    kNavMenuTypeEntry,"Best sellers","Top 1000 books",0,200)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"eBooks","For kindle and tablets",0,201)
    Do lCascadeList.$add(
   kNavMenuTypeImage,"Pre-order","",0,202,"",row(iIcon10001))
       # this line is shown in the pic below
  Case "cds"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"CDs","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"CD store","Over 3m CDs",0,300)
   Do lCascadeList.$add(
      kNavMenuTypeImage,"Rock store","",0,301,"",row(iIcon10002))
  Case "digimusic"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"Digital music","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"Music store","Over 30m songs",0,400)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"Your music library","Play online",0,401)
    Do lCascadeList.$add(
      kNavMenuTypeImage,"Pre-order","this new
      album",0,402,"",row(iIcon10000,-200,-50))
  End Switch
Calculate pControl.$cascadecontents as lCascadeList

The menu will look something like this:

 

Page Control

The Page Control links to a Paged pane on a remote form and allows the end user to change the current page in the linked paged pane by swiping over the page control or clicking for non-touch screens. The Page control also gives the end user a visual clue as to the current selected pane in the linked page pane object, since the highlighted dot in the control changes to reflect the current page in the linked paged pane. There is an example app in the Samples section in the Hub in the Studio Browser.

The paged pane linked to the Page control is specified in the $linkedobject property. In this case, when the page control is clicked or swiped the linked paged pane control will select the next available pane automatically.

Property Description
$::currentpage the current page number
$linkedobject the name of a paged pane object on the current remote form that links to the iPage control
$::pagecount the number of pages

When the page indicator changes in the Page control an evPageChanged is triggered containing the number of the new page in pValue.

Paged Pane

The Paged Pane provides a very convenient method to show a number fields or controls on separate panes, or to break down an entry form into more manageable parts whereby each pane contains a small number of fields. The $pagecount property specifies the number of panes, and $currentpage specifies the current pane. In design mode, you have to set $currentpage to the number of the pane you wish to add fields to, or you can right-click the background of the paged pane and select the number of the pane you want to edit. You can set $effect to select different border effects for the control (a kJSborder... constant).

You can link a paged pane to a Navigation Bar, Page Control, or Tab Bar control so when the nav bar, page or tab changes the current pane of the paged pane changes accordingly. To link a paged pane to one of these controls, set the $linkedobject property of the Nav bar, page control or Tab bar to the name of the paged pane.

By setting $scrolltochangepage to kTrue the pages are laid out horizontally, and the end user can change the current page by scrolling horizontally (for touch devices the end user can change panes by tapping on the current one); in this case, an evUserChangedPage is triggered with the new page number reported in pPageNumber.

Rounded Corners

The $borderradius property lets you add rounded corners to the Paged pane. The radius can be specified by a single value, so all corners are the same radius, or up to four hyphen-separated pixel values, in the order topleft, topright, bottomright, bottomleft, e.g. 4-4-0-0 to add rounded corners to just the top of the paged pane. If the bottomleft value is omitted the topright value is used. If bottomright is omitted the topleft value is used. If topright is omitted the topleft value is used.

Note: If a border radius is set, the rounded corners are not drawn in design mode: they are only rendered when the app is run on the client. The rounded corners are not drawn in design mode to allow the full use of the available space within the page pane control while designing the form.

Using $dataname

The Page Pane control has a $dataname property which you can use to set the value of $currentpage. When the form is opened or redrawn the numeric value of $dataname is used to set the current page. If $dataname is empty or returns an invalid page number, the control uses the page number in $currentpage.

Page Panes in Complex grids

You can use a page pane in a complex grid. You can set the value of $currentpage by assigning a column in the complex grid list to $dataname of the page pane. Therefore each row in the complex grid could display a different page in the page pane control.

In this case, controls within the page pane control will also get their data from the complex grid control, if their $dataname refers to a column in the list used to build the complex grid.

Group Boxes

A Group box component is not available in the JavaScript client components, but you can create one “on the fly” using a new method called $makegroupbox() to change a Paged pane into something that simulates the behavior and appearance of a group box. The method PagePaneName.$makegroupbox(cLabel[,cFont,cFontSize,cTextColor]) must be executed on the client, and converts a Paged pane to a Group box with the specified label, as well as the optional CSS font, font size, and text color. This method can be called from $init in the remote form.

Animated Transitions

If enabled, the $animatetransitions property ensures that the transition between pages is animated when the current page is changed. The property cannot be changed at runtime (the same as $scrolltochangepage).

If used in conjunction with $scrolltochangepage, when the user stops scrolling, the pane will smoothly animate into position, rather than jumping instantly.

The animation time is set to 500ms, which should be fine for most purposes, but if you wish to change this, you can use JavaScript to change the Paged Pane control's (or its prototype's) ANIMATION_TIME property.

Page Styling

Page panes have a default CSS classname ‘omnis-pagedpane-page’. This allows you to apply CSS styling or behavior to each page of the paged pane control.

In addition, a CSS rule (-webkit-overflow-scrolling: touch;) enables momentum scrolling on iOS, i.e. for touch iOS devices, scrolling slows down before stopping.

Picture Control

The Picture control allows you to display an image in your form: you can display an image file in a folder, an image from a database, or an icon, depending on the combination of settings of $dataname, $mediatype and $iconid. If $mediatype is empty (and $iconid is zero), the $dataname of the Picture control is a URL to the image to be displayed, relative to your html page containing the JavaScript Client. If $mediatype is specified, then $dataname is the name of a binary instance variable containing the image data: in this case, $mediatype can be set to one of the standard image types, e.g. image/png, image/jpeg or image/gif. Alternatively, $iconid can be set to a URL referencing an image file in the ‘html/icons’ folder, overriding the $dataname and $mediatype properties. For backwards compatibility, the picture control can display an icon in an icon data file (Omnispic) or #ICONS by setting $iconid to a numeric icon ID.

Image Alignment and Scaling

The $picturealign property specifies where the picture will be positioned in the control and is a kPAL... constant. The $noscale property determines whether or not the images displayed in the control are scaled. The $keepaspectratio property determines whether or not the images displayed in the control keep their aspect ratio when scaled: if true, and $noscale is false, the aspect ratio of pictures is maintained when they are scaled.

The property $keepaspectratiomode controls how the image in the Picture control is scaled and positioned when $keepaspectratio is true and $noscale is false. The value of $keepaspectratiomode is a kKAR... constant with the possible values:

  1. kKARtopLeft
    The image is scaled to fit the control and anchored at the top-left corner. This is the default value (and maintains compatibility with existing libraries)

  2. kKARcenter
    The image is scaled to fit the control and centered, so background may be visible at the top and bottom or the left and right of the image, depending on the shape of the image control and the orientation of the image

  3. kKARfill
    The image is scaled to fill the control and centered, so no margin (background) is shown. This can result in the image being cropped at the top and bottom, or the left and right, depending on the shape of the image control and the orientation of the image

Example

In the Webshop sample app, the product images are shown in a Picture control embedded in the Complex grid control on the main jsShop remote form. In this case, $mediatype is set to JPG and the $dataname of the control is iProductList.product_picture which holds the image data for each product.

Pie Chart Control

See the description for the Bar Chart Control for information about defining the list variable structure for pie and bar charts, plus chart events, as well as information about setting the bar/segment colors for charts.

There is an example app in the Samples section in the Hub in the Studio Browser showing you how to set up a Pie chart, and the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net

Main and Legend Titles

There are a number of properties in the Pie Chart component to allow you to add a legend title and have some control over the appearance and positioning of the legend.

$maintitle The legend title
$showlegendnames If true the legend shows the value names ( column 2 ) and not values ( column 1 ). The list data structure is same as bar chart
$legendcolumns The number of columns the legend is split into
$legendpos Changes the position of the legend: can be above, below, left or right of the pie
$flyout Enables the pie segments to move or “fly out” when the end user’s mouse hovers over the segment (kTrue by default)

Two positioning constants are available for the $legendpos property (which in practice are only appropriate for mobile devices), whereby as the device is rotated and the screen orientation changes, the legend is repositioned automatically either “before” (left or above) the pie or “after” (right or below) the pie. The constant values are:

kJSPieLegendAutoBefore the legend is placed before the pie chart, either above or to the left of the chart
kJSPieLegendAutoAfter the legend is placed after the pie chart, either below or to the right of the chart

The Popup menu is a menu that pops up when the user clicks on the header of the control, or when $hotwhenmouseover is true the menu will pop up when the end user’s pointer hovers over the control. The contents of the popup menu can be:

  1. a list variable specified in $::listname

  2. a remote menu class specified in the $::menuname property, or

When specifying one of these properties, the other property must be empty; the properties are on the Data tab in the Property Manager.

There are two example apps that use the Popup menu in the Samples section in the Hub in the Studio Browser: the first is named JS Droplist, Combo, Popup and uses a popup built from the list; the second uses a Remote menu to display a popup menu. The same apps are available in the JS Component gallery on the Omnis website at: www.omnis.net

When using a list variable to populate a Popup menu, the data in the column specified in $coltext is used for the menu options. The $colenabled property is the column name for the menu line enabled state, and $colcommandid is the column name holding the menu line command id.

You can add an icon to the popup menu by setting $iconid to the ID of an icon in an icon file or #ICONS. You can place the icon before or after the menu title by setting $textbeforeicon.

The menu will normally popup when the user clicks on the control, but you can make the menu popup when the end user’s pointer passes over the control (it is “hot”) by setting $hotwhenmouseover to kTrue.

You can control the position of the popup by setting $menupos to one of the constants: kJSPopMenuPosBottom, kJSPopMenuPosRight, or kJSPopMenuPosTop.

When the menu is clicked the evClick event is triggered with the selected line reported in pLinenumber. You can use the following $event method to trap the line number:

On evClick
  If pLineNumber>0 ## a line was selected
    ## Do something
  End If

You can use an HTML <select> tag for the user interface by setting $usehtmlselect to kTrue.

Progress Bar Control

The Progress Bar control lets you display a progress bar in your remote form, to show the progress of some process in your application. The current value of the progress bar is reported in the $::value property which is a value between 0 and the value of $max inclusive. The color of the bar representing the completed amount can be set in $progresscolor, which only applies when the standard HTML5 progress control is not available.

The $sendcarryon property provides a mechanism to send an evCarryOn event to the progress control. To generate an evCarryOn event, assign kTrue to $sendcarryon. The event processing code for evCarryOn can assign $sendcarryon to kTrue again, to generate the next evCarryOn.

You can add a Cancel button to your form to allow the end user to break a long process, but the Cancel button itself must be named in the $alwaysenabledobject remote form property so it remains enabled during the long process.

System Appearance

When set to true (the default), the $usesystemappearance forces the progress control to use the <progress> HTML5 element (as long as it’s supported by the browser). If $usesystemappearance is set to false, the progress control is built with two <div> elements, and the following additional properties apply. $secondarycolor sets the color of the stripes of the progress bar, and $progressanimation (true by default) animates the progress bar.

Example

The following example assumes the progress control has been added to a remote form and a button is used to initiate some process and send a carryon event to the progress itself; note the ‘lockui’ client command is used to stop any clicks on the UI once the progress is initiated (except for the Cancel button). The initial values for $::value and $::max of the progress control are 0 and 100 respectively. The following code could be behind a button:

On evClick
  Do $cinst.$clientcommand("lockui",row(kTrue))
  Calculate iCancelled as kFalse
  Calculate iValue as 1
  Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)

The evCarryOn event is sent to the progress bar which has the following event method:

On evCarryOn
  If not(iCancelled)
    Calculate iValue as iValue+5
    Do $cinst.$objs.ProgressBar.$::value.$assign(iValue)
    If iValue<100
      Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)
    Else
      Do $cinst.$clientcommand("lockui",row()) ## unlock ui
    End If
  End If

This example is in the Samples section in the Hub in the Studio Browser, and in the JS Component gallery on the Omnis website at: www.omnis.net.

RadioGroup Control

A Radio Group presents a number of mutually exclusive buttons that can be either on or off: selecting one of the radio buttons deselects all other buttons in that group. The variable you assign to a radio group should be numeric. Its value is within the range $minvalue and $maxvalue inclusive and directly corresponds to which button in the group is selected, that is, the first button selects the first value in the range, the second button the second value, and so on. The labels for the buttons are assigned in $text which is a comma-separated list. The Radio group has the following properties:

Property Description
$dataname a numeric variable
$horizontal If true, the radio column order is horizontal
$columncount The number of columns shown for the radio group
$minvalue The minimum value for the radio group
$maxvalue The maximum value for the radio group
$text Comma-separated list of labels assigned to the buttons

The evClick event is reported with pNewValue containing the value selected.

Note that the Check box example app in the Samples section in the Hub in the Studio Browser also uses a Radiogroup (to select Gender in this case), and the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net

Example

The Webshop app uses a Radiogroup control to allow the end user to select a group or category of products to be shown in the main product list. (To examine this control and its properties and methods, open the webshop library and the jsShop remote form.) The $minvalue and $maxvalue of the radiogroup are set to 0 and 8, respectively (although the groups are generated dynamically in the form), and the numeric variable iRadioGroup with an initial value of 1 is assigned to $dataname. When the form is opened, the $construct() method behind the radiogroup calls a $build method.

# radiogroup control is called ‘filter’ containing
# $construct method which is run when the form opens
Do iGroupList.$definefromsqlclass($tables.T_qGroups)
Do $cfield.$build()

The $build method generates a list of product groups from the database, which is then concatenated into a single comma-separated list and assigned to the $text property of the radiogroup.

# $build method behind the radiogroup
Do iGroupList.$selectdistinct()
Do iGroupList.$fetch(kFetchAll)
For iGroupList.$line from 1 to iGroupList.$linecount() step 1 ## loop through the list
  Calculate text as con(   text,mid($prefs.$separators,3,1),iGroupList.product_group## uses the localized separator (possibly semicolon)
End For
Calculate text as mid(text,2,len(text))
Do $cfield.$minvalue.$assign(1)
Do $cfield.$maxvalue.$assign(iGroupList.$linecount())
# $maxvalue of radiogroup is set to the number of groups in list
Do $cfield.$text.$assign(text)

When the form is opened the main product list is built using a method behind the product list itself (also called $build) and the list initially contains the Appetizers only. A group of radio buttons is created, each item representing a different group or category of food or drink; the initial value of the radiogroup is set to 1 selecting the first item in the group.

When the end user clicks on the radiogroup, to select another product type, the click is detected in the $event method in the radiogroup control, the number of the radio button clicked is passed in pNewVal, and the product list is rebuilt based on the selected product group; note a Where clause is created based on the selected group and sent to the $build method behind the main productList control.

# $event method for Radiogroup
On evClick
  Calculate whereClause as con(
    'WHERE product_group =
    ',kSq,iGroupList.[pNewVal].product_group,kSq)
  Do $cinst.$objs.productList.$build(whereClause)

Rich Text Editor Control

The Rich Text Editor control (jsrich) can be used instead of a regular Edit or Multi-line edit field, which adds the ability for end users to edit the text using a text editor UI and to apply “rich” formatting such as bold, italic, and simple bullets. There is an example app showing how you can use the Rich text editor 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

The Rich text editor control uses the Quill open source text editor which relies on modern browser technologies and, as such, some older mobile OS's (iOS < 6.0 & Android < 4.0) may have compatibility issues. For Studio 8.0.2 the control is based on Quill 1.0, which brings several new features and bug fixes, including Code Blocks with syntax highlighting, Undo/redo shortcut keys, Sub/Superscript, In/Outdent, Block Quotes, Image uploads, content tips, and so on.

The text data for the control is stored in the instance variable assigned to $dataname: see below for properties to format the data content. You can allow text editing in the control by setting $showcontrols to kTrue where upon the text content in the field will become editable: on mobile devices this places the cursor in the field and opens the soft keypad ready for typing. The text editing controls in the field will appear at the top of the control and will allow the end user to format the text, including bold, italic, underline, and so on. The text data in the control is HTML markup and can include formatted text such as ordered (numbered) and unordered lists (bullets). End users can also insert images using the Paste option.

Dynamically Loaded Resources

The control dynamically loads the necessary JavaScript & CSS files when it is used. There are several files in the Studio tree to support the text editor:

html/scripts/
    quill.js
    quill-legacy.js
    highlight.pack.js
html/css/
    quill.snow.css
    quill-legacy.snow.css
    highlight-theme.css

When deploying to a web server, you must make sure to also copy these files over. Quill 1.0 only supports IE 11+. When running on earlier IE versions, the control will fall back to Quill 0.2 - this is what the ‘-legacy’ files above are used for.

Properties

Together with the standard component properties, the Rich Text Editor Control has the following properties:

Property Description
$dataname The name of an instance variable to store the HTML formatted text, or a column in an instance row variable
$dataformat Controls the format of the document data stored in $dataname for the control, a constant: kJSRichTextDataFormatJSON, kJSRichTextDataFormatHTML, or kJSRichTextDataFormatPlain
$showcontrols Set this to kTrue to switch the control to edit mode and to display text editing toolbar controls
$plaintextname Specifies the name of a variable that automatically receives the plain text equivalent of the data stored in the variable named in $dataname (just the plain text without any HTML formatting); this property is optional
$contenttip Allows you to specify some text to be displayed in the editor when it has no content
$removedtoolbaritems A bitmask of kJSRichText… values, allowing you to specify toolbar items to hide in your Rich Text Editor instance

Setting Default Text Properties

You can specify the default value of the font, size and text color shown in the editor’s controls by assigning values to the component’s text properties, as follows:

  1. $font
    maps directly to the editor’s font droplist, and will set the default value accordingly.

  2. $textcolor
    will attempt to set the default text color to one of the colors in the toolbar’s color palette. If there is not an exact match, it will add the color as another tile in the palette.

  3. $fontsize
    will set the default font size to the closest match. Set to 13 for the ‘Normal’ font size as default.

Data Format

The $dataformat property controls the format of the document data stored in $dataname for the control. It can be one of the following constants:

  1. kJSRichTextDataFormatJSON
    The document data will be stored in the $dataname as JSON, as a Quill 'Delta' object. This is the best option for restoring the data later, as it preserves all formatting.
    When setting the data, you can assign JSON (Delta), HTML or plain text: this should be detected and converted as necessary.

  2. kJSRichTextDataFormatHTML
    The document data will be stored in the $dataname as HTML. This may lose some minor formatting. This format is suitable to use if you are going to use the data elsewhere in your code, but not for storing the document data and restoring into the Rich Text Editor.
    When setting the data, you can assign HTML only.

  3. kJSRichTextDataFormatPlain
    The document data will be stored in the $dataname as Plain text. This will lose most formatting.
    When setting the data, you can assign Plain Text only.

The $dataformat property can be changed in your code to populate the $dataname with data of the specified format. Note that if you do this in a server-executed method, the $dataname won't be updated until the client next contacts the server.

Appending Data

The $appenddata(cData, bNewLine) and $prependdata(cData, bNewLine) methods allow you to append or prepend data to the content in $dataname. If you pass bNewLine as kTrue, the data will be added on a separate line. These methods can only be executed on the client.

The data format of the passed data depends on the value of the $dataformat property. If $dataformat is JSON, the data could be sent as plain text, HTML or JSON (a Quill Delta object).

Code Blocks

The updated Rich Text Editor allows you to insert Code Blocks. These allow you to insert syntax-highlighted code. The syntax highlighting is achieved using highlight.js and by default includes highlight support for several popular languages.

If the language(s) you require is/are not supported out of the box, you can create a ‘Custom Package’ on the highlight.js download page, and replace the highlight.pack.js in your tree/web server with the one you download.

Similarly, if you want to change the code block’s appearance, you can take any of the theme css files from your highlight.js download, rename it highlight-theme.css and replace the supplied file with your own.

Drag and Drop

End users can drag data from a Rich Text Editor and drop it elsewhere in the form, or users can drag data and drop it into the Rich Text Editor; in the latter case the evDrop event is generated in the control. If some text is selected and dragged out of the Rich Text Editor, then only the selected text is dropped at the cursor position.

End users can also drag external content and drop it onto the Rich Text Editor, e.g. text or an image from another browser pane or a different application, but in this special case the evDrop event is not generated in the control.

Localizing the Rich Text Editor

There are various strings in the Rich Text Edit control that can be localized in the string table for the remote form containing the control. You must use the following string table ids to replace the default text for the controls in the text editor.

Tooltips for buttons

rt_bold rt_subscript rt_italic
rt_superscript rt_underline rt_strikethrough
rt_justifyleft rt_removeformat rt_justifycenter
rt_indent rt_justifyright rt_outdent
rt_justifyfull rt_textcolor rt_insertorderedlist
rt_backgroundcolor rt_insertunorderedlist rt_decrease_indent
rt_increase_indent rt_video rt_blockquote
rt_codeblock rt_clearformat

Text displayed on controls

rt_fontsize rt_fontfamily rt_sansserif
rt_serif rt_monospace

Printing the Text Contents

End users can print the contents of the editor control using a print button on the editor's toolbar, which when clicked opens a window for printing. The $printcontents lets you print the contents.

  1. $printcontents(cTitle)
    Opens a new window to print the editor's current contents. cTitle is the title of the document to print.

You enable the new print button by setting $removedtoolbaritems to kJSRichTextPrint. In addition, the Omnis string table item with ID: rt_print lets you edit the tooltip of the button.

Segmented Control

The Segmented Control displays a number of segments or buttons that you can use for navigation (like a tab bar). or as a toolbar within your web and mobile apps; or you can use it with only two segments to create a switch. You can assign an icon and text to each segment and you can detect which segment has been clicked.

The Segmented control provides a series of ‘segments’ or buttons arranged horizontally, each of which can contain an icon and/or text. You can optionally show the selected segment in a highlighted state, which is useful if you are using the segmented control as a navigation control.

You can use the segmented control as a toolbar, docking it to the top or bottom of its container by setting its $edgefloat property to one of the kEFposn… values.

There is an example app in the Samples section in the Hub in the Studio Browser, showing how you can use the Segmented control as a toolbar and switch (the second image below); the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

Properties

The Segmented control has the following properties, together with the standard properties for a JavaScript control.

Property Description
$currentsegment The number (1 - $segmentcount) of the current segment (this specifies the segment affected by segment specific properties).
This can also be changed in a design view by clicking on a segment of the design component. The current segment will be shown with a red outline while the component is selected.
$hidedisabledsegments Hides any disabled segments
$movesegment Lets you move a segment (in design mode only)
$segmentcount The number of segments (must be at least one).
$segmentenabled If true, the segment is enabled and generates a click event when the user presses it.
$segmenticonid The icon displayed on the current segment. Set to 0 for no icon;
$segmenttext The text displayed on the current segment.
$displaystyle A kJSSegmentStyle… controls whether the text is above or below the icon
$showselectedsegment If true, the currently selected segment will be shown in a highlighted state. See $selectedcolor & $selectedtextcolor.
If false, the highlighted appearance will still be shown while segments are being clicked, to give the user feedback of the click.
$segmentbordercolor The colour that applies to borders / dividers of segments
$segmentborderradius Single value border radius that applies to segments. If $segmentspacing is zero, this applies to only the outer edges of the outer segments. Otherwise it applies to all segments
$segmenteffect Determines whether borders / dividers are applied to segments, either kBorderNone or kBorderPlain
$segmentenabled Set to kFalse to disable a segment
$segmentspacing the space between the segments in pixels. The behavior can be affected by $segmentwidth (see below). If zero, dividers are drawn between segments. Otherwise borders are drawn around the segments
$segmentwidth The width applied to all the segments in pixels. By default, this is zero, in which case the width of the segments is determined by the total width of the control and $segmentspacing. If this value is small enough, the segments will be centred in the control
$selectedsegment The number (0 - $segmentcount) of the currently selected segment. If 0 no segment will be selected.
$selectedcolor The background color of the currently selected segment, or of the segment currently being clicked.
$selectedtextcolor The text color of the currently selected segment, or of the segment currently being clicked.
$bordercolor Controls the color of the segment divider lines, as well as the control’s border.
$backcolor Controls the background color of the segments.

Segment size and spacing

If $segmentwidth and $segmentspacing are set so that the segments extend beyond the width of the control, the overflowing content will be scrollable. However, if $segmentwidth is zero (the default), the segments will always fit inside the container.

In the extreme case where $segmentspacing is very high, as long as $segmentwidth is zero, the spacing will be limited to prevent the segments becoming too small or the content overflowing.

Hiding Disabled Segments

You can set $segmentenabled for a segment to false to disable it. The new property $hidedisabledsegments allows you to hide any segments that have been disabled.

Moving Segments in Design mode

The $movesegment property lets you move a segment: you need to set it to a number corresponding to the new position (the property works in the same way as the Data Grid's $movecolumn property).

Events

An evClick event is generated when one of the segments is clicked and the pClickedSegment event parameter returns the number of the segment clicked.

Slider Control

The Slider control provides a graphical slider component with an optional custom thumb icon that the user can drag to control its numeric setting, which can be used to set the value of another component in your form, such as a volume control. As an alternative, you can use the Native Slider to control variable numeric values.

There is an example app 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.

The current value of the slider is reported in the property $val according to where the slider is positioned. You can specify the range for the slider in the $min and $max properties, while $step is the size of each step the slider takes between the min and max values. The slider also has these properties:

Property Description
$vertical If true, the slider is a vertical slider
$sliderhorziconid The id of the icon to use for a horizontal slider handle
$sliderverticonid The id of the icon to use for a vertical slider handle
$horzmargin The horizontal drawing margin
$vertmargin The vertical drawing margin

The Slider reports three events: evStartSlider (when the control is starting to track), evEndSlider (when the control has finished tracking), and evNewValue (when the value has changed). You can detect these events in the $event method for the component. These events all pass the current value of the Slider in the pSliderValue parameter. As the user drags the Slider thumb the evNewValue event is triggered and pSliderValue is sent to the $event method for the Slider.

To use the values of the slider in your remote form you can trap the slider events in the $event method of the slider control (which must execute on the client), and transfer the current values to instance variables in your form, as follows:

On evStartSlider
  Calculate iStartValue as pSliderValue
On evEndSlider
  Calculate iEndValue as pSliderValue
On evNewValue
  Calculate iNewValue as pSliderValue

Subform

The Subform control allows you to place another remote form class inside the main remote form; the concept of the subform is similar to embedding an iframe into an HTML page where you can embed another form or page. You could, for example, create a single “main” form and a number of other remote forms loaded at runtime into a subform control, to create a powerful and interactive web application with many subforms or frames. The JavaScript Component Gallery app on the Omnis website, for example, is implemented using a main gallery form and each example component is loaded in a separate form as a subform.

When you have placed the subform control on your remote form, you specify the initial remote form to appear in the subform in the $classname property. Alternatively, you can switch subforms at runtime by assigning a new remote form name to $classname to switch the current form displayed in the subform control, as follows:

# oSub is the name of the Subform control on the main Remote form
Calculate $cinst.$objs.oSub.$classname as NewFormName

Note: you can also create a group of subforms dynamically in your code using a Subform Set, which is described in the JavaScript Remote Forms chapter.

Example

The Holidays sample app (in the Applets section of the Hub in the Studio Browser) uses a subform to display either the User or Admin form. When the main jsHolidays remote form is loaded, its $construct() method calls a class method to setup the initial subform to be shown which, in this case, is the User form. In addition, there are buttons on the main Holidays form to allow the end user to switch forms; for example, the code behind the User button is:

# $event method for User button on jsHolidays
On evClick
  Do method setSubForm (kUserForm)
  Calculate iAdminBtnState as kTrue
  Calculate iUserBtnState as kFalse
  Do $cinst.$objs.adminBtn.$enabled.$assign(kTrue)
  Do $cobj.$enabled.$assign(kFalse)

The setSubForm method has the following code to switch forms:

If pOption=kAdminForm ## test if Admin or User
  Do $cinst.$objs.subForm.$classname.$assign("jsAdminForm")
Else
  Do $cinst.$objs.subForm.$classname.$assign("jsUserForm")
End If

There are further subform examples in the Samples section in the Hub in the Studio Browser, and the same apps are available in the JS Component gallery on the Omnis website at: www.omnis.net.

$dataname and Subforms

If the remote form class inside the subform field has only one field, you can override its dataname using the $dataname property for the subform field. For example, your subform class may contain a single headed list field that takes its data from a specific list variable. However, you can change the list assigned to the headed list by setting the subform field’s $dataname property to the name of another list. You could do this in the $construct() method of the subform field.

$construct and Subforms

Opening a remote form containing a subform field or any number of subform objects creates an instance of each form, which belong to the same task as the parent remote form instance. Omnis calls the $construct() methods of all the subform classes first in tabbing order, then the $construct() method of the parent form instance. The reverse happens on closing the parent form, with the subforms being destructed after the parent form instance.

You can send parameters to the subform’s $construct() method by including a comma-separated list of parameter values in the $parameters property when you create the subform field. The $parameters property can only be assigned in the remote form editor, and it has no effect at runtime. If you attempt to set it at runtime in your code, the error "$parameters cannot be assigned at runtime" will be displayed on the client.

$init and Subforms

When changing subform instances you can send parameters to the new target subform instance. To do this you can assign a comma-separated list of values to the $userinfo property of a subform and this can be parsed and sent as parameters to the client-executed $init method in the new subform instance. Each token in the comma-separated list will be a separate parameter, and can be a quoted string (including spaces and commas) or a numeric value. For example, when changing subform:

Calculate $cinst.$objs.subform1.$userinfo as "'Davy Jones',123,0"
Calculate $cinst.$objs.subform1.$classname as "jsSubform1"

In the $init method in the new subform jsSubform1, three parameters will be populated: p1: "Davy Jones", p2: 123, p3: 0.

Multiple Subforms and Caching

The $multipleclasses property tells Omnis to keep a set of remote form instances open for use in the subform object, rather than constructing a new instance each time the class is changed. When you assign a new remote form name to $classname at runtime, the new remote form is downloaded to the client and displayed in the client’s browser. If the $multipleclasses property is enabled, the previous remote form is cached and hidden on the client, otherwise the remote form instance is destroyed. If any previous remote forms have been cached in this way using $multipleclasses, you can switch back to them instantaneously, otherwise they have to be reloaded each time you assign to $classname of the subform object.

Referencing Subform Instances

A subform control has the $subinst property (object) which is the instance contained within the subform control. You can use this property to get a reference to the instance in a subform object and therefore change properties within the instance. If the subform property $multipleclasses is set to kTrue, you must use $subinst(cClassName) to get a reference for the appropriate instance. For example, where a subform control has a single subform class the following code will return a reference to the form instance in the subform:

Set reference item to $cinst.$objs.subfrm.$subinst
Do item.$setcolor(kRed)

or when you may have assigned multiple classes to the subform control ($multipleclasses is set to kTrue):

Set reference item to $cinst.$objs.subfrm.$subinst("classname")
Do item.$setcolor(kRed)

Note that the item returned will be null if the instance does not exist.

Subform Container Notation

You can use $cinst.$container to obtain the instance containing a subform instance, where in the current context $cinst is a subform. The $container property returns the object containing the referenced object. This notation will work in server methods (for all clients) , and client-side methods for the JavaScript Client only. For examples:

Set reference item to $cinst.$container
Do item.$getList() Returns iList
# and
Calculate $cinst.$container().iSelected as iList.C1

Switch Control

The Switch control is like a check box insofar as it represents an On / Off value (1 or zero) but it can display alternative images for the On or Off states. When the end user clicks the switch the value of the control’s variable alternates between 1 and zero so the control is useful for representing preferences which can be Enabled or Disabled. Alternatively, you can use the Native Switch to display on/off values.

The variable you specify in the $dataname property should be a Number or Boolean variable. The $switchon and $switchoff properties let you specify the icon IDs for the images to be used when the switch is either on or off. The properties $justifyhoriz and $justifyvert allow you to justify the contents in the control horizontally or vertically.

Example

There is an example library showing the Switch control with a range of different ON/ OFF images in the Samples section in the Hub in the Studio Browser, and the same app is in the JavaScript Apps Gallery on the Omnis website at: www.omnis.net.

Tab Control

The Tab Control or ‘Tab bar’ allows the end user to select a tab which can correspond to a specific option in your application; the tab control can also be linked to a Paged Pane by setting $linkedobject. The $tabcount property lets you specify the number of tabs; it can be set to zero in design mode, and the number of tabs assigned at runtime using the notation. The $currenttab property specifies which tab is highlighted and its value will change as the end user selects a tab: assigning a new value to this property at runtime will change the highlighted tab.

In design mode, you can specify the properties for a particular tab by making it the “selected tab” in the $selectedtab property, under the “Tab” tab in the Property Manager. The text for a tab is specified in the $tabtext property: you can add a line break by inserting //. The size of the tab (i.e. the width for horizontal tabs) is determined by the width of the text on the tab. However, you can set $fixedtabsize to kTrue to fix the size of the tabs, and set $maxfixedtabsize to set the tab width or height. You can hide or show a tab using the $tabvisible property, and you can disable or enable a tab using $tabenabled; for example, you can set these properties for individual tabs to kFalse in design mode and at runtime set these properties to kTrue to show and enable the tabs.

There are many properties under the Appearance tab in the Property Manager to control the general appearance of the Tab Control and the tabs themselves. The tabs have angular corners by default, but you can round the corners by setting $tabborderradius. You can create a vertical aligned set of tabs by setting the $side property: you can orient the tabs on the left or right. The $tabsjst property determines the position of the tabs within the control.

There is an example app called ‘Tab bar’ in the Samples section in the Hub in the Studio Browser showing how you can link a tab control to a paged pane, as well as using a tab control to display a menu; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

Tab Icons

By default, the tabs display text only, but you can add an icon to the tabs by selecting the position of the text and icon by setting $tablayout. For example, you can set $tablayout to kJSTabsLayoutIconLeft to add an icon to the left of the tab text, and then set $tabiconsize to set the width of the space allowed for the icons.

Reordering Tabs

In design mode, you can move or re-order the tabs in the control by entering a number into the $movetab property; in effect, the number of the selected tab will become the number you entered, and the other tabs are shuffled along. This is useful if you have setup multiple tabs and need to move a tab easily without having to redefine each tab again.

Linking Tabs to Panes

The Tab Control can be linked to a Paged Pane by setting $linkedobject to the name of a Paged Pane control, so when different tabs are clicked, the pane in the linked Paged Pane is changed automatically. Assigning a new value to the $currenttab tab property of the Tab control at runtime will also change the current pane in the linked Paged Pane control.

The base edge of the tab control does not normally have a border, and when the tabs are linked to a paged pane the tab control updates the paged pane border so that there is the appearance of a gap below the current tab. If you want to add a border under the tabs you need to set $baseedgewidth to 1 or more.

Tab Menus

The Tab Control can also be linked to a Remote Menu class; clicking on a tab will trigger the corresponding line in the menu. To implement this, the $trackmenus property must be kTrue, and the $tabmenu property set to the name of a remote menu class for the selected tab (the tab with number $selectedtab). If assigned at runtime, the menu instance must already be present on the client (via a $tabmenu or $contextmenu property in the class data when the form was loaded).

You can control the color of the menu lines and text using the $tabmenu… properties under the Appearance and Text tabs in the Property Manager, or in your code for the control.

Events

When the end user clicks on a tab the value of $currenttab will change and an evTabSelected event is triggered, with the new tab number reported in pTabNumber. This event needs to be enabled in the $events property for the control to be reported.

The $canclickselectedtab property can be enabled so a click on the selected tab generates evTabSelected (provided that evTabSelected is specified in $events). This allows you to detect a click on the currently selected tab (which was not possible in previous versions).

Example

The Contacts sample app users a Tab control in the main jsContacts remote form to allow the end user to switch from viewing a list of contacts to a form showing details of individual contacts. In this case, the Tab control is linked to a page pane which displays the contact list or contact details view. The $linkedobject property of the contactTabStrip control is set to ‘pagePane’ (the name of the page pane) and the $tabtext for each tab is defined as ‘Contacts’ and ‘Details’ respectively. In addition, the evTabSelected event is enabled in the $events property of the Tab control. The code for the Tab control $event method is:

# $event method for Tab control
On evTabSelected
  If pTabNumber=2
    Do method loadRecord (iContactList.$line)
    Do $cinst.$objs.saveBtn.$enabled.$assign(kTrue)
  Else If pTabNumber=1
    Calculate iNewContact as kFalse
    Do $cinst.$objs.saveBtn.$enabled.$assign(kFalse)
  End If

If the Details tab is clicked, the second tab, the second pane in the page pane is displayed and the details for the currently selected contact are loaded using the loadRecord class method.

Timer Control

The Timer is an invisible component that triggers an evTimer event after a specified time while $running is set to kTrue. You can specify a $timervalue, which is interpreted as an interval in seconds or milliseconds according to $useseconds, which should be set to kTrue for seconds or kFalse for milliseconds (the default).

There is an example app 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.

Example

In the Webshop sample app (available under the Applets section in the Hub), it would be possible to use a Timer control to rebuild the Orders list periodically; in this case, you could use the Timer object to run a method at a given interval to rebuild the Orders list in the jsShopOwner remote form. In reality, the Orders list is rebuilt every time a new order is placed, but a Timer object could be used to regulate the rebuilding of the Orders list.

To implement a Timer in the Webshop app, you would need to enable the evTimer event in the $events property of the Timer control. The $useseconds property is set to kTrue and $timervalue is set to 2 (to give an interval of 2 seconds). The $construct() method of the Orders list (a data grid) includes a line of code to start the timer:

# $construct method for Orders list/data grid
Do iOrderList.$definefromsqlclass($tables.T_qOrders)
Do $cinst.$objs.tim.$running.$assign(kTrue## possible using a timer object
Do $cfield.$build()

The $build() method behind the Orders list builds the list when the form is opened, but when used with the Timer object it can be used to rebuild the list as well. The $event method for the Timer object is run every 2 seconds, and has the following code:

On evTimer
  Do $cinst.$objs.dat.$build()

Timer Worker Object

The timer component contains a Worker Object. This has the advantage over the other timer objects in that it can be used with remote tasks in the multi-threaded server. It has the following properties:

  1. $timervalue and $useseconds
    These work as for the current timer objects

  2. $repeat
    If true, then after calling $starttimer() the timer will fire until $stoptimer() is called or the object is deleted;otherwise the timer will fire at most once for each call to $starttimer().A change to $repeat is ignored until the timer is started again

The timer component supports the methods $starttimer() and $stoptimer(). Just like $repeat, changes to $useseconds or $timervalue do not take effect if the timer is already running.

When the timer fires (or the timer is cancelled), Omnis calls the $completed or $cancelled method in the object, just like other worker objects. This occurs in the context of the task that owns the object, and interrupts any code running for that task (after a complete method command has executed).

Toolbar Control

The Toolbar Control allows you to add a series of buttons and an optional menu at the top of a remote form that the end user can click on or tap to perform an action. Each toolbar button can be assigned an icon and text, as well as a different action. When a button is clicked, the item number is reported to the event handling method allowing you to run the appropriate code.

The toolbar is displayed horizontally, by default, but can also be displayed vertically. You can use edgefloat properties to ‘stick’ the toolbar to the top or side of the remote form. It items do not fit on the toolbar they are added to an overflow menu automatically (shown by three vertical dots on the right of the toolbar), or items can be forced to appear on the overflow menu.

A toolbar can have a “side menu”, displayed on the left of the toolbar, by setting $sidemenu to true and adding a list variable name to $dataname containing the menu items. Items in the side menu can have a 'selected' state as well as a 'focused' state. Selecting a line in the side menu sets the current line in the list. The selected line will remain highlighted until another line is selected. When the side menu is opened, the selected line will get the focus.

Example

There is an example app in the Samples section in the Hub in the Studio Browser showing a Toolbar with overflow and a side menu; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net. The example Toolbar has four items or buttons defined, each with an icon and text, the main title ‘Toolbar’ on the left, and an overflow menu on the right.

Items can be forced to always appear in the overflow, regardless of the width of the main toolbar, shown on the right of the toolbar by the three vertical dots, and shown dropped here:

As the browser window is resized, or the remote form (the app) is displayed on a mobile device, the main toolbar width will shrink, and the button items are added to the overflow menu automatically, as shown (note the icons are not displayed when the item is in the overflow menu):

The following image shows the same Toolbar with the side menu added and in the dropped state:

Properties

The custom properties for the Toolbar control are described below. The ‘Item’ tab in the Property Manager contains item specific properties that apply to the $currentitem.

Property Description
$itemcount The number of toolbar items/buttons
$currentitem Item specific properties are assigned to the current item
$moveitem Allows you to move an item in design mode; the current item moves to the position specified by the number entered
$itemiconid The icon for the current item (item specific property); note $showitemicons needs to be enabled to display icons
$itemtext The text for current item (item specific property); note $showitemtext needs to be enabled to display text
$itemoverflow Force the item to be appear in the overflow menu (item specific property)
$itemenabled If kTrue (the default) the item is enabled (item specific property); if kFalse the item is greyed and cannot be selected with the pointer or keyboard; applies to items whether they are on the toolbar itself or the overflow menu
$sidemenu Add a side menu to the toolbar. The $dataname must be a list containing the menu data
$dataname Name of a list variable containing the menu data, to display a menu when $sidemenu is set to true
$verticaltoolbar Display the toolbar in a vertical orientation
$menudirection A kJSToolbarMenuDirection… constant which sets the direction the menu should open. Different values are available depending on the $verticaltoolbar property: Down or Up for horizontal toolbars, Right or Left for vertical toolbars
$toolbartitle The optional title to display on the toolbar; leave this blank for no title
$titlefontsize The font size applied to the toolbar title
$itemwidth The width of items on the toolbar; without a value items have a variable width and are forced to fit the length of the toolbar
$displaystyle A kJSToolbarStyle... constant determining the position of the icon text relative to the icon: either Above, Below, Left of, or Right of the icon
$showitemicons If true, any item with an $itemiconid will display an icon on the toolbar
$showitemtext If true, any item with $itemtext will display text on the toolbar; when true, $showtooltips is disabled
$showtooltips Show tooltips on toolbar items; $showitemtext must be set to false
$showdividers If true, dividers will be shown between toolbar items
$dividercolor The color of the dividers between items if $showdividers is true
$iconcolor The color of standard icons such as the hamburger icon
$sidemenucolor The background color of the side menu
$overflowcolor The background color of the overflow menu
$toolbaractivecolor The color of toolbar items when clicked
$toolbarhovercolor Hover color for toolbar items
$sidemenuhovercolor Hover color for side menu items
$overflowhovercolor Hover color for overflow items
$selecteditem The number of the selected item
$showselecteditem If true, the item will have its background color set to $selectedcolor and its text colour set to $selectedtextcolor.
$selectedcolor The background color of the selected item
$selectedtextcolor The text color of the selected item
$selectedlinecolor The color used for the background of the selected line in the side menu
$toolbarhovertextcolor Text color of toolbar items when hovered
$sidemenutextcolor Text color of side menu items
$sidemenuhovertextcolor Text color of side menu items when hovered
$overflowtextcolor Text color of overflow menu items
$overflowhovertextcolor Text color of overflow menu items when hovered

Clicking on a toolbar item will make that item selected, and $selecteditem is set to the selected item number. If $showselecteditem is true, the item will have its background color set to $selectedcolor and its text color set to $selectedtextcolor.

Disabling Items

The $itemenabled property allows you to disable specific items. When $itemenabled is set to kFalse for an item it is greyed and cannot be selected with the pointer or keyboard. This property applies to items whether they are on the toolbar itself or the overflow menu.

Events

The Toolbar reports two events: evClick reports the toolbar item that was clicked, with pClickedItem returning the item number; and evNavigationClick reports true if an item on the side menu was clicked, with the group number reported in pClickedMenuGroup (zero if the data is ungrouped) and the item number in pClickedMenuItem. You can write event handling code in the $event for the toolbar to trap these events and branch according to the value of pClickedItem or pClickedMenuItem.

Defining the $dataname list

To enable the side menu, you need to set $sidemenu to kTrue and specify a list variable name in $dataname containing the contents of the menu. The $dataname can generate either a grouped or an ungrouped menu.

Ungrouped list columns with each row representing an item:

  1. Text (Character): The text of the menu item.

  2. IconPath (Character): A URL of an image to display. The image will be scaled to fit.

Grouped list columns with each row representing a group:

  1. SubList (List): A list with columns matching the ungrouped list above. Contains data for the group.

  2. GroupName (Character): The text displayed on the group header.

  3. Fixed (Boolean): Optional column. If true, the group is always expanded. False by default.

  4. Collapsed (Boolean): Optional column. If true, the group is collapsed by default. False by default.

Transbutton Control

The TransButton control is like a standard button, but it can display a different icon and/or background color when the end user’s pointer hovers over the control, or when the button is tapped on touch devices. In all other respects the Transbutton is like a standard push button control, insofar as it generates a single evClick event when the button is clicked which can be used as confirmation or to initiate an action in your code using the $event method. Note the evClick event must be enabled in the $events property for the control for it to be reported.

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can use the Trans button, and the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net

Hover Action

The Transbutton has several properties prefixed “$hot” that relate to the appearance of the button for the hover action. You can specify two icons for the Transbutton: one to represent the “off” state which is specified in $iconid, and the other to represent the “over” state which is specified in $hoticonid: if no $hoticonid is specified the icon in $iconid is used which will not provide a hover effect. You can also specify a different background color for the hover action in $hotbackcolor, and an alternative border color in $hotbordercolor.

The icons used in $iconid and $hoticonid can be from an icon set, or #ICONS, or an icon datafile. You can use the standard icon sizes (16x16, 32x32, 48x48 and their 2x equivalents for hi-def support), but you can also use non standard sized images as well, but in this case they can only be sourced from an icon set (and the size should be specified in the file name according to the usual naming). The Transbutton will not draw or position icons from standalone pages in #ICONS or icon datafiles (e.g. omnispic.df1) correctly in the client, since the client cannot determine the icon size from its URL.

You can set $vertical to true to center the button’s content vertically: $align also affects the placement of the icon when $vertical is true.

HTML Button Text

You can specify a label for the button using the $text property which is a single line of plain text. When set to kTrue the $textishtml property specifies that the text in $text is treated as HTML, and therefore any HTML can be used to style the text. For example, you can insert a line break by setting $textishtml to kTrue, and using <br> in $text for the button wherever a line break is required.

The $textishtml property also allows other styling of the button text using various character and color attributes. Note that design mode does not render the HTML (the raw HTML code is displayed), and if you use attributes in the HTML they must be enclosed in single quotes.

Tree List Control

The Tree List Control provides a graphical way of displaying a list of items in a hierarchical format. Each node can have a check box or its own icon. The $dataname property for a tree list is the name of a list variable containing the content (data) and structure of tree list. The list can contain the entire data for a tree list when the form is opened, or the content can be built as nodes are expanded when a tree list is in “dynamic” mode.

There are two example apps in the Samples section in the Hub in the Studio Browser showing how you can create a tree list with check boxes (left) and a dynamic tree structure (right); the same apps are available in the JS Component gallery on the Omnis website at: www.omnis.net

Properties

Tree lists have the following properties:

Property Description
$checkbox If true, and $multipleselect is also true, the tree control has check boxes that can be used to select nodes
$currentnodeident The current node ident for Dynamic tree lists only: see below
$datamode Controls how the list content is used to structure the tree list, a constant: kJSTreeFlatList, kJSTreeFlatListWithTags, kJSTreeFlatListOld, kJSTreeFlatListOldWithTags
$evenrowcolor Specifies the color to be used for every even row in the list of nodes. The kColorDefault setting means use the same color as odd numbered rows ($backcolor).
$extraspace Adds extra space in between the lines in the list; it is the number of pixels added to the normal font height of a row in the list, or zero for no extra space
$iconurlprefix All icons used in the tree (as a result of $showicons being true) must come from a single icon directory; the default is _icons/omnispic/
$lineborder If true, a row border is added between each node
$linebordercolor Specifies the color of the line when $lineborder is true; it uses the value of $bordercolor when set to kColorDefault
$multipleselect If kTrue allows the end user to select more than one line; should be enabled for tree lists with $checkbox enabled
$nodeaction Performs an action on the tree node, only for Dynamic mode: see below
$nodedata List for tree node when building dynamically: see below
$showicons If true, the tree control shows node icons from location in $iconurlprefix
$showlines If true, the tree control displays dotted lines connecting nodes
$twostate If true, and the tree control has checkboxes (see $checkbox), selection of each node is independent

Tree List Format

The format or mode of the data is set in the $datamode property which controls how the list content is used to structure the contents of the tree list. There are several different data modes to format a tree list, as well as the Dynamic mode, represented by the following constants:

  1. kJSTreeFlatList
    The first N columns represent a node in a tree of depth N. The last 5 columns are node properties: iconid,ident(int),expanded(bool),textcolor(zero means $textcolor),tooltip

  2. kJSTreeFlatListWithTags
    The first N columns represent a node in a tree of depth N. The last 7 columns are node properties: iconid,ident(int),expanded(bool),textcolor(zero means $textcolor), tooltip, tag(char), enterable(bool)

  3. kJSTreeFlatListOld
    A list with the same structure as the plug-in client tree kTreeDataFlatList

  4. kJSTreeFlatListOldWithTags
    A list compatible with the plug-in client kTreeDataFlatListWithTags

  5. kJSTreeDynamicLoad
    the tree list content can be built dynamically; see below

Tree Events

When the user selects a node the evClick event is reported, while a double-click reports an evDoubleClick. In both cases, the id and tag of the selected node is reported in the pNodeIdent and pNodeTag parameters. Note you cannot get click or double-click events for nodes which are enterable, as the click puts them into edit mode.

For enterable nodes, the evRenamed event is reported if the end user has renamed the node. evRenamed has node ident, node tag, old name and new name as event parameters.

Scrolling in long lists

Tree lists scroll to view the current line in the list, and any parents opened as necessary, whenever the current line changes or the $currentnodeident property is set. In a non-multiple select tree lists, setting either the current line in the list or the $currentnodeident will select the line and scroll to it. This applies to flat list trees only.

In multiple select tree lists, setting the current line will scroll to that line but will not select it. Setting $currentnodeident notationally will set both the current line and select the node. Tree lists without checkboxes will clear any current selection, but tree lists with checkboxes will not. This behavior mimics the user behaviour of clicking a node.

In multiple select tree lists, the $currentnodeident and the current line in the list can reference different nodes; however, in single select tree lists, they will always reference the same nodes.

Dynamic Tree Lists

The content inside a Tree List Control can be built dynamically as the end user expands a node. In previous versions, the entire contents of the tree list had to be built and sent to the client, including the contents for all unexpanded nodes, which for large lists created quite an overhead. Building the tree list data and displaying content in a tree list can be optimized with the ability to build node contents “on the fly” as required (note there is an example app in the Hub and JS Component gallery).

Creating Dynamic Trees

To use a Tree Control in dynamic mode you need to set its $datamode property to kJSTreeDynamicLoad. Note that dynamic mode can only be used for ‘single-select’ trees, and attempting to assign kJSTreeDynamicLoad to $datamode will fail if $multipleselect or $checkbox for the tree control is kTrue.

As in previous versions, a dynamic tree still requires a list identified by $dataname, but the list need only contain the initial content of the tree, that is, the content for the root or parent nodes. After the list content is changed, the tree reloads its content from the list.

Dynamic trees also use lists to set the content of expanded nodes and to add nodes programmatically to the tree. The lists all have the same structure: each list represents an ordered set of nodes with the same parent (or no parent in the case of the $dataname list), and the columns are as follows:

  1. Column 1: Text. The text displayed for the node.

  2. Column 2: Icon. Only used when $showicons is set to kTrue. This is a line number in the list identified by $nodeiconlist, or zero if the node does not have an icon. $nodeiconlist is described below.

  3. Column 3: Ident. A unique positive integer that identifies the node. Cannot be the same as the ident of any other node in the tree. The tree control throws an exception (resulting in a message box displayed on the client) if you try to use a duplicate ident.

  4. Column 4: Tag. A string associated with the node. Any value that is useful to the developer. Need not be unique.

  5. Column 5: Tooltip. The tooltip string for the node, displayed when the user hovers the mouse over the node. Leave empty for no tooltip, although on some browsers nodes may inherit their tooltip from their parent node if the tooltip is empty.

  6. Column 6: Text color. The text color for the node (an integer RGB value). Zero means use the $textcolor of the tree.

  7. Column 7: Flags. Integer flags. A sum of zero or more of the following constants:

  1. kJSTreeFlagEnterable. The node text can be edited (this works with the existing evRenamed event).

  2. kJSTreeFlagHasChildren. The node has children.

  3. kJSTreeFlagExpanded. The node will be immediately expanded. If you set this flag you must supply the child nodes using a node list supplied as the children column.

  4. kJSTreeFlagDiscardOnCollapse. If set, when the user collapses the node, the tree deletes the node contents. This means that the next time the user expands the node, the tree will generate an evLoadNode event; evLoadNode is described later in this document.

  1. Column 8: Children. If the kJSTreeFlagHasChildren is present, you can pre-populate the node content by using a nested list to specify the children. If you do not supply any children using this list, then you can supply them later by using the evLoadNode event (see below). The content of this column is ignored if the kJSTreeFlagHasChildren is not present. You can nest children lists arbitrarily deep (within reason).

$nodeiconlist allows you to specify the icons to be used with the tree. These must be available when the tree is updated from the dataname list. $nodeiconlist must be the name of an instance variable list with at least one column which must be a character column containing icon URLs. You can populate each URL in the node icon list using the iconurl() function, for example:

Do iNodeIcons.$define(iNodeIcon)
Do iNodeIcons.$add(iconurl(1710))
Do iNodeIcons.$add(iconurl(1711))
Do iNodeIcons.$add(iconurl(1712))

Populating Expanded Nodes

Dynamic trees have the event evLoadNode which allows you to populate the tree on demand, by only populating node content when a node is expanded. When using the kJSTreeDynamicLoad mode for $datamode, evLoadNode is generated so that you can set the content of the node by setting the $nodedata property which is the name of a list containing the expanded node content. For other settings of $datamode, evLoadNode is generated when the user expands a tree node.

The evLoadNode event has two parameters, pNodeIdent and pNodeTag, corresponding to the node that is being expanded. In the event processing for evLoadNode, you can set a new tree property, $nodedata, to a node list representing the content of the node (with the above column format); if the event processing fails to set this property, the tree control sets the node content to empty.

The list assigned to $nodedata can specify nested children if desired.

$nodedata is a runtime-only property that can only be set.

Manipulating Tree Nodes

Dynamic trees support ‘node actions’ to allow you to manipulate the nodes in a Tree List programmatically. For example, you can expand or collapse a node, and you can add, delete or rename modes. You execute a node action by assigning a row variable to the $nodeaction property of the tree. The supported actions are as follows:

  1. kJSTreeActionExpand
    row(kJSTreeActionExpand, ident). Expands the node with the specified ident if it is not already expanded.

  2. kJSTreeActionCollapse
    row(kJSTreeActionCollapse, ident). Collapses the node with the specified ident if it is not already collapsed.

  3. kJSTreeActionRename
    row(kJSTreeActionRename, ident, newname). Renames the node with the specified ident to the new name.

  4. kJSTreeActionDelete
    row(kJSTreeActionDelete, ident). Deletes the node with the specified ident (also recursively deletes node children). If the current node is deleted, an evClick event will be generated to inform the application of the new current node.

  5. kJSTreeActionAdd
    row(kJSTreeActionAdd, ident, position, nodelist). Adds the nodes in the nodelist to the tree, where ident specifies the parent node of the nodes in nodelist; to add a new root nodes specify ident as zero. The position parameter can be one of:

  1. -1 to add the new nodes before any existing children of the node specified by ident

  2. 0 to add the new nodes after any existing children of the node specified by ident

  3. a child node ident. New nodes are added after the child node with this ident. If no such node exists, the new nodes are added after any existing children.

$nodeaction is a runtime-only property that can only be set.

Collapsing a Node

The tree control now generates evCollapseNode when the user collapses a node. This applies to all trees, not just dynamic trees.

The Current Node

The current (selected) node in the tree is no longer represented by a list line. Instead, there is a new property, $currentnodeident that applies to dynamic trees. When the user changes $currentnodeident (by clicking on a node), the control generates evClick. In addition, the developer can assign $currentnodeident (and read its value in client-executed methods). $currentnodeident is a runtime-only property.

Video Control

The Video control allows you to play a video within your remote form. The video can be hosted on YouTube or you can play a video via the HTML5 video support in the browser. The JS Video control has the following properties:

Property Description
$dataname

If $youtube=kFalse, this is a 2 columned list containing the location and type of the videos to be played: Column 1 is the URL of the video file; Column 2 is the media types

If $youtube=kTrue, this is a list containing the IDs of the YouTube videos to be played; only Column 1 of the list is used and contains the ID of the YouTube video

$showcontrols If true, the control displays video controls such as the Play and Pause buttons
$youtube

If true, the control will play a movie from youtube.com; column 1 of the $dataname list is the YouTube video id

If false, the control will use HTML5 video to play video files from URLs

$startposition The time (in seconds) at which the video should start when played
$currentposition (Runtime only) The current time (in seconds) of the current position in the video. Assign to this to ‘seek’ to a particular time
$duration (Runtime only) The duration of the current video (in seconds). Read-only (in a client-exec method)
$poster A URL to an image to display before the first frame of the video is ready. HTML5 video only ($youtube=kFalse)
$playing Whether the video is currently playing. Assign to this in order to play or pause the video. Note that many mobile devices prevent the playing of videos if not in direct response to a user action
$volume The volume level of the video player (0-100). Assigning 0 will mute the player
$playbackrate The video's playback speed, with 1.0 being default speed. Youtube will round down to the closest supported rate of the particular video
$requestcaptions If true, closed captions will be turned on (when available, attempting to use the client's language) for Youtube videos. Note that even if disabled, captions may be enabled through the video controls, or through the user’s account settings in Youtube (if they are signed in)

Properties relating to the current video player ($currentposition, $duration, $volume) will return -1 if queried before a video is ‘ready’ (see evVideoReady).

YouTube

If you set the $youtube property to kTrue, the $dataname for the video control should be a list containing YouTube ids: the data in the first column of the first row in the list is used to reference the video on YouTube. Note the YouTube id is not the full URL on youtube.com, but just the id on the end of the URL, e.g. 'Ff-qlTlSkc0'.

Playlists

If the list assigned to a Youtube video control ($youtube = ktrue) has more than one line, a YouTube playlist will be created, using the video IDs supplied in each line of the list. The videos in the playlist will be played successively.

If $showcontrols is true, the playlist can be accessed via the video controls in the UI. You could notationally skip to the next video by skipping to the end of the current video. For example, using the client-executed method:

Calculate $cinst.$objs.youtubeVideo.$currentposition as $cinst.$objs.youtubeVideo.$duration

HTML5

If you set $youtube to kFalse, the $dataname should be a 2 column list. The first column should contain URLs to the video files, located somewhere on the internet or the Omnis App Server, and the second column should state the media type. For example:

Do iList.$define('VideoURL','VideoType')
Do iList.$add('videos/myVideo.mp4','video/mp4')
Do iList.$add('videos/myVideo.ogv','video/ogg')
Do iList.$add('videos/myVideo.webm','video/webm')

Not all browsers are able to play all video file types, so you should provide the video in multiple formats and populate the list with the URL to each file and type. When the client connects, the browser will play the first video file it is able to play from the list.

Events

The JS Video control has the following events:

  1. evVideoReady
    Sent when the video is ready to be played, and can be interacted with.

  2. evVideoEnded
    Sent when the video has finished playing (i.e. it has played to the end).

Both events receive a pVideoURL parameter, describing the currently playing video. For HTML5 videos ($youtube = kFalse), this will be a URL to the video file. For Youtube videos ($youtube = kTrue), this will be the Youtube video ID. These should correspond to a value in the list assigned to the control’s $dataname.

External Components

iCalendar

The iCalendar external component allows you to load and manage calendar events: it is a non-visual External Component that you can use in your Remote Forms (or window classes). iCalendar allows you to read, write and modify objects based on the standard iCalendar format, which is supported by many third-party calendar products.

The iCalendar model is based on four object types:

  1. Component: A group containing Properties which represent, for example, an event. Components can contain other Components (sub-components).

  2. Property: Used to communicate information about a Component, such as a description or a location.

  3. Value: Properties have a value associated with them. For example, a DTSTART Property will have a date or datetime value.

  4. Parameter: A modifier for a Property. Properties may have more than one Parameter (or none).

There are two types of object in the Omnis iCalendar external component:

  1. Document: Represents the entire Document and its children.

  2. Component: Used to access and manipulate iCalendar Components and their associated Properties and Parameters.

To access the iCalendar objects & methods, you need to create an instance variable in your remote form (or window class), choose Object as its Type, under Subtype drop down the Select object dialog, open the ‘iCalendar Objects’ group and select ‘Document’ object.

Working with iCalendar files

iCalendar Documents can be initialised with character data, or built up with the Omnis iCalendar methods.

To load an iCalendar file into a Document object, use FileOps to read in the character data. Then use $initwithdata() to initialise the document.

 Do FileOps.$getfilename(lPath,"Select ics file","*.ics")
 Do lFileOps.$openfile(lPath,kTrue)
 Do lFileOps.$readcharacter(kUniTypeUTF8,iCalText)
 Do lFileOps.$closefile()
 Do lDoc.$initwithdata(iCalText)

To output the character data, use $getdata() on the Document or a single Component. To save the data into a file, use FileOps.

 Calculate lDocText as iNewDoc.$getdata()
 Do FileOps.$putfilename(lPath,,"*.ics")
 Do lFileOps.$createfile(lPath)
 Do lFileOps.$openfile(lPath)
 Do lFileOps.$writecharacter(kUniTypeUTF8,lDocText)
 Do lFileOps.$closefile()

Updating sub-components

The functions $getcomponent() and $getsubcomponent() return a copy of a Component. Therefore, modifying the returned Component will not affect the parent (the Component or Document that the method was called on). In order to update the parent, Component copy will need to be saved back to the parent with $replacerootcomponent() or $replacesubcomponent().

Custom Properties

As well as the standard Property types, custom Properties can be added to Components. These must be prefixed with “X-”, e.g. “X-PROPERTY”. By default, the data type of a custom Property is character. When adding a Property to a Component with $addproperty(), the optional iDataType Parameter can be used to override the default data type. Doing so will set the “VALUE” Parameter to the data type associated with the constant. The data type cannot be changed after it has been created.

Custom Parameters

Like custom Properties, custom Parameters can be applied to Properties. Similarly, they must also have “X-” as a prefix.

Error Properties

When a Document is initialised with $initwithdata(), the character data is parsed. If there are any syntactic or semantic errors in the data, such as a misspelt Property name or a Property without a value, an X-LIC- error Property will be inserted. For example, the following error is caused by misspelling the ATTENDEE Property:

X-LIC-ERROR;X-LIC-ERRORTYPE=PROPERTY-PARSE-ERROR:Parse error in property name: ATENDEE

Special Values

These values contain multiple parts and are therefore represented as rows. The static $createrow() helper method can be used to build these rows, which can be used to create a new Property or update a value.

Recur

The “RECUR” value type in the iCalendar model denotes a recurring event. It is commonly used with the “RRULE” Property. Its value may contain several parts, separated by semicolons. The parts contain key value pairs separated by the equals sign. The example shows a Recurrence Rule property.

RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z

A Component’s $propertylist will store an RRULE Property as a rows containing columns relating to each keyword. To create an RRULE Property with $addproperty(), the vValue parameter can take either a character or row argument. To create a recurrence type row, use $createrow(kICalendarRowTypeRecur).

Duration

The “DURATION” value type is represented in a component’s $propertylist as a row. The columns are: IS_NEGATIVE, DAYS, WEEKS, HOURS, MINUTES and SECONDS. To add a Property with a duration type, a row containing these column names can be used. The column values are all Integers, with the exception of IS_NEGATIVE, which is a Boolean. Alternatively, a string can passed. For example, P15DT5H0M20S denotes a duration of 15 days, 5 hours, and 20 seconds. See the RFC 5545 iCalendar specification for details on this format (https://tools.ietf.org/html/rfc5545#section-3.3.6).

Period

“PERIOD” value types have two parts: The first is the start time (date time). The second can either be the end of the period (date time), or a duration. Period is the default value type of the Free/Busy Property. In the $propertylist, period values are displayed as a row containing a START date time and either a DURATION or an END date time.

19970101T180000Z/19970102T070000Z date time “/” date time (Explicit)

19970101T180000Z/PT5H30M date time “/” duration (Start)

Geo

“GEO” Properties hold geographic coordinates, represented as two floats separated by a semicolon. The values are latitude and longitude respectively, e.g. 37.386013;-122.082932.

In the $propertylist of a Component, they are displayed as a row containing a LAT and a LONG column with float values.

Static Methods

$createcomponent()

OmnisICalendar.$createcomponent(iType)

Creates a new iCalendar Component object using one of the kICalendarComponent... constants. Returns an iCalendar component object.

  1. iType: A kICalendarComponent... constant to specify the Component type.

$createrow()

OmnisICalendar.$createrow(iType)

Returns a row which can be used to add or update certain Properties. iType can be one of the kICalendarRowType... constants.

  1. iType: A kICalendarRowType... constant to specify the type of row.

Document Object Methods

$initwithdata()

$initwithdata(cData)

Initializes the object with the Character contents of an iCalendar file. Returns true if successful.

  1. cData: The character data containing the contents of an iCalendar file.

$getdata()

$getdata() - no parameters

Returns character data representing the Document that can be saved as an iCalendar file.

$getcomponent()

$getcomponent(iComponentId)

Returns a copy of the root Component object with the specified ID.

  1. iComponentId: The ID of the root Component to find.

$addrootcomponent()

$addrootcomponent(oComponent)

Adds a Component to the root of the Document. Returns the ID of the new Component.

  1. oComponent: The Component to be added to the root.

$deleterootcomponent()

$deleterootcomponent(iComponentId)

Removes the Component with the specified ID from the root. Returns true if the Component was deleted.

  1. iComponentId: The ID of the Component to delete.

$replacerootcomponent()

$replacerootcomponent(iComponentId, oComponent)

Replaces the Component at the specified ID with oComponent. Returns true if successful.

  1. iComponentId: The ID of the Component to replace.

  2. oComponent: The new Component.

Document Object Properties

$componentlist

A list of root-level Component info for the Document. The columns for this list are: ID, Type and TypeName.

Component Object Methods

$getdata()

$getdata() - no parameters

Returns character data representing the Component and its children, that can be saved as an iCalendar file.

$isvalidcalendar()

$isvalidcalendar() - no parameters

Returns true if the VCALENDAR Component meets the RFC 5546 iCalendar specification standards.

$getsubcomponent()

$getsubcomponent(iComponentId)

Returns a copy of the sub-component object with the specified ID.

  1. iComponentId: The ID of the sub-component to find.

$addsubcomponent()

$addsubcomponent(oComponent)

Adds a sub-component to the Component. Returns the ID of the new Component.

  1. oComponent: The sub-component to be added to the Component.

$deletesubcomponent()

$deletesubcomponent(iComponentId)

Removes the sub-component with the specified ID from the component. Returns true if the sub-component was deleted.

  1. iComponentId: The ID of the Component to delete.

$replacesubcomponent()

$replacesubcomponent(iComponentId, oComponent)

Replaces the Component at the specified ID with oComponent. Returns true if successful.

  1. iComponentId: The ID of the Component to replace.

  2. oComponent: The new Component.

$addproperty()

$addproperty(cName, vValue, [wParameters, iDataType])

Adds a new Property to the Component. Returns the Property ID.

  1. cName: The name of the Property. Must be a valid Property type.

  2. vValue: The value to assign to the Property. The type can be Character, Integer, Date Time, Float, Boolean or Row.

  3. wParameters: A row of Parameters to add to the Property.

  4. iDataType: A kICalendarDataType... constant. Sets the 'VALUE' Parameter which overrides the default data type for the Property. Can be used to specify the type of a custom Property.

$deleteproperty()

$deleteproperty(iPropertyId)

Delete the Property with the specified ID. Returns true if the Property was deleted.

  1. iPropertyId: The ID of the Property to delete.

$setparameter()

$setparameter(iPropertyId, cName, cValue)

Sets the Parameter of the Property. If there is an existing Parameter with the same name, it will be overwritten. Returns true if successful.

  1. iPropertyId: The ID of the Property associated with the Parameter.

  2. cName: The name of the Parameter to set.

  3. cValue: The value to set the Parameter to.

$updateproperty()

$updateproperty(iPropertyId, vValue, [wParameters])

Updates the Property with the specified ID. Providing Parameters will overwrite any existing ones. Returns true if successful.

  1. iPropertyId: The ID of the Property to update.

  2. vValue: The new value to assign to the Property. The type can be Character, Integer, Date Time, Float, Boolean or Row.

  3. wParameters: A row of Parameters to add to the Property.

$deleteparameter()

$deleteparameter(iPropertyId, cName)

Removes the Parameter with the name cParamName from the Property. Returns true if the Parameter was deleted.

  1. iPropertyId: The ID of the Property associated with the Parameter.

  2. cName: The name of the Parameter to delete.

Component Object Properties

$componentlist

A list of sub-component info for the Component. The columns for this list are: ID, Type and TypeName.

$propertylist

A list of iCalendar Properties held by this Component. The columns for this list are: ID, PropertyName and PropertyValue. The PropertyValue column contains a row for each Property. Each row has a “_VALUE” column containing the Property value (the type of this depends on the Property), and columns for any Parameters that the Property has.

$typename

The type name of the Component.

$typenumber

The type number of the Component.