Release Notes for Alpha Anywhere (Alpha Five Version 12)

This document describes the updates and fixes made to Alpha Anywhere since its initial release.

To see the 'What's New in V12' document (which describes all of the new features in Alpha Anywhere's initial release) please click here.

 

Please note that Alpha Anywhere patches are only available to users with a current subscription.
 

You can verify your subscription status from within Alpha Anywhere by going to Help, About, or by clicking this link shown here (https://activation.alphasoftware.com/subscriptionStatus.aspx). If you install an update for which your subscription is not entitled, you will need to uninstall the update and rollback to an older version that you are authorized to use in order to continue using Alpha Anywhere.
 

The 'Pre-Release' Build

In addition to the official updates that Alpha Software makes available from time to time (which are described in this document), we also make available our internal pre-release builds that allow you to see what features have been added and what bugs have been fixed since the last official update. The features and bug fixes in the pre-release build will be part of the next official update. To see the pre-release notes, please click here.

 

Alpha Anywhere V3.5 - Build 2999-4519 28-Jul-2015

Bugs

UX Component - Captcha Controls - Captcha control got broken in build 2970. This is now fixed.

Editors - Horizontal Scroll Bar - Various editors in the Development version (e.g. code editor, CSS editor, etc.) did not automatically display a horizontal scroll bar if the current line in the editor too long to display in the window.

 

Alpha Anywhere V3.5 - Build 2991-4518 24-Jul-2015

Features

CSS Icons - Google Material Design Icons - The open source Google Material Design icon set is now included with Alpha Anywhere. When you select an image, and you select the 'Css Icon' category, in addition to the built-in 'FontAwesome' category, there is now a new category called 'MaterialIcons'. There are over 700 icons in the Material Design icon set.

Bugs

UX Component - List Control - Custom Data Source - Pagination - Fetch More - If the Xbasic function for the custom data source set the e.fatalError flag to .t. the 'Fetch More' button in the List was not turned off.

Trial Version of Alpha Anywhere - If a user was using Alpha Anywhere in trial mode (i.e. they did not have a license key), certain features of the product that should have been enabled were incorrectly disabled.

 

 

Alpha Anywhere V3.5 - Build 2988-4516 22-Jul-2015

Features

UX Component - PhoneGap Applications - Setting Default Properties for the PhoneGap Genie - When you build a PhoneGap application it is critical that you turn on all of the required plug-ins for your application in the PhoneGap Build Project Settings genie.

Now, a new property in the UX Builder allows you to specify that certain PhoneGap settings should be automatically set when a PhoneGap application is built using a particular component.

 

 

When you click the smart field for the PhoneGap default settings property, a dialog is shown where you can set certain PhoneGap Builder properties. When you open the PhoneGap genie, the corresponding properties in the builder will automatically be set.

 

 

UX Component - List Builder - Refresh Database Schema - By default when you edit a List that is based on one or more SQL tables, the database schema information is refreshed every time you click OK to exit the List builder. In most cases, if your database is local, the time taken to refresh the database schema is negligible. However, if your List is based on one or more tables in a remote SQL database, the time taken to refresh the schema can be significant.

A new property Automatically refresh database schema on edit allows you to turn off the automatic refresh of schema information when the List builder is opened. If you subsequently change the structure of any of the tables that the List is based on you should click the 'Refresh Database Schema' link shown below.

 

 

 

 type::Definition::Exists() - Check if a namespace exists - Check if a type in a specified namespace exists.

Syntax

L flag =  type::Definition::Exists("mynamespace::mytype")
 

This method is particularly useful for checking if a .NET dll has been successfully registered.

 

UX Component - List Control - SQL Data Source - Group By in SQL - Filter List - If a List control is based on a SQL statement that uses the GROUP BY clause and the UX contains a button to filter the list, if a filter is defined on any of the summary fields in the SQL statement, an appropriate HAVING clause will now be generated.

 

UX and Grid Component - Class Name Selector - Filter - When you bring up the Class Name selector dialog you can now filter the list of CSS class names to make finding the class name you want easier.

 

 

Bugs

 

UX and Grid Component - Javascript Actions - Filter List Of Actions - If you opened the Javascript Actions dialog and you applied a filter to filter the list of actions shown in the window, then clicked the OK button without first clearing the filter, the actions that were excluded by the filter were permanently deleted.

UX Component - Pre-render at Design-Time - {dialog.object}.getParentObject() - If a child UX (that is pre-rendered at design-time) was opened by a parent Grid or UX component, the {dialog.object}.getParentObject() method did not return the correct value.

UX Component - Pre-render at Design-Time - Session Timeout Warning - Was not working if the UX was pre-rendered at design-time.

UX Component - Pre-render at Design Time - 3rd Party CSS Icons - Working Preview - If your UX included any 3rd party CSS icons (e.g. FontAwesome, Fontello, etc.) these icons did not display in working preview if the UX was pre-rendered at design-time.

UX Component - Spin Lists - Percentage Width - If the width of a Spin List control was set to a percentage value (e.g. 50%), the width setting was not correctly applied. NOTE: To see the fix you will need to edit any property on the Spin List control to cause the generated code to be recalculated.

 

Tips

UX Component - Google Map - Getting a Pointer to the Low Level Map Object - The UX component allows you to place a Map control on the UX. Alpha Anywhere creates a map object that has many methods (such as placing markers on the map). Behind the scenes, the Alpha Anywhere map object just calls methods of the underlying Google Map object.

In some cases you might want to get a pointer to the underlying Google map object so that you can invoke methods on it directly. For example, you might have read about some feature in the Google Map API documentation that is not implemented in the Alpha Anywhere map object. Getting a pointer to the underlying Google Map object will allow you to implement any feature you might read about in the Google Map API documentation.

 

Here is how you can get a pointer to the Google Map object:

 

// get a pointer to the Alpha Anywhere map object

//assume your map control is called 'MYMAP1'

var mObj = {dialog.object}.getControl('MYMAP1');

//now get a pointer to the underlying Google Map object

var gMap = mObj.map;



 

 

 

Alpha Anywhere V3.5 - Build 2970-4510 14-Jul-2015

 

Videos

UX Component File Upload to Amazon S3 Storage Amazon S3 is a popular service for storing files. In this video we show how you can build a UX component that allows a user to upload files from their machine directly to S3 storage.


Watch Video - Part 1
Watch Video - Part 2
Download Component

Date added: 2014-12-31

In this next vide we show how you can make an Ajax callback after all of the files have been uploaded. By making an Ajax Callback this action can be used as a replacement for the 'File Upload - User Defined' action in Action Javascript:

Watch Video - Part 1
UX and Grid Component Image Upload When you use the Image Upload action in Action Javascript to upload an image to an image field in a database you now have the option of uploading the image to Amazon S3 storage, rather than to a folder on the Alpha Server.

This video shows how to set up image upload to Amazon S3 and discusses some of the benefits of upload to images to Amazon S3, rather than to the Alpha Anywhere server that is hosting your application.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

Date added: 2015-01-28
UX Component Applying Security Client-Side A common pattern in applications is to control the visibility (or enabled state) of certain controls on a page based on the 'role' that the user has in the application security framework. For example, a button might only be visible to users in the 'Administration' role.

Typically, the security settings are enforced server-side. But in some situations you might want to enforce the security rules on the client-side.

In this video we show how controls in a UX can be shown/hidden client-side based on the user's role.

Watch Video - Part 1
Watch Video - Part 2
Download Component

Date added: 2015-02-06
UX Component - List Control Exporting Data in List to Excel or Ascii Files A popular feature in the Grid component is the ability to export the data in the Grid query to an Excel or Ascii file. The UX component List control also allows the data in the List to be exported to Excel or Ascii. When you export data from a List you can either export the data currently shown in the List, or the data in the query that the List is based on. Setting up the code to export the List data is easily done using Action Javascript.

In this video we show how the data in a List and in a List query can be exported to Excel.

Watch Video
Download Component

Date added: 2015-02-09
UX Component 'File Upload' Action in Action Javascript This video shows how you can configure the UX component to upload a file to the Alpha Anywhere server and then store the filename of the uploaded file in a character field in the table to which the UX component is data bound.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-02-15
UX Component 'File Upload' Action in Action Javascript - Uploading to Amazon S3 This video shows how you can configure the UX component to upload a file to Amazon S3 storage and then store the object name of the S3 object in a character field in the table to which the UX component is data bound.

TIP: It is recommended that you watch these videos (Watch Video - Part 1    Watch Video - Part 2 ) which discuss uploading files to the Alpha Anywhere server (as opposed to Amazon S3) before watching this video.


Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-02-15
UX Component File Download from Amazon S3 This video shows how you can use the File Download action in Action Javascript to download files that were previously uploaded to Amazon S3 storage.

The video discusses the two different download modes - 'Indirect' (in which the Alpha Anywhere server retrieves the file from S3 and then sends it to the client) and the much more efficient 'Direct' mode (in which the file is downloaded to the client directly from Amazon S3 storage, thus placing minimal load on the Alpha Anywhere server).


Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-02-15
UX Component File Upload to Amazon S3 Storage - Ajax Callback On Complete When all files have been uploaded to S3 a Javascript event is fired, but there is no property in the builder that allows you to specify the name of an Xbasic function to execute.

In this video we show how an Ajax callback can be made after all of the files have been uploaded to S3. The Xbasic function that handles the callback gets passed an array with the names of all of the files that were uploaded.

A typical use case for this technique would be to store the name of the files that were uploaded in some database on the server.

Watch Video - Part 1

Date added: 2015-02-18
UX Component Stripe Checkout The Stripe API allows you to use the popular Stripe service to process credit card transactions.

Watch Video
Download Component

Date added: 2015-04-01
UX Component - List Control Client-side Summary Values - Aligning Summaries with List Columns The List control allows you to insert client-side group breaks in a List and to display summary values in the group headers and footers. In a columnar List layout you typically want to align these summary values with the appropriate List columns.

In this video we show how a genie can generate the necessary Javascript to make it easy to align the summary data with the corresponding List column.

Watch Video
Download Component

Requires build 4465 or above
Date added: 2015-04-07
Reports Linked Reports The Alpha Anywhere report writer lets you create 'Linked reports'. A linked report is a report that is embedded inside a parent report and linked on some common fields. Linked reports can themselves also contain other linked reports.

In this video we take a simple database that has a 'customer', 'orders' and 'payments' table and create reports on each of these tables. We then link the 'orders' and 'payments' reports into the parent 'customer' report.

When you use linked reports you will often want to reference fields values in the linked reports from the parent report. The video shows how this is done by computing the net amount due for each customer, which is the total for their orders minus the total for their payments.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4

Download Files

Requires build 4469 or above
Date added: 2015-04-17
UX Component - List Control Using the a5-item Template Item Attribute to Add Custom Event Handler to the List Row Template Each row in a List control is rendered by merging data into a row template. The row template is standard HTML which you are free to edit. You can include events in the HTML, but adding onClick and other events directly into the HTML template is not efficient and does not work well on touch enabled devices. A much better solution is to use 'template items' to add custom events to the HTML template.

In this video we show how the a5-item attribute can be added to the HTML template and how you can define event handlers for these 'template items'.

Watch Video

Requires build 4473 or above
Date added: 2015-04-17
UX Component - List Control Field Level Events - Adding Events for Click, Double Click and Right Click on a Field in a List The List control has several events that fire when the user clicks, double clicks, taps, etc. on a List row. Now there are additional events that fire when the user clicks, double clicks or right clicks on individual fields in a List. The onFieldClick event fires when the user click on a column in a particular row of the List. The event handler that get called is passed an object with the row number of the row, the name of the field and the value of the field that was clicked.


Watch Video

Requires build 4473 or above
Date added: 2015-04-17
Grid Component Master Template - Tabs - Controlling Active Tab with Javascript When you build a Grid component you can specify that the Grid parts (Search, Grid and Detail View) should be shown in a Master Template. There are several pre-defined Master Templates that you can choose from. For example, you can choose a template that puts each Grid part in its own tab.

In this video we show how you can use Javascript to automatically control which tab has focus. For example, after the user does a search you would want the Grid tab to have focus. After the user clicks on a row in the Grid to show the Detail View for that row, you would want the Detail View tab to have focus.

Watch Video
Download Component (requires a connection string called Northwind that connects to the sample Northwind database).

Date added: 2015-04-28
Grid Component Adding 'Genie-Style' Tabs to the Detail View When you build a Grid component you can specify that the Detail View fields should be shown in a Tab Control. A common design pattern with tabs is to hide the tab buttons and instead display Next and Previous buttons that allow the user to step through the tabs one at a time.

This style of moving from tab pane to pane by clicking Next and Previous buttons is called 'Genie-style' tabs.

The Grid does not have a built-in option for creating 'Genie-style' tabs (unlike the UX, which does), but with a small amount of Javascript you can add this feature to the Grid, as shown in the video.


Watch Video
Download Component (requires a connection string called Northwind that connects to the sample Northwind database).

Date added: 2015-04-28
UX Component - List Control Disconnected Applications - Compressing Data Before Storing it in Local Storage When you build applications that are designed to work while disconnected, the data in the List controls in your UX component are persisted to Local Storage. There is a limit to the amount of data that can be put into Local Storage. The limit varies by browser, but it typically in the 5MB range.

By compressing the data before it is put into Local Storage you can store more data. In this video we show how to turn the compression feature on and how to measure the impact of data compression.

Watch Video
UX Component Using Date Variables in Client-side Calculated Fields When you define a client-side calculated field expression in a UX and a fields in the expression is a 'Date' type field, it is important to understand what goes on behind the scenes. Alpha Anywhere converts the date string into a Javascript date object, which enables date calculations in your client-side calculated expression.

This video explains some of the subtleties when working with 'Date' type fields in client-side calculated fields.

Watch Video - Part 1
Watch Video - Part 2

Addendum. In the video we describe how the formatDate() function should be defined. Under some circumstances the formatDate() function, as defined in the video, will give an error because the code that adds the .toFormat() method to the date object has not yet executed. The modified version of the formatDate() function, shown below, can be used instead:

function formatDate(dt) {
       var fmt = A5.__dtfmt + ' ' + A5.__tfmt;
       try{
                return dt.toFormat(fmt);
       } catch(err) { }
}


Date added: 2015-06-26
UX Component - List Control Capturing Photos in a Disconnected Application  when using PhoneGap If your disconnected application runs in a PhoneGap shell then you can capture a large number of photos while you are disconnected without being constrained by the amount of Local Storage available on a device. You can also load photos onto your device so that they are available while you are disconnected.

In this video we show how photo capture works in a PhoneGap application when the option to use the file system on the device is enabled.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

We also show how the List control is configured to use PhoneGap and the file system on the device:

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

Date added: 2015-07-07
     

 

 

 

Features

UX Component - Methods - {dialog.Object}.refreshClientSideComputations([flagSynchronous]) Method - Now takes an optional flag to indicate whether the refresh should be synchronous or asynchronous. By default, this method now executes asynchronously and the refresh is delayed for 300ms. The reason for changing the behavior of this method to be asynchronous is to prevent multiple calls to this method within a very short time from degrading performance of a UX component (especially in the case where the UX has a lot of watch expressions or the UX is running on a mobile device - which will have a relatively slow processor compared with a desktop machine). If multiple calls to the method are made within a 300ms window, only the last call is now executed - unless the calls are made with the flagSynchronous flag set to true.

 

Application Server - Open SSL - Updates to OPenSSL 1.0.1p

PhoneGap - UX Component with Child UX Components - Pre-render at Design-time - When you build a PhoneGap application you specify the name of the UX component that is the 'start-up' component. This is the UX that is loaded when the user taps on the application icon on the device home screen. Since the start-up component is physically part of the PhoneGap app, the application can be launched regardless of whether the mobile device has a connection or not.

A common design pattern is for this start up component to call child UX components. These child UX components can either be embedded into the start-up component (for example on a Panel Card that is not initially visible) or might be displayed in pop-up windows. These child components are loaded by making an Ajax callback to the server.

However, if you do not have a connection, you will not be able to make the callback to load the child component.

Now, when you add an embedded object to a UX, or when you use Action Javascript to define an event to open a child UX, you can specify that the child-UX should be pre-computed.

In the image below, the new property (Method for opening UX in a PhoneGap or Static HTML application) for an embedded object is shown in the Optimizations (PhoneGap/Static HTML) section.

 

 

A similar property is also available in the Action Javascript builder for opening a child UX.

 

 

The options for this property are:

Benefits of the Pre-computed Method

The primary benefit of the precomputed method is speed. No callback is necessary, so the child UX will load very quickly.

Limitations of the Pre-computed Method

Since the child UX component is pre-computed at the time the PhoneGap application (or Static HTML) application is build, there is no concept of what the user's security groups are and what the value of any session variables are. Therefore this option is not appropriate if you have any server-side show/hide expressions, or if certain controls have associated security settings. Also, any data in the component will have been rendered at design-time so you may need to write Javascript code to set certain control values in the child UX after it has been rendered.

 

 

PhoneGap - Action Javascript - Working with Files - New actions have been added to Action Javascript that make it easy to work files files in the file system of a mobile device. The new actions are:

 

PhoneGap - File Upload Action - Action Javascript - Uploads files from the file system on a mobile device to a server.

When you select this action, the following dialog appears:

 

IMPORTANT: Your PhoneGap application must include the Device, File, File Transfer plug ins.

 

Properties of note in this builder include:

If you select multiple files to upload, the files are uploaded asynchronously. Each selected file has its on 'On Upload Complete' event. There is also an 'On Upload Complete' event that is fired once all selected files have been uploaded.
If you upload files to the Alpha Anywhere server, you can specify an Xbasic function to call after each file has been uploaded.

 

 

PhoneGap - File Download Action - Action Javascript  - Downloads files from a remote server and stores the files in the file system a mobile device.

When you select this action, the following dialog appears:

 

 

 

IMPORTANT: Your PhoneGap application must include the Device, File, File Transfer plug ins.

 

Properties of note in this builder include:

 

PhoneGap - File System Action - Action Javascript - A collection of actions that make working with files in the mobile device file system easier.

When you choose this action, you can select from the following list of file system actions:

 

 

 

Note: All PhoneGap file system actions are asynchronous. When you define any of these actions you specify a success function that gets called once the PhoneGap action has successfully completed.

 

List Control - Detail View - Photos in PhoneGap Applications - Previously, when you built a disconnected application (using List controls with associated Detail Views) you were limited as to how many photos you could capture while you were disconnected because the photos had to be stored (as base64 encoded data) in the browser's Local Storage cache until a connection was available and you could synchronize the data. On most mobile devices, Local Storage is limited to about 5MB.

Also, if the data you were loading from your server onto a mobile device contained photos, the number of records you could retrieve from the server and keep on the mobile device was limited because the photos had to be stored along with your data in Local Storage on your device.

Now, if your application uses PhoneGap, you can use the file system on the device to store your photos and you can capture a large number of photos while you are disconnected, without having to worry about the limits of Local Storage. Future versions of Alpha Anywhere will also allow you to capture video and audio while you are disconnected.

NOTE: Photos, videos and audios are collectively labeled as 'media' files in this topic.

 

Quick Summary of Steps to Use PhoneGap File System for Photos:
-
Photo fields in your SQL database must be character fields.
- Create a List control with a Detail View on your UX component.
- In the Detail View, set the control type for the Photo fields to Image.
- In the List builder go to the Detail View pane and set the Media and other Linked Files properties. Most importantly, specify if the media files should be uploaded to Amazon S3 or the Alpha Anywhere server. It is also recommended that you check the Automatically download media files... property so that your photos in your existing data are available when you go offline.
- In the List builder, go to the Fields pane and set the control type for the Photo fields to Image. Also, if you have specified that the media files should be uploaded to the Alpha Anywhere server, edit the Image Capture and Storage properties to specify the folder where the uploaded photos should be stored.
- Add a button to the Detail View to capture an image using the camera. Define the click event for this button using the Image Capture for List-Detail View action in Action Javascript. In the builder for this action set the Image Capture Method to Phonegap and set the Data capture mode to Filename.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
 

NOTE: In order to use this feature, your PhoneGap application must include these PhoneGap plug-ins: Camera, Console, Device, File, File Transfer, Media, Media Capture.

Similarly, when you retrieve data from the server to store on your device, there is no need to store the photos in Local Storage. The photos can be downloaded and stored in files on the device. This will substantially increase the amount of data you can load onto your device.

In order to use the file system for your images (rather than Local Storage), you configure the Image Capture for List-Detail View - Camera/Photo Library action in action Javascript to use the 'Filename' option (rather than the 'Base64' option). See below for more detail.

When you sync the List with the server database, the photos (and other media files, once support for videos and audios is made available) are first uploaded (to the Alpha server or to Amazon S3) and then once the media files are all uploaded, the data in the Lists are synchronized.

Before examining how to configure the Image Capture for List-Detail View - Camera/Photo Library action in action Javascript and the List Detail View to use this option, it is helpful to understand more about what happens behind the scenes when you capture photos, and then sync the data in your List controls.

 

Behind the Scenes

When you take a picture, the List data for a row in the List might look like this (where the file in the picture field is a local file on the mobile device):

 

{Name: 'Fred Smith', picture: 'file://folder_in_the_file_system/image1.jpg'}

 

Note: If you had not set the action that captured the picture to use the 'filename' option, the data in the List might have looked like this (note that the picture field contains a long string of base64 encoded image data):
{Name: 'Fred Smith', picture: 'xysshdh24g22334hack46h2dk43hahdh...........'}

 

When you sync the List data, the media files (the photo in this case) are first uploaded to the server. Let's assume you are uploading media files to S3. The URI of the image on S3 might be something like:

https://yourS3bucketName.s3.amazonaws.com/image1.jpg

 

After the media files have been successfully uploaded to the server, the data in the List are changed as follows:

 

{Name: 'Fred Smith', picture: 'https://yourS3bucketName.s3.amazonaws.com/image1.jpg'}

 

The data in the List can then be synchronized with the server database. The following record would be written to the database:

Name              Picture

Fred Smith        https://yourS3bucketName.s3.amazonaws.com/image1.jpg

 

Once the data synch operation has completed, the data in the List is again changed back to:

{Name: 'Fred Smith', picture: 'file://folder_in_the_file_system/image1.jpg'}

 

The reason to change the data in the List back to its original state is that there is no need to reference a remote image (on say S3) when the local copy of the image is already available in the device file system.

 

Taking Your Media Files With You When You Go Off-line

If the data in your List has references to remote files (e.g. photos, videos, audio files, etc.) that are located on remote servers (such as the Alpha server, or Amazon S3), you can retrieve those files and store them in the file system on the mobile device. By doing this, you ensure that even when you are disconnected, your application can still reference these files.

Assume that a typical row in the SQL table that you are querying to populate the List contains data like this:

Name                   Picture

Fred Smith             https://yourS3bucketName.s3.amazonaws.com/image1.jpg

 

When you retrieve data from the server, the JSON representation of the data in a typical row in the List might look like this:

{Name: 'Fred Smith', picture: 'https://yourS3bucketName.s3.amazonaws.com/image1.jpg'}

 

The picture field is pointing to an image on Amazon S3 and this image will not be available if you are not connected. However you can fetch the image while you do have a connection, store the image in the file system, and update the data in the List to something like this:

{Name: 'Fred Smith', picture: 'file://folder_in_the_file_system/image1.jpg'}

 

Notice that the picture field in the List no longer points to the remove server, but instead is pointing to a file on the mobile device.

Orphaned Files

Assume that when the List is initially populated, the data in the List are:

[

   {Name: 'Tom Smith', picture: 'https://yourS3bucketName.s3.amazonaws.com/image1.jpg'},

   {Name: 'Jan Toms', picture: 'https://yourS3bucketName.s3.amazonaws.com/image2.jpg'}

]

 

When you fetch the media files, the following files will be stored in the file system on the mobile device:

Assume that the user then does another query and retrieves this data with which to populate the List:

[

  {Name: 'Tom Smith', picture: 'https://yourS3bucketName.s3.amazonaws.com/image1.jpg'},

  {Name: 'Ian King', picture: 'https://yourS3bucketName.s3.amazonaws.com/image3.jpg'},

  {Name: 'Jack Jon', picture: 'https://yourS3bucketName.s3.amazonaws.com/image4.jpg'}

]

 

At this point, the file system on the device will contain these files: 'image1.jpg', 'image2.jpg', 'image3.jpg' and 'image4.jpg', Notice that it still contains a file called 'image2.jpg', but there is no data in the List that references this file. 'image2.jpg' is an 'orphan' file and it can be deleted. The List Detail View has settings that allow you to automatically delete orphan files (see below). There are also events that are fired before and after orphan files are deleted.

 

Configuring Photo Capture to Use the File System

In order to capture photos in disconnected application you will need a List control with an associated Detail View. Let's assume that the List control is bound to a SQL table that has these fields

NOTE: When you are capturing base64 data, the photo field could be a character field, or a binary field. But if you want to use the file system on the mobile device for your photos, your photo field must be a character field.

Assume that you have have added a List control that is bound to this table to your UX. The control type for the photo field (imageChar) in the Detail View should be set to Image.

First you will need to edit the List control and go to the Fields pane and ensure that the control type for the imageChar field is set to Image. Since imageChar is a character field the List does not set its default type to Image.

 

You should then add a button next to this Image control and set the action on this button to Image Capture for List-Detail View - Camera/Photo Library.

When you click the smart field to configure this action, the builder will open as shown below:

 

 

Note that the builder has several properties shown as read-only properties.

 

In this example, the target field (i.e. the Bound field type) is a character field. Therefore we have the option of uploading the image to either Amazon S3, or the Alpha Anywhere server when the data in the List are synchronized.

NOTE: If the Bound field type is a binary field then uploading the image to Amazon S3 is not an option. The image can only be uploaded to the Alpha Anywhere server.

 

NOTE: More properties...  are actually stored in the List control settings. It is merely a convenience that you can edit these setting in this builder. Open the List builder and go to the Field pane to see the settings for each image field.

NOTE: Upload target settings are actually stored in the List control settings. They are not stored as part of your Action Javascript definition. It is merely a convenience that you can edit the Upload target settings from within this builder.  If you open the List builder and go to the Detail View pane,  Media and Other Linked Files (PhoneGap Application Only) section, you will the upload settings.

NOTE: Upload target settings apply to all image fields in the List (and any child Lists with pre-fetched data that are linked to this List). For example, assume that you have two image fields in your List. You might have one button to capture a photo for the first image and another button to capture a photo for the second image. If both of these buttons are configured to use the Filename option for the Data capture mode, then both of these images will be uploaded to the same target (either the Alpha Anywhere server, or Amazon S3). It is not possible to upload the first image field to S3 and the second image field to the Alpha Anywhere server.

 

Upload Target Settings Dialog

The Upload Target Settings Dialog allows you to define if the media files should be uploaded to the Alpha Anywhere server or to Amazon S3. There are two ways to get to this dialog:

  1. While you are editing an Action Javascript button to capture a photo, you can click the smart field for Upload target settings (as explained above)
  2. While editing a List control settings. Go to the Detail View pane and then click the Media files smart field (as shown in the image below).

    NOTE: You must define the Upload Settings in the top-most parent List if you have a List hierarchy (i.e. a parent-child relationship between Lists with the child Lists configured to pre-fetch their data).

 

 

The Upload Target Settings dialog is shown below.

 

 

NOTE: In the case where you are not using PhoneGap, you can still access photos in your data when you are offline. However, the amount of data you can load into the List will be limited because the photos are stored in Local Storage along with the List data. In order to store images in the List data so that they are available when you are offline, the photo field in your database must be a binary field (as opposed to a character field - which is required if you are using the PhoneGap option) and you must configure the List to embed the image data (as base64 encoded data) into the List (by checking the Embed images into HTML property for the image field in the List settings, Fields pane).

Methods

The following methods are available

Events

The following client-side events have been added:

 

 

 

 

 

UX Component - Optimizing Initial Load Time - When a UX component is opened, the layout of the component is computed from the UX component definition. In a large component that can take some time and the component will appear to be slow to open.

NOTE: If the component is opened from a button on a parent component, and the action that defines how the component is opened uses the 'Use cached UX Component' option, the second and subsequent times the button on the parent component is clicked, the UX will open quickly.


 

A new option in the UX allows you to pre-render the component layout at design-time, thus speeding up the load time for the component at run-time.

NOTE: Not all use cases are appropriate candidates for this option. In particular, if you have controls on your UX that are shown/hidden based on a user's security group, or based on session variables, then you should not use this option. The reason is that at design-time when the component is rendered, it is not know what the value of the session variables or group assignments are.

TIP: You can easily check if a component uses security and/or server-side show hide expressions by click the Menu button and then selecting the 'Security and server-side show/hide settings in component...' menu choice.

 

To turn on this optimization feature go to the Properties pane in the UX builder and check the 'Pre-render component at design-time' property.

 


 

When you check this property you will see two additional properties:

 

TIP: When you save a pre-rendered component at design-time, you might have Xbasic code in functions you have defined that is meaningless at design-time, but is nevertheless being called when the component is being pre-rendered. You can test if you are in pre-render mode by checking the flagPreRender property of the rtc object that is passed to all server-side code in the e object. For example:

 

function someXbasicFunction as c (e as p)

if eval_valid("e.rtc.flagPreRender") then
    if e.rtc.flagPreRender then
        exit function
    end if
end if

 

.... your code

end function


 

 

json_sqlQuery() Function - Allows you to filter a JSON array using a simple SQL query syntax. For example assume you have a JSON string as shown below. The JSON is an array of objects. You can think of this as a table with the following fields: firstname, lastname, city and state.

 

 

dim json as c
json = <<%str%
[
    {firstname: 'John', lastname: 'Smith', city: 'Boston', state: 'MA'},
    {firstname: 'Fred', lastname: 'Jones', city: 'Cambridge', state: 'MA'},
    {firstname: 'Tom', lastname: 'King', city: 'New York', state: 'NY'}
]
%str%
 

Assume that you want to apply a filter to this string to retrieve certain records and also to sort the result.

The SQL that you would need to express your query might be:

select * from JSONTABLE WHERE state = 'MA' ORDER BY lastname

 

Or if you would like to use arguments in your SQL, you might express your query as:

select * from JSONTABLE WHERE state = :whatstate ORDER BY lastname

 

Here is how you can use the json_sqlQuery() function:


dim args as sql::arguments
args.add("whatstate","MA")
dim jsonResult as c
json2 = json_sqlQuery(json,"select * from jsontable where state = :whatstate ORDER BY lastname",args)

 

The resulting string will be:

 

[

    {firstname: 'Fred', lastname: 'Jones', city: 'Cambridge', state: 'MA'},
    {firstname: 'John', lastname: 'Smith', city: 'Boston', state: 'MA'}

]

 

 

UX Component - List Control - Persisting List to Local Storage - The UX component has a property that allows you to minify the data before it is put into Local Storage, thereby reducing the amount of space needed to stored the List data.

 

When you check the Minify data option now, any blank fields in the JSON data are automatically removed and system fields that are used internally in the List (these are field that have a leading '*' in their name) are also removed. This can result in a significant reduction in the amount of space needed to save a List in Local Storage.

 

X Component - SQL - Native SQL and Stored Procedures - You can now enter native SQL statements (including SQL to execute Stored Procedures) in the SQL Statement for a List that is based on a SQL data source.

Previously if you wanted to base a List on native SQL, or on a Stored Procedure you had to use a Custom data source. However, when you used a custom data source you then had to write your own code to handle pagination and server-side filtering.

Now, pagination and server-side filter all word regardless of whether the SQL for the List is portable, native or a Stored Procedure.

If you apply a server side filter to a List that is based on a Stored Procedure, or a native SQL statement that cannot be parsed, Alpha Anywhere will execute the SQL (without the filter/order clause) and then apply the filter/order to the data that is retrieved from the database server.

For example, suppose you based on List on this SQL statement:


exec getAllCustomers


The you apply a server-side filter to the List:


Country = 'USA'
 

Since the Stored Procedure can only return all customers and since it (presumably) was not designed to take an arbitrary 'where' clause, Alpha Anywhere will execute the Stored Procedure and then apply where filter to the data after it has been returned by the database server, but before it is sent to the List control.
 

Storage Connection Strings - Amazon S3 - Connection String Builder - Region Name - The dialog now uses 'friendly' region names that match the region names used in the AWS Management Console.

 

 

Web Applications = Development Server - The Alpha Anywhere Development Server now allows an unlimited number of sessions from localhost clients (i.e. browsers running on the same system) without requiring an Application Server license. This extends the existing Development Server functionality that has always allowed 5 sessions from any client. Localhost clients are no longer counted towards the 5 session limit, so a developer may do unlimited testing using local browsers and device emulators, and still test from 5 non-local clients such as an actual mobile device, a coworker's or client's computer, etc.

Previous versions of Alpha allowed an unlimited number of localhost sessions and no non-local sessions when running the server without a license.
 

Web Security - Password Validation - The password validation in the web security now supports regular expressions in the Text Format. Previously, if a regular expression was used for validation, it had to be added as a custom expression. Publishing to IIS does not support custom expressions, so a custom expression should be converted to a regular expression if possible.
 

PhoneGap Builder - File Opener Plugin - The File Opener plugin has been added to the options screen in the PhoneGap Builder.

More info on the plugin is available here.

 

http_fetch() Function - Validation has been added to the host specified for the HTTP request. Users have occasionally specified a full URL as the host name, which has caused a failure. The new validation logic will extract the host name from the URL if one is mistakenly provided and allow the HTTP request to be completed

UX Component - List Control - Scroller - You can now dynamically show/hide the scroller for a List control. This is useful if you are dynamically populating the List and under some circumstances that are so few rows in a List that the scroller is not wanted, but in other cases there will be many rows in the List and the scroller would be wanted.

The List's .setDisplay() method is used for this as follows:

 

var lObj = {dialog.object}.getControl('myList');

lObj.setDisplay('scroller',false); //hide

lObj.setDisplay('scroller',true); //show

 

Other parts of the list that can be controlled with the .setDsiplayMethod() are:

 

 

Grid Component - .filterCheckedRows() Method - Now takes an optional argument to filter the unchecked rows as opposed to the checked rows.

Syntax:

{grid.Object}.filterCheckedRows([flagUncheckedRows])

 

UX Component - DataBound UX Components - Refreshing Schema Information - The UX builder has an option to automatically refresh the stored schema information every time the UX is opened for editing. For complex data bindings, this can slow down the time taken to open the UX for editing. If you know that the table schema has not changed, there is no need to refresh the stored schema in the UX and you can therefore speed up opening the UX for editing by skipping this step. When you specify that the schema should be refreshed when the UX is edited, there is now a new option to prompt for confirmation each time the UX is opened.

 

 

a5_getExifInfo() Function - Extract EXIF information from an image.

Syntax

P result = a5_getExifInfo(c imageFilename)

 

The result object that is returned has these properties

 

 

UX Component - Action Javascript - Populate Controls in an Unbound UX - New options if no matching record found - If the specified primary key is not found in the table you can now specify that the values in the databound controls should be cleared, you can also suppress the error message, and you can call a Javascript function.

See 'Errors and No Match Found' section in the genie.

 

 

Faster Startup - Alpha Anywhere now starts up faster because the licensing check is now done in a background thread.

PhoneGap - Index.HTML Meta Tags - When you build a PhoneGap app, a new option in the PhoneGap builder now allows you to insert custom META tags in the index.html file that is generated for your PhoneGap app.

A common use case for this feature is to turn off iOS auto-detection of phone numbers and email addresses.

 

 

Web Applications - Context Object Documentation - The Context object is available to all server side code that executes in the context of a Web application (for applications that use the Alpha Anywhere server and for those that use the Alpha Anywhere plug-in for IIS).  This object has an extensive set of methods and properties that allow you to get information about the request and the response to interact with the security framework.

 

Click here to see Context object documentation.

 

 

json_parse() Function - Parsing Javascript Object Literals - The JSON parse function now takes an optional second argument to indicate if the JSON being parsed is a Javascript object literal rather than a JSON string. For example, consider the following Xbasic code which defined an Xbasic object (i.e. dot variable):

 

dim p as p
p.name = "Fred"
p.sayHello = "{javascript}function() { alert('hello');}"

 

Now, generate a Javascript object literal. Pass in .t. as the second argument to vartojson() to indicate that we want an Javascript object literal and not a JSON string.

 

dim jsObject as c

jsObject = vartojson(p,.t.)
 

Here is what the resulting string looks like:

 {
name: 'Fred',
sayHello: function() { alert('hello');}
}

 

Now, in order to be able to parse this object literal back to Xbasic, we use the json_parse() function but we set the optional second argument to .t.


dim pj as p
pj = json_parse(jsObject ,.t.)
?pj.name
= "Fred"

?pj.sayHello
= "{javascript}function() { alert('hello');}"


 

 

 

UX Component - List Control - Template Items - a5-item Attribute - Template Items are a powerful new way to efficiently add event handlers to the HTML markup used in the List template. Template items are added to the HTML markup by adding an a5-item attribute to the markup, as explained below.

 

Watch Video

 

Regardless of whether the List is defined as a free-form or columnar layout, every row displayed in the List is created by merging data into the row template. For a free-form List, there is a single template for the entire row and for a columnar List, there is a template for each column in the List. The template is HTML with placeholders for the List data.

For example, the template for the Firstname field in a columnar List might be:

{Firstname}

 

The template for a free-form List might be:

<b>{Firstname} {Lastname}</b> <br>

{City} {State} {Zip}

 

You might want to add an event handler so that when the user clicks on the Firstname field, an event fires. You might change the template for the Firstname field to:

<span  onClick="event1()" >{Firstname}</span>

 

When the user clicks on the Firstname field in any row of the List, the event1() Javascript function should be called.

While inserting the onClick attribute into the <span> that wraps the {Firstname} placeholder seems easy enough there are two problems with it:

Both problems can be solved by using template items. The template could be defined as:

<span  a5-item="item1" >{Firstname}</span>

 

In the above example, 'item1' is the name of a template item. The event handlers for the 'item1' template item are defined in the Template Item editor.

 

To define template items, you can either click the Quick Access... button at the bottom of the List Builder window and then select 'Template Items' from the menu.

 

 

Or, you can click the Template 'items' hyperlink in the Column Template of Layout Template editor.

 

When you open the Template Items editor you get a screen that looks like this:

 

 

You can define as many template items as you want. For each item you define event handlers for the Click, Double Click and Right Click events.

You can also set the 'Selectable' property. If this property is set, then when the user clicks on the item, the row in which the user clicks is selected. Otherwise, the row is not selected.

 

When you insert a template item into the HTML markup you can insert an optional 'item argument'. The item argument follows the item name, delimited by a colon. In the example below, 'item1' is the item name and 'argumentValue' is the item argument. The purpose of the item arguments is to pass additional information to the Javascript event handler.

<span  a5-item="item1:argumentValue" >{Firstname}</span>

 

The Javascript event handlers for the item can reference:

When you are editing the List template the Template 'items' hyperlink also gives you access to a special genie that makes it easy to insert items into the template:

 

 

 

UX Component - List Control - onFieldClick, onFieldDblClick, onFieldRightClick Events - New events have been added to the List that fire when you click, double click or right click on fields in the List.

 

Watch Video
 

Contrast these events with the onClick, onDblClick, etc. event which fire when you click on a row (as opposed to a field) in the List.

When the onFieldClick, onFieldDblClick or onFieldRightClick events are fired, the e object that is passed into the event handler has these properies:

NOTE: The above events are only implemented for Label and RawData control types.

 

 

 

varToJsonHash() Function - Converts an Xbasic property array to a JSON hash

 

Syntax:

C jsonHash = varToJSonHash(p propertyArray, c hashProperty [, L flagSpecialTags  [, L  flagCondense [, flagUseDoubleQuotes ]]])

 

Where:

 

Example:

Consider the following Xbasic property array:

 

DIM P[0] as p
p[].name = "John Smith"
p[..].address = "123 Main Street"
p[..].age = 23




p[].name = "Fredia Malt"
p[..].address = "456 Center Lane"
p[..].age = 33

 

We can convert this to a JSON hash, using the 'name' property as the hash index as follows:

dim jsonHash as c

jsonHash = vartojsonHash(p,"name")
 

The resulting JSON string looks like this:


{
    'John Smith' : {address: '123 Main Street',age: 23},
    'Fredia Malt' : {address: '456 Center Lane',age: 33}
}
 

In this next example we use the flagSpecialTags property

 

DIM P[0] as p
p[].name = "John Smith"
p[..].address = "123 Main Street"
p[..].age = 23

p[..].sayHello = "{javascript}function() { alert('hello John') }"




p[].name = "Fredia Malt"
p[..].address = "456 Center Lane"
p[..].age = 33

 

jsonHash = vartojsonHash(p,"name", .t.)
 

 

The resulting JSON string is:

 

{
    'John Smith' : {address: '123 Main Street',age: 23,sayHello: function() { alert('hello John') }},
    'Fredia Malt' : {address: '456 Center Lane',age: 33}
}


 

AlphaDAO - SQLServer Driver - Faster Connections - There are two changes in the SQL Server Extension driver:

  1. The actual ODBC driver is selected based on the installed drivers and the selected SQL Server database version. The logic is not complicated but can be expensive; taking a few milliseconds to find the best matching driver. The driver has been optimized so that for a specific SQL Server version, the result is cached and only needs to be evaluated once per process.
  2. The code that should be enabling connection pooling was not working properly. The SQL Server Extension driver now pools connections in a driver specific environment. This behavior should not have any effect on other drivers and is not implemented for the generic ODBC driver because some ODBC drivers are not thread-safe.

As a result of both changes, the connection times are now in the microsecond range when connecting to a local machine.

 

UX Component - Edit Combo - Stored Value is Different than Display Value - Resolving Value Message - When you define an Edit-Combo that sets the stored value to be different than the display value, and the Edit-Combo is populated using an Ajax callback, you can now control the message that is shown when the stored value is resolved into a display value. By default the message:

Resolving: <stored value being resolved>

is shown while the Ajax callback that resolves the stored value is running. But you can customize this message or even eliminate it by setting the message text to <None>.

 

 

UX Component - List Controls - Detail View - Parent/Child Data - In disconnected applications, when you define parent-child relationships between List controls you must set the child List's 'Pre-load data' property to true.

However, when you are building a connected application you might still want to define a parent-child relationship between Lists and you might want to define a Detail View for each List to allow editing of the List data, but you might not want to pre-load the child data (since Alpha Anywhere can easily fetch the child data as needed as you have a connection).

Previously, if you did not have the pre-load option checked, you were not allowed to edit data in the child Lists (using the child List's Detail View).

Now, you can edit data in the child Lists, but you must specify linking values in the optional Linking fields section. The data you fill into these properties is used to ensure that the values in the linking fields are automatically set to the corresponding values in the parent List record when insert or updates are performed.

 

 

a5_sql_schema_to_json() Function - Takes a schema of a SQL database and generates a JSON representation of the schema showing all tables in the database, and their relationships.

 

Example:

 

Type the following commands in the Interactive window:

 

dim cn as sql::Connection

?cn.Open("::Name::northwind")

= .T.
dim sn as sql::Schema

?cn.GetSchema(sn)

= .T.

dim jsonSchema as c

jsonSchema = a5_sql_schema_to_json(sn,{ show_field_type_info : true })

showvar( jsonSchema)
 

 

UX Component - Action JavaScript - Geolocation Functions- A new option, Get accurate position within a designated radius has been added to the Action JavaScript Geolocation functions. When enabled, you may specify a desired accuracy radius. The returned lat/lon will fall within the desired accuracy radius if at all possible. This option calls a new custom method that has been added to the navigator.geolocation object called getAccuratePosition(). This method uses the geolocation watchPosition() method to attempt to get position data within a specified accuracy radius. The method will time-out at the maximum wait time and will return the last known location, even if the accuracy does not meet the desired accuracy target.


The maximum wait time defines the maximum amount of time in ms to wait for a geolocation change event.
If Ignore first result is checked, the first geolocation point returned will not be used. Some devices return cached location data for the first result, which is, in most cases, inaccurate.

The returned geolocation data can be accessed through the {dialog.object}.getGeolocation() method.

Example code for the 'Callback function' in the above image:
 

   function gotResults() {
       var e = {dialog.object}.getGeolocation();
       alert('Lat = '+e.latitude+' Lon = '+e.longitude);
     }
    

UX Component - Client-side Group Breaks - Aligning Summary Values with List Columns - The List control allows you to insert client-side group breaks in a List and to display summary values in the group headers and footers. In a columnar List layout you typically want to align these summary values with the appropriate List columns.

A new genie in the Header/Footer builder make this easy to do. The genie generates a sample Javascript function that you can easily modify.

Watch Video
Download Component
 

 

UX, Grid, TabbedUI and Custom Components - Local CSS and Linked CSS Files - SASS - When you define local CSS (at the Local CSS definitions property), or when you link in CSS files you can now use SASS syntax in your CSS definition.

NOTE: For more information on SASS syntax see http://sass-lang.com/

In the case of linked CSS files your CSS file should have a .scss extension and when you specify the name of the linked CSS files you should include the .scss extension.

 

TIP: You can turn off automatic SASS processing of your local CSS definitions by adding this property to the  Advanced, Other Properties section in the builder: 
    tmpl.sassProcessor = .f.

 

UX and Grid Builder - Editing HTML Content - Script Tags - When you add a <script> tag to HTML content that you are editing, by default Alpha Anywhere assumes that the type is 'text/javascript' and does not auto-complete or syntax highlight the text between the opening an closing <script> tags.

However, if you set the type to 'text/html', then Alpha Anywhere will treat the text in the <script> tags as HTML and will do syntax highlighting and html code completion.

This feature is very useful when you want to create strings of HTML for use in Javascript code.

 

 

UX and Grid Component - HTML Snippets - When writing Javascript functions, a common requirement in the Javascirpt code is to define a long string of HTML markup. A good example of where this requirement is common is when using the A5.u.temp.ate.expand() function in client-side templates.

For example, you might write Javascript like this:

 


var _d = {

    firstname: 'Fred',

    lastname: 'Smith',

    Address: {
                Street: '123 Main St',
                City: 'Boston',
                State: 'Ma'
            }
    };
 

var _t = [
    'Hello {firstname} {lastname}<br>',
    'Address: {Address.Street}<br>',
    '{Address.City} {Address.State}'
].join('');
 

var settings = {
    template: _t,
    partials: ''
}
var html = A5.u.template.expand(_d,settings);

 

 

The HTML template in the above code was written as an array of single-line strings that were then joined to create a long string.

 

While the above pattern for creating long strings is perfectly reasonable, it is difficult to write because the single-line strings all need to be Javascript escaped and you do not get any HTML auto-complete help while you compose the script.

 

A better technique is to add a static-text control to the UX and then to add the HTML template to the static-text control using a <script> tag with a type of "text/html".

Because the HTML markup is in a <script> tag, it will not be rendered when the UX is run. And because the type is 'text/html' the markup will not be executed as Javascript code.

Any text inside a  <script> tag with a type of "text/html"   will be highlighted as HTML text and the standard HTML auto-complete help will apply.

By giving a unique Id to the <script> tag, your Javascript can easily reference the contents of the <script> tag.

 

 

In the above example Javascript, the code can be changed as follows:

 

var _d = {

    firstname: 'Fred',

    lastname: 'Smith',

    Address: {
                Street: '123 Main St',
                City: 'Boston',
                State: 'Ma'
            }
    };
 

var _t = $('template1').innerHTML
 

var settings = {
    template: _t,
    partials: ''
}
var html = A5.u.template.expand(_d,settings);

 

And the template can be defined in a static-text control as follows

 

<script id="template1">

    Hello {firstname} {lastname}<br>
    Address: {Address.Street}<br>
    {Address.City} {Address.State}

</script>

 

json_flatten() Function - Takes a JSON string that defines an array of hierarchical objects and 'flattens' the array.

This function is useful for Reporting where the report data source is set to a Custom data source that returns JSON data. If the JSON data that is returned is hierarchical, then you will need to 'flatten' it in order to get it into an appropriate format for the report writer.

The syntax for json_flatten() is

c output = json_flatten(C jsonIn, c template)

The format of the template is shown in the following example.

 

Consider the following JSON String:


[
        {
            "id": "alfki",
            "name": "customer 1",
            "__a5crc": -253329,
            "orders": [
                {
                    "orderId": 1,
                    "orderData": "12/1/2013",
                    "ordcust": "1|||alfki",
                    "orderDetails": [
                        {
                            "lineitemId": 1,
                            "prodId": 1,
                            "qty": 3,
                            "ordprod": "1|||1"
                        },
                        {
                            "lineitemId": 4,
                            "prodId": 3,
                            "qty": 2,
                            "ordprod": "1|||3"
                        }
                    ]
                },
                {
                    "orderId": 3,
                    "orderData": "12/3/2013",
                    "ordcust": "3|||alfki",
                    "orderDetails": [
                        {
                            "lineitemId": 6,
                            "prodId": 4,
                            "qty": 9,
                            "ordprod": "3|||4"
                        },
                        {
                            "lineitemId": 7,
                            "prodId": 3,
                            "qty": 1,
                            "ordprod": "3|||3"
                        }
                    ]
                }
            ]
        },
        {
            "id": "bolid",
            "name": "customer 2",
            "__a5crc": -194126,
            "orders": [
                {
                    "orderId": 2,
                    "orderData": "12/2/2013",
                    "ordcust": "2|||bolid",
                    "orderDetails": [
                        {
                            "lineitemId": 2,
                            "prodId": 6,
                            "qty": 6,
                            "ordprod": "2|||6"
                        },
                        {
                            "lineitemId": 3,
                            "prodId": 9,
                            "qty": 7,
                            "ordprod": "2|||9"
                        }
                    ]
                }
            ]
        }
]


The JSON object defined by the above string shows an array of customers with embedded orders. For each order, there are embedded line-items.

The structure of the JSON object is

Customers

    Orders

        Order Details

 

The json_flatten() function takes two arguments - the JSON string you want to flatten, and a template that defines which properties in the input JSON you want to map to the output JSON.

Assume that the following template is specified:


{
   "id" : "id" ,
   "name" : "name" ,
   "orders" : [ 
                 { 
                    "orderId" : "orderId" , 
                    "orderData" : "orderData" , 
                    "orderDetails" : [
                                         { 
                                            "lineitemId" : "lineitemId" , 
                                            "prodId" : "prodId" , 
                                            "qty" : "qty" 
                                         }
                                    ] 
                } 
              ]
}

 

 

If you 'flatten' this JSON using the above template, you will get the following output:

[
    {
        "id": "alfki",
        "name": "customer 1",
        "orderId": 1,
        "orderData": "12/1/2013",
        "lineitemId": 1,
        "prodId": 1,
        "qty": 3
    },
    {
        "id": "alfki",
        "name": "customer 1",
        "orderId": 1,
        "orderData": "12/1/2013",
        "lineitemId": 4,
        "prodId": 3,
        "qty": 2
    },
    {
        "id": "alfki",
        "name": "customer 1",
        "orderId": 3,
        "orderData": "12/3/2013",
        "lineitemId": 6,
        "prodId": 4,
        "qty": 9
    },
    {
        "id": "alfki",
        "name": "customer 1",
        "orderId": 3,
        "orderData": "12/3/2013",
        "lineitemId": 7,
        "prodId": 3,
        "qty": 1
    },
    {
        "id": "bolid",
        "name": "customer 2",
        "orderId": 2,
        "orderData": "12/2/2013",
        "lineitemId": 2,
        "prodId": 6,
        "qty": 6
    },
    {
        "id": "bolid",
        "name": "customer 2",
        "orderId": 2,
        "orderData": "12/2/2013",
        "lineitemId": 3,
        "prodId": 9,
        "qty": 7
    }
]

 

 

 

 

Notice that the template has omitted the '__a5crc' in the input property. The template indicated which properties were to be extracted from the input JSON. It also indicates that the property name should be called in the output JSON.

For example, the template indicates:

 "id" : "id"

Had that been:

 

 "id" : "CustomerId"

 

The output JSON would have named the 'id' property 'CustomerId'.

 

Here is a simpler example:

 

dim json as c
json = <<%str%
[
    {"id" : 1, "name": "John", "kids" : [ {"name": "callie"},{"name" : "griffin"} ]},
    {"id" : 2, "name": "Tom", "kids" : [ { "name" : "betty" } ]}
]
%str%

dim template as c
template = <<%str%
{"id" : "id", "name" : "firstname", "kids" : [ {"name": "name"} ] }
%str%

dim json2 as c
json2 = json_flatten(json,template)
json2 = json_reformat(json2)

 



Here is what json2 looks like:

 

[
    {
        "id": 1,
        "firstname": "John",
        "name": "callie"
    },
    {
        "id": 1,
        "firstname": "John",
        "name": "griffin"
    },
    {
        "id": 2,
        "firstname": "Tom",
        "name": "betty"
    }
]

 

 

 

The json_flatten() function can also be used to simply map property names in the input JSON to new property names in the output JSON. For example, consider the following script:

 

 

 

dim json as c
json = <<%str%
[
    {"id" : 1, "name": "John"},
    {"id" : 2, "name": "Tom"}
]
%str%

dim template as c
template = <<%str%
{"id" : "id", "name" : "firstname"}
%str%


dim json2 as c
json2 = json_flatten(json,template)
json2 = json_reformat(json2)
showvar(json2)
 

The resulting JSON will look like this:

[
    {"id" : 1, "firstname": "John"},
    {"id" : 2, "firstname": "Tom"}
]

 

 

 

 

PhoneGap-  Modified The Default Location For Persistent Files - Previous versions set the Persistent File Location property to "Compatibility" mode on both Android and iOS devices. It has now been changed to "Internal" for Android and "Library" for iOS. This is the recommended setting on Android to ensure the files are contained within the app folder and that the files are deleted when the app is deleted. Under iOS, the files are always in the app folder, however, files in the Library folder are not available to iTunes nor are they synchronized to iCloud.

When "Compatibility" mode is set as the persistent file location for an Android PhoneGap app:

When "Compatibility" mode is set as the persistent file location for an iOS PhoneGap app:

In general "Compatibility" mode is NOT the recommended setting.

If you have used the PhoneGap file plug-in in previous versions, the default setting will make your app files inaccessible. The setting will not change for existing PhoneGap apps because the previous "Compatibility" setting will remain within the configuration file. Your app will only be affected if you delete the previous PhoneGap project and create a new one. You can change this setting by enabling Show Advanced Options in the Configuration Options settings of the PhoneGap App Builder Genie. Once the Show Advanced Options is enabled, you can change the persistent file location as required

Web Applications - Web Projects Control Panel - 'Search all files in this Project' Command - This command will now search in report, label and letter file (.i.e. .a5rtp, .a5lab and .a5ltr). The data source definition of the report layout (not the report body itself) will be searched.

UX Component - Action Javascript - PhoneGap - File System Actions - A new action in Action Javascript allows you to perform actions on the file system of the mobile device on which your UX is running.

NOTE: File system actions are only supported for PhoneGap applications.

The actions currently supported are:

 

All of these actions are performed asynchronously. For each action you specify the Javascript to execute once the action has successfully completed. If the action fails, the Javascript you specify for the on failure action is executed.

Because the actions are asynchronous, you cannot simply define an Action Javascript that calls two file system actions sequentially. For example, assume that you defined an Action Javascript that did this

  1. Create a new directory
  2. Write a file to the new directory

This would likely fail because the second action (write a file to the new directory) would be executed immediately after the first action (before the new directory had actually been created).

In order to make the above work, the second action (write a file) needs to be called in the first action's onSuccess function.

The asynchronous nature of file system actions makes it tricky to write complex scripts that perform many file system actions

In the above example, you would need to convert your Action Javascript to text mode and the rearrange the code.

For example, assume you defined the above two actions using Action Javascript. Once you converted to text mode your code would look like this:

 

{dialog.object}.phoneGapCreateDirectory('dir1', function() { //ok}, function() { //fail } );

 

{dialog.object}.phoneGapCreateFile('dir1/file1.txt','some data',function() { //ok }, function() {//fail },false);

 

To re-organize the code so that the write file action happens after the new directory has been created, we simply paste the action into the create directory's onSuccess function:

 

{dialog.object}.phoneGapCreateDirectory('dir1', function() {

    //ok

    {dialog.object}.phoneGapCreateFile('dir1/file1.txt','some data',

    function() { //ok },

    function() {//fail },false);

 

}, function() { //fail } );

 

 

UX Component - PhoneGap File System Methods - The following methods have been added to the UX for working with files on the mobile device.

 

NOTE: File system actions are only supported for PhoneGap applications.

 

Create a directory {dialog.object}.phoneGapCreateDirectory(dirName, onComplete, onError)
Create a directory (recursively) {dialog.object}.phoneGapCreateDirectoryRecurse(dirName, onComplete, onError)
Read a directory {dialog.object}.phoneGapGetDirectory(dirName, onComplete, onError)
Read a directory (recursively) {dialog.object}.phoneGapGetDirectoryRecurse(folder, onDirComplete, onDirError)
Remove a directory {dialog.object}.phoneGapRemoveDirectory(dirName,onSuccess,onError)
Remove a directory (recursively) {dialog.object}.phoneGapRemoveDirectoryRecurse(dirName,onSuccess,onError)
Delete a file {dialog.object}.phoneGapDeleteFile(fileName,onSuccess,onError)
Check if a file exists {dialog.object}.phoneGapFileExists(fileName,onResult,onFailed)
Read a file {dialog.object}.phoneGapReadFile(fileName,onReadFile,onReadFileERROR)
Create a file {dialog.object}.phoneGapCreateFile(fileName,text,onCreatedFile,onCreateFileERROR,flagAppend)

 

 

 

UX Component - Action JavaScript - Stripe Checkout- A new Action JavaScript has been added to the UX component that allows you to easily use Stripe Checkout.

Stripe Checkout, and the Stripe API, allow you to process credit card payments from within your desktop web or mobile app.

You will need to obtain your unique test and live authentication/api keys from Stripe prior to working with Stripe Checkout within your app. See the Stripe Website to setup your account.


A typical use case is to assign the action to a button click event, once the total of all items to be purchased has been computed.

 

Watch Video

Download Component

 


Specifying your Stripe API Keys: Stripe will issue you a total of four authentication/api keys. One set is for testing and one set is for a live app. The keys can be entered in explicitly within the Action Javascript builder or you may specify the keys within your project properties (click the Project Properties button when the Web Control Panel has focus).



Entering the Stripe Checkout keys in the Project Properties
Entering the Stripe Checkout Keys in the Project Properties allows you to easily use Stripe Checkout within multiple components. Be careful to enter the test keys (typically prefixed with sk_test and pk_test) and the live keys (typically prefixed with sk_live and pk_live) in the appropriate fields.

The secret key is used server side when the server is communicating to the Stripe API with the token supplied by Stripe Checkout. The secret key is never revealed client side.



Stripe App Type: The app type can be Test or Live. Use Test for all of your testing and when you are ready to go live you must switch this property to Live and republish the app. If you are building a PhoneGap app, make sure to rebuild the PhoneGap app and upload to PhoneGap Build.

Icon Image: The icon image is displayed at the top of the Stripe Checkout component. The recommended minimum size is 128 x 128 px. Supported image types include .gif, .jpeg and .png.


Currency type: This specifies the currency of the amount being charged. The code entered here is the 3 letter ISO country code. Stripe offers support for a worldwide range of currencies. You can accept payments in your supported currencies from almost any credit card and debit card no matter where the customer lives. Customers in other countries may be charged additional fees by their bank.


Charge description: A general description of the product or service being purchased. The JavaScript you enter here can simply return a string (like the example below), return the value contained within a control or return the result of a JavaScript function, defined within the UX component's JavaScript Functions property.



Charge amount: The amount (in cents) that is being charged. The JavaScript you enter here may simply return a number (example: return 1235; for a $12.35 charge), may read the value of a control (make sure you convert to cents!) or may return the result of a JavaScript function, defined within the UX component's JavaScript Functions property.



OnStripeCheckoutComplete: This event fires after Stripe has attempted to process the payment with the token supplied by Stripe Checkout. The JavaScript you enter here can examine the results returned from Stripe by calling the {dialog.object}.getStripeResults() method (see the sample code below). The {dialog.object}.getStripeResults method returns either a Stripe charge object with a wide range of properties or an error.

See Stripe Charges Doc for more information.


HTTPS For Your Site All submissions of payment info using Stripe Checkout are made via a secure HTTPS connection. However, in order to protect yourself from certain forms of man-in-the-middle attacks, it is suggested that you serve the page containing the payment form with HTTPS as well.


 

UX Component - Image Upload Action Javascript - Mobile - Amazon S3 - When defining an Image Upload action for a UX component that is run on a mobile device you can specify in the image should be uploaded directly to Amazon S3 rather than to the Alpha Anywhere server.

This option is only available if the image is bound to a character field in the Table to which the UX component is bound.

Image upload in a mobile application uses the camera, or the photo library to select the image.

The option to upload to S3 is available for both HTML5 camera access and PhoneGap camera access.

NOTE: In the case where you are building a PhoneGap application, it is very important that when you build your PhoneGap project you include all of the necessary plugins when you define your PhoneGap project. You must include the File, FileTransfer and Camera plugins.

The ability to upload file images to Amazon S3 when using the Image Upload action in Action Javascript for the 'Desktop' mode was released previously. More information about this feature can be found in this topic: Action Javascript - Image Upload Action - UX and Grid Component - Amazon S3

 

UX Component - Android - Client-side Events -  onKeyboard Event - A new event has been added that fires when the keyboard comes up, or is dismissed. This event is only supported on Android devices.

NOTE: The reason that the event is not supported on iOS is that under iOS the reported screen size of the device does not change when the keyboard is up.

NOTE: If you have set the UX quirks mode keyboardAffectsScreenSizeCalc property to true for backward compatibility then the onKeyboard event will not fire. For example:

{dialog.object}._quirks = { keyboardAffectsScreenSizeCalc: true};

 

 

UX Component - List Control - .setValue() Method - New Options - Several  new options have been added to the List control's .setValue() method. The options allow

Examples:

Select all records in a List:

var lObj = {dialog.object}.getControl('MYLISTNAME');

lObj.setValue({select: 'all'});

 

Select records by Group name (deselecting any existing selections):

var lObj = {dialog.object}.getControl('MYLISTNAME');

lObj.setValue({

    select: 'group',

    groups: ['CA','MA'],

    additive: false

})

 

Select records by Group name (preserving any existing selections):

var lObj = {dialog.object}.getControl('MYLISTNAME');

lObj.setValue({

    select: 'group',

    groups: ['NY'],

    additive: true

})

 

Select all rendered records in a 'Virtualized' list (if there are 100 records per 'page' and the List has (say) 2,000 records then there are 100 rendered records that will be selected):

var lObj = {dialog.object}.getControl('MYLISTNAME');

lObj.setValue({

    select: 'view',

    additive: false

})

 

 

UX and Grid Component - Javascript Actions - Filter List - The Define Javascript Action dialog now has a filter control to allow you to easily filter the list of actions. This is useful because some developers now have a large number of Javascript Actions defined in their components.

 

 

a5_json_viewer()  Function - The A5_json_viewer() function can be used to open a viewer for JSON data.

 

 

Xbasic - CURL Genie - The code generated by the Xbasic CURL Genie is now more flexible. Instead of generating a constant for the post body length, it now generates a variable. For example, assume that you paste this CURL command into the genie.

 

curl --data "param1=value1&param2=value2" https://example.com/resource.cgi
 


The generated output from the genie will now be:


dim cf_1 as extension::CurlFile
dim flag_1 as l
dim ce as extension::Curl

ce = extension::Curl.Init()
ce.setOpt("URL","https://example.com/resource.cgi")
ce.setOpt("NOPROGRESS",1)
dim posted_fields as c = ("param1=value1&param2=value2")
ce.setOpt("POSTFIELDS",posted_fields)
ce.setOpt("POSTFIELDSIZE_LARGE", len(posted_fields) )
ce.setOpt("USERAGENT","curl/7.40.0")
ce.setOpt("MAXREDIRS",50)
ce.setOpt("CAINFO",a5.Get_Exe_Path()+"\caroot\ca-cert.pem")
ce.setOpt("CAPATH",a5.Get_Exe_Path()+"\caroot")
ce.setOpt("SSH_KNOWNHOSTS","C:\Users\Cian\AppData\Roaming/_ssh/known_hosts")
ce.setOpt("TCP_KEEPALIVE",1)
ce.SetOpt("FILE",cf_1)
flag_1 = ce.Exec()
if flag_1 then
    showvar( "Headers: "+crlf()+cf_1.GetHeaders()+crlf()+"Content:"+crlf()+cf_1.GetContent())
else
    showvar("error: " + ce.Error() )
end if
ce.close()

 


 

 

File.to_property() Function - Can now automatically de-serialize a file that was serialized using property_to_string(), property_to_blob() or json_generate().

 

Example:

dim src.fname as c = "john"
dim src.lname as c = "public"
file.From_string("c:\data\sample.txt",property_to_string(src))
file.From_string("c:\data\sample.json",json_generate(src))
file.From_blob("c:\data\sample.dat",property_to_blob(src))


dim p1 as p
file.to_property("c:\data\sample.txt",p1)
? p1
= fname = "john"
lname = "public"


dim p2 as p
file.to_property("c:\data\sample.txt",p2)
? p2
= fname = "john"
lname = "public"

dim p3 as p
file.to_property("c:\data\sample.dat",p3)
? p3
= fname = "john"
lname = "public"


 

UX Component - Static HTML Web Sites - Publishing to Amazon S3 - If you have a static UX component (i.e. the component does not make any callbacks to an Alpha Anywhere server), you can publish the static HTML site to Amazon S3. The advantage of this is that you don't need to publish your site to an Alpha Anywhere server and the site will be accessible from any browser that has an internet connection.

 

VERY IMPORTANT - The Amazon S3 bucket that you publish to must be configured to allow 'Public Read' otherwise when you try to access the application Amazon will return a 'Permission Denied' error. To set the correct policy on your Amazon bucket, you can use this JSON setting string in the Amazon Web Services console.

 

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "AllowPublicRead",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::specify_the_name_of_your_bucket_here/*"
            ]
        }
    ]
}
 

 



Web Applications - Publishing - Check Security Before Publish - You can now check if any pages, components, or reports in the list of files to be published are set as 'Always Denied' in the web security. This is useful if publishing new pages or components to verify the security is set before the new elements are published. The check is only performed if security is active, and will check all pages, and components and reports if component security is activated. Most other files have security set by file extension.

If the option is selected and the file list to publish includes pages, components, or reports that are set as 'Always Denied', a list of these files will be shown before publish. You can continue with the publish or cancel and correct any errors.

This option can be selected at publish, and a default value for the option can be set in the publish profile. The option can also be set separately for right click publish.

Web Applications - Publishing - Publish Page Security as Binary - Some projects may have very large number of entries in the 'Pages.SecuritySettings' security file. The file is normally stored as a text file, but if it is very large (over 1 MB for example), it may load slowly on the application server when the security is loaded. This security file can be converted to a binary file when published which will load much faster. If the security cache timeout is set to 0 to never check for updates, a slow load time will only impact the first request for a project.
 

a5_url_fromStorageJSONformat() Function - Generates a signed URL to download a file from Amazon S3 storage.

The a5_url_from_storageJSONformat() function can be used to display/download a file from storage (e.g. Amazon S3) directly, with very little load on the Alpha server. The purpose of the function is to take a JSON string that defines the address of an object in storage (e.g. Amazon S3) and to generate a signed URL that can be used to download the object directly to the client from storage without having to first download the object to the Alpha server and then have the Alpha server send the file to the client.

 

The JSON string format that defines the address of an object in storage is:

{cs: 'storage connection string', object: 'name of object', source: 'vendor'}

 

NOTE: Currently the only vendor supported is Amazon S3 so vendor must be set to 'S3'

NOTE: The storage connection string is defined by selecting the Tools, Storage Connection Strings menu when the Web Projects Control Panel has focus. When you define storage connection strings you have the option of encrypting the storage connection string. You must NOT encrypt the storage connection string or else Alpha Anywhere will not be able to parse the storage connection string to determine your storage credentials.

 

For example, assume you have a named storage connection string called 'myS3bucket'. A JSON string that defines the address of an object called 'ProductPrices.pdf' would be:

{cs: 'myS3bucket', object: 'ProductPrices.pdf', source: 'S3'}

 

To generate a URL to display or download this object you would do the following:

 

dim address as c

address = <<%txt%

{   

    cs: 'myS3bucket',

    object: 'ProductPrices.pdf',

    source: 'S3'

}

%txt%

dim url as c

url = a5_url_from_storateJSONformat(address)

 

The resulting URL would look something like this (assuming that the bucket name specified in the connection string was 'myBucket'):

https://s3.amazonaws.com/myBucket/ProductPrices.pdf?AWSAccessKeyId=key&Expires=expiration&Signature=signature

Where:

key - your access key - as defined in the storage connection string

expires - indicates how long the URL can be used for (only applies if the object was uploaded to storage as 'Protected Read')

signature - a special signature based on the credentials specified in the storage connection string.

By default, the expires property is 240 seconds. That means that if the URL is used more than 240 seconds after it was generated, Amazon S3 will return a 'permission denied' error. The a5_url_from_storageJSONformat() function takes an optional second argument where you can specify how long the URL is good for in seconds. The default value for this parameter is 240.

 

 

 

File Upload - Amazon S3 - A new action has been added to Action Javascript for the UX component to upload files to a bucket in Amazon S3 storage.

NOTE: This action is not available for the Grid Component. However, the standard 'File Upload' and 'Image Upload' actions in Action Javascript, which are supported in the Grid now supports an option to target the upload to Amazon S3.


Watch Video - Part 1
Watch Video - Part 2

 

The benefit of this method is that the upload occurs directly to the Amazon servers without putting any load on the the Alpha Application Server.

NOTE: There is a small load on the Alpha Server for each file that is uploaded because a callback has to be made to the Alpha server to sign the URL used for the upload. This is necessary because the secret key for your Amazon account is stored on the Alpha server.

Features of the Amazon S3 File Upload include:

 

IMPORTANT: Before you can upload files to Amazon S3, you must configure your Amazon bucket to allow CORS support. CORS (Cross-Origin Resource Sharing allows you to make callbacks to a different server than the server (the Amazon server in this case) from which the page was originally loaded (your Alpha server). To configure your bucket you will need to open the AWS console.  You can click the 'Setting CORS Support on your Amazon Bucket' in the Action Javascript builder for more information.

 

In order to create an action to upload files to Amazon S3, use Action Javascript. Select the 'File Upload = Amazon S3 Storage' action.

 

 

The genie for this action is shown below:

 

 

 

Method for specifying Amazon S3 credentials and bucket - There are two ways in which you can specify the credentials for your Amazon S3 bucket. You can specify a named storage connection string, or you can use the 'Explicit' option, in which case you will need to specify your Amazon access key, secret and bucket name.

NOTE: To create a names storage connection string, go to the Tools menu when the Web Projects Control Panel has focus and select the Storage Connection Strings menu item.

 

 

Allow multiple files - If you check this box, the user will be able to select multiple files. The files will be uploaded in parallel.

If you check this box then you can specify value for the Max total file size property, which is the maximum combined size of all selected files. By default, this property is set to -1, which means no maximum.

Display progress during upload - If you check this property, then progress will be displayed during the file upload.

NOTE: If you do not check this property, you can still create your own progress display by adding custom code to the Javascript On Progress event.

Allow cancel - Specify if the user can cancel the upload after it has been started, but before it completes.

Progress indicator type - The progress can be displayed either as a text that shows the percentage complete, or as a bar.

In the image below, progress is shown for a multiple file upload using the 'bar' option. Note that the Allow cancel property was also checked, and so a small button to the right of the bar is shown where the user can click to cancel the upload.

 

This next image shows progress using the 'text' option.

 

 

Placeholder for progress indicator - You must specify the name of a Placeholder control where the progress will be shown.

Authenticated read - Allows you to specify whether the file that is uploaded to S3 is 'public read' or 'authenticated read'. A 'public read' file can be read by specifying the URL of the object on Amazon S3. For example, assume you upload a file called 'Image1.jpg' and you use the same object name on S3 (i.e. you don't specify any code in the Target object name on Amazon S3 event so that the name of the object on Amazon is the same as the filename of the file on the client-machine), you will be able to read the file using this URL:

 

http://<nameOfYourAmazonS3Bucket>.s3.amazonaws.com/Image1.jpg

 

If the Authenticated read property is checked then you can retrieve an object from S3 using Xbasic functions in server-side code.

For example, assume you wanted to retried 'Image1.jpg' which had been uploaded to S3 with the Authenticated read property turned on, you could perform an Ajax callback that executed this code to retrieve the file and save it to a local file called c:\myfiles\Image1.jpg.

 

dim cs as c

cs = "::storage::YourStorageConnectionStringName"

a5storage_getitem_as_file(cs,"Image1.jpg","c:\myfiles\Image1.jpg")

 

The full list of a5storage helper functions is shown below:

 

 

Validating File Selection

You can specify a maximum file size for any file that the user can select. By default this is set to -1, which means no maximum.

If the Allow multiple files property is checked you can also specify a maximum total file size for all files combined.

You can specify list of file types that the user can select in the Allowed file types property. You can enter a comma delimited list of file extensions. For example

.png,.jpg,.jpeg

 

You can also customize the error messages that are shown if a rule is violated. For example, in the image below, the message that will be shown if the user selects a file that is larger than 1,000,000 bytes is

File exceeds max allowed size of [maxfilesize]

[maxfilesize] is a placeholder that will be replaced at run-time.

You can also completely customize the display of validation error messages by defining your own on Validate Error event handler in the Javascript Events section. You can also use language and text dictionary tags (<a5:r>..</a5:r> and <a5:t>..</a5:t>) to translate the messages into different languages.

If you define a custom on Validate Error handler then you should blank out the default messages so that the system messages do not display.

 

 

 

Javascript Events

The genie exposes the following Javascript events:

Target object name on Amazon S3 - If this event is not defined, the name of the object in the S3 bucket will be the same as the name of the object on the client machine. For example, if the user uploads a file called 'sales_analysis_march_2015.xlsx', the name of the file in the Amazon bucket will be 'sales_analysis_march_2015.xlsx'.

Your code in this event can reference these variables:

 

However, you can add code to this event to compute a different name on S3. Your Javascript code must return the name you want to use. For example, assume you want to store the uploaded file in a folder called 'sales analysis' then your Javascript code in this event will be

return 'sales_analysis/' + e.name

 

Before file select - fires after the user clicks the button to initiate the action, but before any files are selected. If your code executes return false, the action is aborted.

After file select - fires after the user has selected the file(s) to upload, but before any uploads have actually started. Your code can reference a Javascript variable called e, which is an array of objects containing information about each file that was selected.  If your code executes return false, the action is aborted. You can use this event to perform custom validation on the selected files before initiating the upload. If you are writing a custom onProgress event handler you can use this event to set up the HTML for your custom progress indicator.

On progress - Fires each time progress information is returned by Amazon. You can use this event to create a custom progress handler. You code can reference these variables:

On Upload Complete - Individual File - (If multiple files are allowed) - fires after each individual file has been uploaded.

On Upload Complete - All Files - (If multiple files are allowed) - fires after all files have been uploaded.

On Upload Complete - (If only a single file is allowed) - fires after the file has been uploaded.

On validate error - Fires if any file violates the file rules (maximum size or allowed type).

 

 

File Download - Amazon S3 - A new option has been added to the File Download action in Action Javascript to allow you to download files that are stored in Amazon S3 storage.

The File Download dialog allows you to specify the File Download 'Type' as 'Amazon S3 Storage'.

 

Watch Video - Part 1
Watch Video - Part 2

 

 

Once you set the type as Amazon S3 Storage you can specify additional properties. These include:

 



 

 

Download Mode - Direct and Indirect Mode

When you download a file from Amazon S3  you have the option of using Direct or Indirect mode. Indirect mode is most like a regular file download, excepting that the file must first be retrieved from Amazon S3 before it can be sent to the user. The user will be prompted to save the file on his computer. This mode is inefficient because the file has to first be retrieved from Amazon S3 before it can be sent to the user. Depending on the size of the file being retrieved, this can place a heavy load on the Alpha Anywhere server.

The Direct method on the other hand is much more efficient because the file is downloaded directly to the client from Amazon S3 storage. A lightweight callback is still made to the Alpha Anywhere server to 'sign' the URL used to retrieve the file from S3, but this callback places very little load on the server.

When you download using the Direct method there are some additional considerations that you have to be aware of. The typical way in which the download is accomplished is by setting the URL of a hidden IFrame element on the page (which Alpha Anywhere automatically includes on the page) to the URL of the object on S3. So, for example, consider the case where the user wants to download a .xlsx file from Amazon S3. The URL to this object might be something like:

https://s3.amazonaws.com/bucketnameOnS3/myspreadsheet.xlsx

 

Setting the src property of the hidden IFrame to this URL will cause the browser to display a prompt asking the user if they want to save the file. The browser does this because it does not have a built-in handler for .xlsx files.

Now consider the case there the user wants to download a .pdf file from storage. In this case the URL to this object might be something like:

https://s3.amazonaws.com/bucketnameOnS3/mypdf.pdf

 

However, browsers typically do have built-in handlers for .pdf files and so setting the src property of the hidden IFrame to this URL will not result in the user being prompted to save the file. Instead, the browser will actually render the PDF, but the user will not see it because the IFrame is hidden.

Therefore, the Download Action builder prompts for the ID of the IFrame where PDFs will be rendered (TIP: Set the initial address of this IFrame to about:blank) . The user will still not receive a prompt to save the file, but they will see the PDF document rendered in the IFrame that they specified. Once the PDF has been rendered, they will be able to right click on it and then save it to their machine (since the PDF render feature of the browser exposes this option).

A similar situation exists for image files and therefore the ID of an Image element must be supplied to render the images that are downloaded from S3.

The ID of the elements for PDF and Image files are specified at these prompts in the builder:

 

 

Action Javascript - Image Upload Action - UX and Grid Component - Amazon S3 - The Image Upload action allows you to upload an image and store the image in a field in the table to which the UX or Grid component is bound.

In the case where the image is bound to a character field in the target table you now have the new option of uploading the image to Amazon S3 storage rather than to the Alpha Anywhere server.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

 

Uploading the image to Amazon S3 storage is an extremely efficient solution because it places minimal load on the Alpha server (both for uploading the image and then subsequently displaying the image when the component is run).

When you choose the option to upload to Amazon S3 storage you can either upload the image as:

NOTE: The Image Upload builder has a property called Authenticated read. To use the 'public read' option, the Authenticated read property should  not be checked. To use the 'protected read' option, the Authenticated read property should be checked.

When you upload using the 'public read' option, the image is uploaded to Amazon S3 and then the URL to the image is stored in the character field in the database. For example, this URL might look like:

https://s3.amazonaws.com/yourBucketNamehere/imageFileName

This URL can be pasted into a browser address bar and the image from Amazon S3 storage will be shown. In other words, it is not necessary to supply any credentials in order to see the image.

When you upload using the 'protected read' option, the image is uploaded to Amazon S3 as a protected file and the value that is stored in the character field in the database is a special JSON string that contains information about the storage connection string and the object name on Amazon S3. For example:

{cs: 'name of your storage connection string', object: 'name of object on S3', source: 'S3'}

 

 

NOTE: When you check the Authenticated read property you must use the Named Storage Connection String option as the Method for specifying Amazon S3 credentials.

 

When the component is rendered, the Alpha server automatically takes this JSON encoded string and computes a special signed URL that can be used to retrieve the image from S3. This special signed URL expires after a certain amount of time (current set to 240 seconds).

 

When an image is upload to S3 the work flow is as follows:

When the component is run, if the image field in the current row that is being displayed, contains the special JSON encoded string which is used for protected reads, the Alpha Anywhere server converts this JSON string into a signed Amazon S3 URL that can be used to retrieve the image.

 

To use the Amazon S3 image upload option in the Image Upload genie, select the Upload target property and set it to AmazonS3 as shown in the image below.

The options for the  Upload target property are:

 

Once you select AmazonS3 as the upload target the Amazon S3 Storage Properties section is displayed, allowing you to set your Amazon S3 properties. For a complete discussion on these properties see the topic that documents the 'File Upload - Amazon S3' action in Action Javascript.

 

 

 

Action Javascript - File Upload Action - UX and Grid Component - Amazon S3 - The File Upload action allows you to upload a file and store the file in a field in the table to which the UX or Grid component is bound.

In the case where the file is bound to a character field in the target table you now have the new option of uploading the file to Amazon S3 storage rather than to the Alpha Anywhere server.

 

Watch Video - Part 1
Watch Video - Part 2

 

Uploading the file to Amazon S3 storage is an extremely efficient solution because it places minimal load on the Alpha server when the file is uploaded. In addition, once the file has been uploaded to Amazon S3, when the file needs to be downloaded, there are options to configure the download so that the download takes place directly from Amazon S3 to the client, placing no load on the Alpha server, or in the case of a protected read (see below), placing minimal load on the Alpha server.

When you choose the option to upload to Amazon S3 storage you can either upload the file as:

NOTE: The File Upload builder has a property called Authenticated read. To use the 'public read' option, the Authenticated read property should  not be checked. To use the 'protected read' option, the Authenticated read property should be checked.

When you upload using the 'public read' option, the file is uploaded to Amazon S3 and the File Upload action builder gives you an option of storing the URL to the file in the character field, or a special JSON string that contains information about the file's location on S3.

If you choose the URL option, the format of the data stored in the field is:

https://s3.amazonaws.com/yourBucketNamehere/fileName

 

This URL can be pasted into a browser address bar and the file from Amazon S3 storage will be downloaded, (or shown -- if the browser has a built-in handler for the file MIME type).  It is not necessary to supply any credentials in order to retrieve image.

If you choose the JSON option, the format of the data stored in the field is:

{cs: 'name of your storage connection string', object: 'name of object on S3', source: 'S3'}

 

When you upload using the 'protected read' option, the JSON option is the only option.

 

NOTE: When you check the Authenticated read property you must use the Named Storage Connection String option as the Method for specifying Amazon S3 credentials.

 

When a file is upload to S3 the work flow is as follows:

To use the Amazon S3 file upload option in the File Upload genie, select the Upload target property and set it to AmazonS3 as shown in the image below.

The options for the  Upload target property are:

 

Once you select AmazonS3 as the upload target the Amazon S3 Storage Properties section is displayed, allowing you to set your Amazon S3 properties. For a complete discussion on these properties see the topic that documents the 'File Upload - Amazon S3' action in Action Javascript.

 

 

 

 

 

Xbasic Modules - Live Preview - If you do a 'Full Preview' when doing Live Preview, Xbasic Modules that are used in your Xbasic code are now automatically published to the Live Preview folder.

 

Reports - Layout Table Reports - 'Keep Row Together' Property - A new property is available for Layout Table reports. This property will prevent a page break in the middle of the row. This property is useful for 'growable' row content, such as HTML and Linked Reports.

 

 

Alpha DAO - ODBC - New SQL Connection Property = A5ODBCTableList - There is a new property available on the ODBC connection string dialog labeled 'ODBC Table List' and identified in the connection string as A5ODBCTableList.

The default value for A5ODBCTableList is false; meaning no change in behavior. When set to true, the selected vendor behavior will continue for most functionality. The one exception will be listing tables. This will defer to the ODBC driver as you would see if you used 'ODBC' as your vendor.

This new option provides a fallback for ODBC drivers giving better control over the list of tables than the native syntax implementation.

One use case for this option is to limit the number of tables displayed in AS/400 (DB2 iSeries); which tend to include an entire library list (like a path in Windows) and can be quite large. The DB2 iSeries driver has optional parameters for the library list that can be set when creating a DSN; and which our connection string is unaware of. Checking 'ODBC Table List' when connecting to the AS/400 DB2 iSeries driver through an ODBC DSN defers to the driver itself to create the table list.
 

UX Component - List Control - Export Data to Excel or Ascii - You can now export data in a List control to either Excel or to Ascii files.

Watch Video

 

After the export file has been created you can either download the file to the client, or call an Xbasic function to further process the exported file. A typical use case where you might want to call an Xbasic function to process the exported file would be if you wanted to email the file to a list of recipients, or upload the file to cloud storage, such as Amazon S3 storage.

In the case where the List is based on a SQL query you have the option of:

Consider the case where you have defined a List and have turned on the pagination feature. You might have set the page size to 100 rows. The query that the List is based on might have 1,000 records, but the List will only show 100 rows of data at a time. If the export is based on the 'Data in the List' the export file will have 100 rows in it (because the List only has one page of data - 100 rows - in memory at any time). However, if the export is based on 'Data in the List Query' the export file will have 1,000 rows in it (subject to the Max Records setting which might limit the number of rows in the export file).

To export data in a List you can use Action Javascript to define the code.

  1. Select the 'List Control Actions' in Action Javascript

  2. Select the 'Export List data to Excel/Ascii' action from the list of available actions.

  3. Click the smart field to define the 'Export list data settings'.
     

In the case where the List is based on a SQL query, the builder shows the 'Export what' property which can be set to 'Data in List query' or 'Data shown in List'.

If the 'Export what' property is set to 'Data in List query' the 'Maximum number of records to export' property is shown.

 

 

In the case where the 'Export what' property is set to 'Data shown in List' or if the List is not based on a SQL query (in which case the data that is exported is always the 'Data shown in List'), the 'Customize field sizes and column heading in export file' property is shown.

NOTE: The 'Customize field sizes and column heading in export file' property is only shown if the 'Export format' is Excel.

This property allows you to customize the column headings in the Excel file and control the data types of the data in the excel file.

 

 

 

To customize fields, click the smart field for the 'Customize field sizes and column heading in export file' property.

A build opens up where you can enter a CR-LF delimited list of definition - one for each field  you want to customize.

The syntax for the definition can be shown by clicking the 'Show syntax help' hyperlink.

The syntax allows you to specify the data type, size and column heading of each column in the Excel file.

 

 

UX Conponent - List Control - List with Detail View - .addTableRows() Method - Insert Rows - The .addTableRows() method now has new options to allow you to add the new row at a specified position in the List (i.e. insert rows), rather than at the end of the List (append rows). For information on the .addTableRows() method, click here.

 

 

Bugs

UX Component - Tab Controls - Method For Selecting Active Pane - Automatic - Nested Tabs - If you had nested tab controls and the outer tab was set to use the 'Automatic' method for selecting the active pane, the watch expression that selected the active pane was not being generated correctly.

UX Component - Android - Scrolling - Fixed an issue where (in certain cases), after editing in a text control in a component, you could no longer scroll a Panel Card to the top or bottom of the Panel Card.

UX Component - onSynchronize Server-side Event - Open UX in Window - Cached Option - If a data-bound UX component was opened in a pop-up window and the allow caching of the child UX feature was turned on, and if the child UX had a long-running onSynchronize event, it was possible for the primary keys in the child UX to get overwritten with the wrong values the second and subsequent times the child UX was opened. If this occurred, any edits to data made in the child UX would have been applied to the wrong record.

UX and Grid Component - Amazon S3 - File and Image Upload - Uploading files to S3 buckets that were not in the default US East region was not working correctly.

UX Component - Container Width 100% - Break - On some browsers, if you have a two consecutive containers, each with a width of 100% and you do not have the break between the containers turned on, you might get strange behavior when you scroll the Panel Card that contains that containers. Turning on the break between the containers resolves the issue. Now, if you set a container's width to 100%, the break in the Container End is automatically turned on.

TabbedUI Component - onLogout Event - Fixed various issues with the onLogout event.

Grid Component - AlphaDAO - Compound Primary Key - If you specified that a Grid had a compound primary key and you selected the columns in the Primary Key in the order in which they should appear in the Primary Key, Alpha Anywhere would define the Primary Key in the order in which the columns existed in the schema. For example, if you specified that the primary key was Lastname, Firstname, but the schema order was Firstname, Lastname, the primary key was defined as Firstname, Lastname. To fix the problem you must edit the existing grid and reselect the primary key columns.

UX Component - {dialog.object}.panelGet() Method - Previously, if you called this method with an invalid Panel name, the method returned the top-most Panel (root Panel). Now, false is returned.

UX Component - List Control - Multiple Layouts - onOrientationChange - If a List has a separate layout for Landscape and Portrait mode, now, when changing orientation, the selected row is remembered when the List layout is changed.

UX Component - Edit Combo - Different Stored and Display Values - Data Source Type Xbasic Function - Previously different display and stored values were only supported if the data source was AlphaDAO. Now, it is supported for Xbasic Functions.

Grid and UX Component - Export to Excel - Text Dictionary Tags - Text dictionary tags in column headings were not honored when exporting to Excel or Ascii files

Grid and UX Component - Export to Excel - SQL Databases - Dates - Dates are now exported using a date format that such that when the Excel file is opened the dates are shown using the regional settings of the machine. Previously the dates used a format that matched the regional settings of the server.

AlphaDAO - Postgres - Geography Searches - Fixed bugs in geography searches. Radius search was failing and case of search field was not properly preserved when the SQL WHERE clause was composed.

copy_folder() Function - Under some circumstances, the copy_folder() function did not copy files.

UX - List Control - Server-side Summary Fields - Under some circumstances the server-side summary fields values were not available in the 'summary' object when the afterServerSideSummaryFieldsComputed event was fired.

Grid Component - Read Only Grid - .getValue() Method - Empty Values  - If the .getValue() method was used to read the value in a control that was empty, the method would return '&nbsp;' for the value rather than a blank string.

Javascript Library - Date Object - .fromFormat() Method - The Alpha Anywhere Javascript library add a .fromFormat() method to the Javascript date object prototype. Under some circumstances (when using 'yyyy-MM-dd' as the date format string) strings representing date values were not correctly parsed into date objects.

UX Component Builder - Moving Controls Up/Down - Fixed an occasional error that was reported when moving controls up/down in the UX Component builder.

 

UX Component - onOrientationChange Event - Android - Fixed an issue where the onOrientationChange event did not fire on Android devices after the first orientation change, and then after that, it fired, but reported the wrong orientation. This bug resulted from know bugs with the Android orientation event that cause the screen size to be reported incorrectly when the orientation event is fired. We have worked around this issue by introducing a 300 ms delay after the system reports an orientation change before we read the screen size.

When computing the orientation on Android, the keyboard position is now ignored. Previously on Android if the screen was in (say) portrait mode and the keyboard came up, the onOrientationChange event would fire and report that the screen was in landscape mode. The onOrientationChange would also fire when the keyboard was dismissed. This is because when the keyboard is visible, the screen size that Android reports is affected by the size of the screen. On iOS, the keyboard does not affect the reported screen size.

If, for backward compatibility reasons, you want to use the old method on Android where the keyboard does affect the reported screen size, add this code to the onRenderComplete client-side event:

{dialog.object}._quirks = { keyboardAffectsScreenSizeCalc: true};

 

Navigation Component - iOS - Navigation component menus did not operate well on iOS devices.

Report Server - Temp File Cleanup - Under certain conditions temporary files created for SQL based reports were not being deleted when the report was completed. These files are now immediately deleted when the report is finished. The report server now uses the temporary file cleanup setting from the parent Application server to remove other old temporary files created by the report server.

UX Component - List with Detail View - Image Capture - Fixed an issue when a UX component had more than one Detail View image capture field on it.

UX Component - Panel Card - Text Area Control - Scrolling - Fixed an issue with scrolling text in a text area control when the control was in a Panel Card.

Excel Import - Determining Field Type of Imported Data - Made a change to Excel import so that more rows of the sheet are examined in order to determined the field type of each column in the Excel sheet.

UX Component - Arguments - Bound to Session Variables - If an argument value was bound to a session variable, the argument value was not getting updated on Ajax callbacks if the value of the session variable was changed after the component was initially rendered. Also, if the session variable was set in the onDialogInitialize or onDialogExecute server-side event, the argument values were not getting reset to the new value of the session variables.

Video Component - Opening from Button on uX Component - Under some circumstances, if you had a button to open a Video component on a UX component, it would fail.

UX Component - PhoneGap - Linked Javascript Files - {HeadSection} Directive - If a UX component linked a Javascript file and specified the special {HeadSection} directive, the linked file was not copied into the PhoneGap project folder.

Web Applications - Web Security - New Password Encryption - A new password encryption process has been added that generates a much longer encrypted value for a password. This is considerably more secure than previous encryption methods as a password cannot be decrypted even if a person has the project's password encryption key.

The security settings genie now has a new property on the 'User Id and Password Options' tab under 'Password Options'. If password encryption is selected, a 'Password use legacy encryption' option is shown. When checked, the system will use the legacy encryption method used in earlier Alpha Anywhere builds for any new passwords entered. If the option is not checked, any new passwords entered will use the new password encryption process.

New security systems will use have the 'Password use legacy encryption' property un-checked by default and will use the new encryption process. Existing security systems will initially have the 'Password use legacy encryption' property checked and will continue to use the older encryption methods. The property can be changed at any time and will only impact new passwords being entered. Existing passwords are not converted when the property is changed. The new process will still use any existing encryption key that has been defined for the web security.

This system is compatible with previous Alpha Anywhere builds as passwords encrypted in previous versions will still work. It is not necessary to convert any existing passwords.

However, all existing passwords in a project or published application can be converted to the new scheme if desired with a new utility function.

The function 'a5ws_RefreshPasswordEncryptionUtility()' can be run from the development program interactive window or the application server interactive window. When run from the development program, a list of all projects in the workspace that have security will be shown (unless there is only one project). When run on the application server, a list of all applications in the webroot that have security will be shown (unless there is only one application).

The function will convert all previously encrypted passwords in the selected application or project to the new password encryption. If the optional parameter 'UseLegacy' is set to True, all passwords will be converted back to the legacy encryption scheme.

 

NOTE: Only Alpha Anywhere builds after release build 2614-4409 can recognize passwords that are encrypted with the new method. If you want to roll back to build prior to 2614, you must first run the utility to convert all passwords back to the legacy encryption used in the earlier builds.


If you change the encryption key or add a new key, all existing passwords will be lost, and will need to be re-entered.

 

 Recommended Action

 

UX Component - Tab Controls - Fixed a bug where the UX would fail if the last control in a Tab Pane was hidden and the previous control was any type of container end control.

a5_merge_JSON_into_template() Function - Application Server - The a5_merge_JSON_into_template() function did not work when called from Xbasic code running in the Application Server. It only worked in the Development Server.

Xbasic Code - File System Dictionaries - Fixed a bug when exporting code to a File System Dictionary that was not relative to the Workspace.

UX Component - Arguments - OnSynchronize and OnDialogExecute Events - Under some circumstances argument values shown in the server-side onSynchronize and onDialogExecute events did not reflect the argument bindings that had been defined.

Javascript Code Editor - Code Colorization of Commented Out Code - Code in commented out sections was not always colorized correctly. This was a cosmetic bug - it had no effect on application.

Reports - SQL Data Source - Image File Reference Fields - Fixed a bug where Image File Reference fields were not working correctly.

Grid Component - Row Expander - Scroll Position on Page - If a Grid had been scrolled on the page and then a Row Expander for a row near the bottom of the page was opened and the user clicked on one of the rows in the Grid shown in the Row Expander, the parent Grid would scroll back to the top of the page. This is fixed now, but you can also work around the issue by using a master template in the child Grid and wrapping the master template in a div with a position:relative; style attribute. For example

<div style="position:relative;">

</div>

UX Component - Panel Cards - Tab Control - Hidden Controls - If a UX component used Panel Cards and you had a Tab Control in one of the Panels, if the last control in a given Tab Pane was hidden, the UX would fail. This is now fixed but you can also work around the bug by simply moving the hidden control up so that is is no longer the last entry for the Tab Pane.

UX Component - Pop-up Window - Google Map - As a result of a recent change Google made to Google Maps, the following pattern had stopped working:

  1. create a UX with a map control in a container window
  2. create a button to show the window

When the UX was run the map, which should have been hidden because the window had not yet been shown, should have been hidden, but was not. This is now fixed.

List Control - Image Fields - Missing Images - In some situations, the 'missing image' for a field that did not have an image, was not being displayed.

Grid Component - Geography Search - Radius Search - If you performed a search for all records within a specified radius of a point and you specified that the search result should be sorted by distance from the center point, then if you tried to navigate to the next page of records in the search result you would get an error.

Tips

UX Component - List Control - Using a Slider Control to Scroll a List - Say you have a List control and you want to put a Slider control under the List to scroll the List. Assume that the name of the Slider control is 'Slider1'

 

Step 1 - Put this code in the List's AfterRenderComplete event

var s = {dialog.object}.getControl('Slider1');
var l = {dialog.object}.getControl('{dialog.listId}');
s.min = 0;
s.max = (l._data.length -1);
s.refresh();

 

This code sets the min/max values on the slider to match the row count of the List.

 

Step 2 - Put this code in the Slider control's onSlide event:

var l = {dialog.object}.getControl('LIST1');

//the value of the slider while it is being dragged is in arguments[0].value
var val = arguments[0].value
l.scrollToItem(val);
 

 

 

UX Applications - PhoneGap - iOS Native Date Picker - If your UX component allows editing for date field fields you might want to use the native iOS Date Picker in your app. This is easily done by:

1. Setting the HTML5 type for the textbox where you edit the value to 'date'

2. Setting the display format for the textbox to yyyy-MM-dd

3. If the UX uses a List control with a Detail View the client-side display format for the date field can be set in the List Control, Fields tab.

 

UX Component - List with Detail View - Searching while Offline - When you use the List Detail View genie to create a List control with an associated Detail View and Search part, the genie inserts code like this in the Search button's click event:


{dialog.object}.getControl('name_of_the_list').searchList({searchMode : 'auto'});
 

The 'auto' in the .searchList() method means:

1. if the List is not dirty then do a server-side search
2. if the List is dirty do a client-side search (because doing a server-side search would repopulate the List and blow away your unsynchronized edits)
 

If your List is not dirty and you do not have a connection, the command will do a server-side search (because the List is not dirty), but because there is no connection, the search will obviouslyfail.

Once approach is to test for connectivity before doing the search, and if there is no connection, then automatically switch to a client-side search. For example, you can change the code in the button's click event to:


var flag = {dialog.Object}._getOnlineStatus();
if(flag) {
    // device is connected - ok to so a server-side search
    {dialog.object}.getControl('name_of_the_list').searchList({searchMode : 'auto'});
} else {
    // device is not connected - must do a client-side search
    {dialog.object}.getControl('name_of_the_list').searchList({searchMode : 'clientSide'});
}
 

 

 

UX and Grid Component - Tab Controls - Right to Left - For Hebrew and Arabic applications you might want the Tab buttons on a tab control to be displayed right to left, rather than the standard left to right format.

To do this, you can add the following CSS markup to the Local CSS property in the component.

 

.{dialog.style}TabTButton, .{dialog.style}TabTButtonSelected, .{dialog.style}TabBButton, .{dialog.style}TabBButtonSelected {

       float: right;
}
 

 

Application Server - Silent Install - The Alpha Anywhere server installation program can be run in 'silent mode' by using the /S command line switch.

 

For example:

 

a5v12_AppServer.exe /s

 

However, the first time you install the Alpha Anywhere server on a machine you will need to specify your license key. Since you are doing a silent install, you cannot enter the license key in the Application Server UI as you normally would do.

You can add the license key to a special registry key and Alpha Anywhere will automatically install the license if it is found in this registry location.

The registry key in which you must install your license number varies depending on whether you are running on a 32 bit or 64 bit operating system.

 

The following command line shows how you can add your license number to the appropriate registry key

 

For 64 bit operating systems

reg add "HKLM\SOFTWARE\Alpha Software\Alpha Anywhere Application Server 12.0\httpd" /v ActivateLicense /t REG_SZ /d "yourlicensenumber"

 

 

For 32 bit operationg systems


reg add "HKLM\SOFTWARE\Wow6432Node\Alpha Software\Alpha Anywhere Application Server 12.0\httpd" /v ActivateLicense /t REG_SZ /d "yourlicensenumber"

 

The commands to add the registry key should be executed before you run the Alpha Anywhere install.
 

You can also specify the install path and the install group when you run the installer by setting Environment variables before you run the installer.

The installer reads the following environment variables

For example, from the Windows command prompt:

SET A5_MAINDIR=c:\AlphaAnywhere\Server

 

PDF Report Print on Development Server But Not Production Server - Occasionally we here from developers who report that their PDF reports are working fine on their Development server but when they deploy their application to their production server, the PDF reports do not print. The error that is report is:

 

Report did not print. Error reported was:
Report Server: 'Alpha Five Printer' (for creating PDF, RTF and HTML output) is not installed. Re-install Alpha Anywhere Application Server at line: 27

 

The error indicates that the Amyuni Printer Driver (also called the 'Alpha Five Printer') did not install properly on your server machine when the Alpha Anywhere Application Server was installed.

Here are some things you can check to resolve the problem:

 

That indicates the print driver did not install.  This can happen for a couple reasons.

  1. If you were not logged in as an administrator when the Application Server was installed the driver may not have installed.
  2. The driver may have installed, but isn't assigned to a port.
  3. The Application server is running under a system account
  4. The server is running under Server 2012 or Win 8 and the Windows Print Spooler is not running


The first issue can be checked and corrected fairly easily.  Log onto the server machine with administrator rights.  Open the "Devices and Printers" from the Windows control panel and see if the driver for "AlphaFivePrinterV4p5" is installed.  If it is, then open the "Printer Properties" and verify the printer is assigned to a port.  Normally, it is assigned to a NUL port.
If the printer isn't listed, open Windows Explorer or My Computer, and look for the folder that contains the Alpha Anywhere Application Server program.  It would normally be at:


C:\Program Files (x86)\a5V12 ApplicationServer

Find the subfolder named "AmyuniV4" and find the file "InstallAmyuniPrinters.exe".  Right click on the file and select to "Run as Administrator".  A window should open showing the progress.  If it fails to install, check any error message.  If it fails, the last issue may be the problem as Windows may not install any print driver if the spooler is not running.

If the driver is installed, or installs correctly, then the problem may be is the user rights.  If running the Application Server as a service with srvany, or under AlwaysUp, make sure the user login is not the "Local System Account". That account does not normally have printing privileges.  Is is best to run the program under a user with full administrator rights

 

UX Components - Panel Cards - Child Components that Open in a Parent Component Panel -- A common pattern when building mobile applications using the UX component is to have a master component with one or more  Panel Cards and then have buttons that open child components in a Panel Card in the master component.

When utilizing this pattern be sure to turn off the 'Body can scroll' property for the target Panel (i.e. the Panel in which the child UX will be rendered).

 

 

 

Alpha Anywhere V3.11 - Build 2689-4440 4-Feb-2015

 

Videos

UX Component Hiding/Showing/Enabling/Disabling Buttons in a Button List Control You can use Javascript to dynamically hide, show, enable and disable buttons in a Button List control on a UX component. You can also dynamically add and remove buttons from the Button List.

In this video we show the Javascript to dynamically alter the Button List.

Watch Video
Download Component

Date added: 2015-01-30

 

 

Features

Web Applications - Publishing Using FTP - CURL - When you publish your web application to an ISP, your publishing profile will typically specify that the method for publishing the files is FTP.

You then have the option of using either the built-in FTP features in Alpha Anywhere, or using an external FTP client.

If you choose to use the built-in FTP features in Alpha Anywhere, you now have a new option of using CURL FTP. Unlike the standard FTP feature in Alpha Anywhere (which uses Active mode), the CURL FTP option supports passive mode. Passive move is more reliable as is has enhanced error checking and error messages.

NOTE: Some FTP servers require passive mode and will not support the standard built-in Alpha Anywhere FTP features, which use active mode. In this case you must use the CURL FTP option.

 

To select the CURL option, check the 'FTP Publish with CURL' property in the Profile Editor dialog.

Passive mode FTP is slower than active mode FTP, especially when uploading a lot of files, rather than one large zipped file. Therefore it is recommended that you only use the CURL FTP option when using the 'InternalOptimized' option (which zips all of the files to be published into a single zip file).

 

 

UX Component - List Control - Disconnected Data Entry - Preventing Duplicate Records when Connectivity is Lost - When you are working with disconnected data in a List control there is a small possibility of a synchronization request being submitted to the server more than once - resulting in the possibility of duplicate records in the database.

To understand how this might happen, consider what happens when the user clicks the 'Synchronize' button on a device to synchronize edits that were made while offline.

  1. A JSON packet containing all of the edits that were made to the List (including any child Lists) is sent to the server.
  2. The server processes the updates.
  3. After the server has completed processing the updates, the server sends a response back to the client indicating which rows were successfully synchronized and which rows have errors. This response will set the 'dirty' state of each row in the List that had been edited back to 'clean'.

Obviously, in order for the server to receive the synchronization request, the user must have a connection. But suppose that AFTER the user sends a synchronization request to the server, but BEFORE the server completes the work and can send a response back to the client, the client looses connectivity.

The server will continue processing the updates to the server and will do all of the synchronization requests contained in the package sent from the client. The server does not know that the client is now offline and so, after it completes all of the work, it will send a response to client indicating which rows were successfully synchronized. However, since the client is now offline, the client will not receive this message from the server. This means that all of the rows on the client that were edited are still marked as 'dirty' (even though the server has successfully applied all of the edits).

Now assume that the client gets its connection back and the user clicks the 'Synchronize' button again. The client will send a JSON package to the server and this package will include all of the updates that were previously sent to the server.

In order to protect against this possibility, a special server-side log can be used to prevent synchronization commands from being executed more than once.

In order to turn on the server-side synchronization log, edit the List control and on the Detail View pane, check the Use server-side synchronization log table property.

 

 

 

Before you can check this property however, you must first define the setting for the Synchronization Log Table. To define these settings, click the Project Properties button when the Web Projects Control Panel has focus.

Scroll to the Offline Data Synchronization Log Table Settings section and set the properties for the table. You can map this table to an existing table in your SQL database or Alpha Anywhere can create a new table for you with the correct table structure.

 

 

Bugs

UX Component - List Control - Dynamic Images - Client-Side - Fixed an issue with dynamic, client-side images in a List control. Image did not display correctly after data in the List had been edited.

Grid Component - Linked Grids - Detail View - New Record - If a child Grid was linked to a parent Grid, when going to the new record in the child Grid's Detail View, the linking fields in the Detail View were not filled in with the linking values as they should have been.

Reports - Native SQL - Dynamic Filter at Runtime - If a report was based on native SQL, rather than portable SQL, then if you tried to apply a dynamic run-time SQL filter to the report, the dynamic filter was ignored. Now, the dynamic filter will be added to the native SQL query for the report. However, because this may be combining a native SQL query with a portable dynamic filter, there is no guarantee that the resulting SQL statement will execute correctly.

Video Finder - A bug was introduced in the previous update that prevented the Video Finder from opening.

 

 

Alpha Anywhere V3.11 - Build 2684-4438 30-Jan-2015

 

Bugs

UX Component - Signature Capture - Build 2682 introduced a bug when saving data from a signature capture control.

Grid Component - Linked Grids - Up/Down Keys - In some cases when using the up/down keyboard navigation keys to navigate in the child grid, the keystrokes were being handled by the parent Grid.

 

Alpha Anywhere V3.11 - Build 2682-4435 28-Jan-2015

Videos

UX Component  Dynamically Re-populate the Choices in an Edit-Combo using Javascript The choices shown in an edit-combo can be dynamically repopulated at run-time using Javascript.

Watch Video

Date added: 2014-12-21
UX Component Constraining an UX that has Panels to an Element Rather Than Entire Window When a UX component that uses Panels is rendered, by default it consumes the entire window (only true if UX uses Panels). That means that if you have created an .a5w page to render the component and placed HTML markup on the page that you would like to be rendered in addition to the UX component, that markup will be overwritten by the UX. An advanced property of the UX now allows you to specify that the UX should be constrained to an element, rather than the entire window.

In this video we show how an .a5w page can be defined with a DIV to contain the UX and how the UX can be configured so that it is constrained to this DIV element.

(Requires build 4411 or above).

Watch Video
Download Component

Date added: 2014-12-22
     

 

 

Features

Publishing Web Applications - Publishing Profiles - Lock Profile - A new property has been added to each publishing profile. The 'Lock' property allows you to lock a profile to prevent accidental publishing to a deployed application.

The 'Lock' property can be set to blank (not locked), 'Locked' or 'Locked with password'.

At publish time, if you select a profile that has been locked, the publish will be aborted. If you select a profile that is 'locked with password', you will be prompted for a password before publish continues.

UX Component - List Control - List Builder - Resizeable - The List builder dialog window is now resizeable.

 

ui_bitmap_info_get() Function - Image Type - Now can return the image type of image binary data.

Syntax:

c type = ui_bitmap_info_get(b blobImageData,"T")

 

Example

dim b as b

b = file.to_blob("c:\images\image1.jpg")

? ui_bitmap_info_get(b,"T")

= "JPG"

 

 

UX Component - List Control - Numeric Fields - Client-side Display Format - The List Builder now allows you to specify a client-side display format for numeric fields. Previously you had to define a client side display format by directly editing the template for the field. This method is easier than editing the template.

 

 

AlphaDAO - MS SQL Server - DateTimeOffset Field Type - Support has been added for the SQL Server DateTimeOffset field type.

The Alpha Anywhere support for the SQL Server DateTimeOffset type works as follows:

UX Component - Web Security Server-Side Action Scripts - The web security action scripts in a UX component now allow the password to be optional in the variable mapping even if the security setting require a password. The password is optional if the component can only edit an existing security record. The password mapping is required if the component can add a new user security record. A warning message will appear when the action script is saved if a password variable is not specified.

 

Xbasic Code Editors - JSON Strings - Real-time Validation - If you use the specify <<%json%... %json% delimiters to enter a long string of JSON data, the Xbasic editor will perform real-time validation on the JSON data.

For example, in the image below, the JSON has an error because of the trailing comma after the last property (age: 23). Notice the squiggly red line indicating the error. If you click on the error indicator you will see the error message.

 

Reports - Free-form Reports - Text Dictionary Tags - You can now use text dictionary tags (<a5:t>...</a5:t>) to internationalize the labels in a report.

For example, you can set the label of a column to

<a5:t>Last Name</a5:t>

 

Next, turn on the text dictionary feature in your web application by going to the Web Projects Properties dialog when the Web Projects Control Panel has focus and specify the connection string and table name for your text dictionary.

To define entries in the Text Dictionary select the 'Text dictionary...' menu item from the 'Reports', 'Label' or 'Letter' menu while you are editing the report, label or letter.

 

 

json_to_xml() Function - ATOM Format - The json_to_xml() function can now generate XML using the "atom" format:

 

For example:

 

js = <<%str%
{
    "OrderId":10248,
    "ProductID":11,
    "UnitPrice":14,
    "Quantity":12,
    "Discount":0
}
%str%

dim xml as c
xml = json_to_xml(js)

 

 

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <OrderId>O10248</OrderId>
    <ProductID>11</ProductID>
    <UnitPrice>14</UnitPrice>
    <Quantity>12</Quantity>
    <Discount>0</Discount>
</data>
 



dim format as c
format = <<%str%
{ "format" : "atom"}
%str%

dim xml as c = json_to_xml(js,"",format)

<?xml version="1.0" encoding="UTF-8"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
    <atom:content type="application/xml">
        <m:properties>
            <d:OrderId>O10248</d:OrderId>
            <d:ProductID>11</d:ProductID>
            <d:UnitPrice>14</d:UnitPrice>
            <d:Quantity>12</d:Quantity>
            <d:Discount>0</d:Discount>
        </m:properties>
    </atom:content>
</atom:entry>

 


 

UX Component - Panels - Render Position - By default, when a UX component that has Panels is rendered, it consumes the entire window. In certain cases you might want to constrain the UX to a particular element.

 

The 'Render position type for UX component with Panels' property allows you to constrain a UX with Panels to a specified element. The default for this property is 'window'

 

 

Watch Video

Bugs

Dynamic Connection Strings - Field Validation - Cross-file Validation Rule - Was not honoring dynamic connection strings.

UX Component - PhoneGap - Windows Phone 8.1 - Ajax callbacks in PhoneGap applications on Windows Phone 8.1 were not working.

AlphaDAO - SQL Server - Varchar fields - Memory Leak - Fixed a memory leak when executing update statements that used arguments.

UX Component - List Control - Detail View - Image Capture using Camera - PhoneGap - Fixed an issue where the image was lost when the data was synchronized. This issue only occurred in PhoneGap applications.

UX Component - List Control - No Records in List Message - List Virtualization - The 'no records in list' message did not display if List Virtualization was turned on.

Security Framework - Editing an Existing User - Under some circumstances you would get an error when trying to edit the properties of an existing user account.

UX Component - Client-side onSynchronize Event - Changed the order in which this event is fired. It is now fired after the code that sets argument values in the stateInfo object has executed.

UX Component - Chart Control - Javascript Events - If you executed an event (say a click on a pie chart slice) and the data that was passed to the event handler had single quotes in it, you would get a Javascript error.

UX Component - Tab Controls - Panels - Fixed a bug rendering nested Tab controls when the UX used Panels.

Web Applications - Security Framework - Alternate Login - Under certain conditions, when a new user was added a duplicate record in the security tables was being created.

UX Component - Buttons - Label Position - If a button (or other non-data control) had its label position set to some value other than 'None' the control did not render correctly. This bug was introduced in the previous update.

Grid Component - Edit-combo - v.hasStoredValue Error Message -  If a Grid that contained an edit-combo was built using an older version of Alpha Anywhere and then run using Version 3.1 you would get an error stating that the v.hasStoredValue property was not found. The solution was to edit the edit-combo and then re-save it. Now, it is no longer necessary to edit edit-comb control and re-save it.

PhoneGap Build - Unable to Log-in to PhoneGap Build from the PhoneGap Genie - As a result of a change in the ca-cert.pem certificate file (in the CARoot folder in the Alpha Anywhere executable) that was made in build 4410, you were not able to log into PhoneGap. This update installs a new ca-cert.pem file which fixes the problem.

Tips

Chrome Browsers - Making Text Selectable - By default when running a component (Grid or UX) in Chrome, the static text (not the text in textarea or textbox) is not selectable. Alpha Anywhere does this automatically so that when a component is run on a mobile device, you do not unintentionally select text when dragging on different parts of the screen.

However, in a desktop application you might want the static text to be selectable. Here is how you can do this for a Grid:

Specify that the Grid has a master template. Then define a custom template using this HTML markup:

<div style="-webkit-user-select: text; ">
    {grid.Search_Part}
    {grid.Grid_Part}
    {grid.DetailView_Part}
</div>

 

Xbasic - OLE Automation - Implementing Callback Event Handlers in Xbasic - This topic discusses how you can write Xbasic code to handle callback events when running OLE automation code.

For example, consider the following Xbasic code that uses the ADODB.CONNECTION object to connect to SQL server and then execute a SQL command.

 

dim adow as ADODBOleWrapper
dim conn as p = ole.create("adodb.connection" )
conn.Open("driver={SQL Server};server=LOCALHOST;database=Northwind")
conn.Execute("select * from customers")
conn.Close()
 

 

When this code executes, it will raise these events:

In order to handle these events with Xbasic code you need to pass in an optional second argument to the ole.create() method.

 

First, to get the function prototype for the event handlers you can use this method:

dim events as c

events =  ole.Class_Event_Prototypes("adodb.connection")

showvar(events)

 

Once you have the function prototypes, you can create an Xbasic class using this pattern:

 

define class ADODBOleWrapper

'Your class code goes here

implementation EventHandler as OLE::A5Events

    'your Xbasic code to handle the callback functions goes here
end implementation

end class

 

Note that the class has a special 'implementation' section where the OLE callback handlers are defined.

For example, let's create a real class that writes the name of the event that was raised to a property of the class (called 'traceEvents').

 

define class ADODBOleWrapper
dim traceEvents as c

function TraceEvent as v(event as c)
self.traceEvents = self.traceEvents + event
end function

implementation EventHandler as OLE::A5Events
function begintranscomplete as v(TransactionLevel as N,pError as a,adStatus as a,pConnection as p)
self.TraceEvent("begintranscomplete "+TransactionLevel+crlf())
end function

function committranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("committranscomplete "+crlf())
end function

function connectcomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("connectcomplete "+crlf())
end function

function disconnect as v(adStatus as a,pConnection as p)
self.TraceEvent("disconnect "+crlf())
end function

function executecomplete as v(RecordsAffected as N,pError as a,adStatus as a,pCommand as a,pRecordset as p,pConnection as p)
self.TraceEvent("executecomplete "+crlf())
end function

function infomessage as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("infomessage "+crlf())
end function

function rollbacktranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("rollbacktranscomplete "+crlf())
end function

function willconnect as v(ConnectionString as C,UserID as C,Password as C,Options as a,adStatus as a,pConnection as p)
self.TraceEvent("willconnect "+crlf())
end function

function willexecute as v(Source as C,CursorType as a,LockType as a,Options as a,adStatus as a,pCommand as p,pRecordset as p,pConnection as p)
self.TraceEvent("willexecute "+crlf())
end function

end implementation

end class

 

As you can see, this class defined a method called TraceEvent() which writes to the 'traceEvents' property of the class instance.

In the Implementation section, the event handlers are all defined and they call the TraceEvent() method (using self.TraceEvent() ) to write the name of the event that was just fired to 'traceEvents' property of the class instance.

 

Now, putting this all together, we can rewrite the OLE automation code as follows:

 

 

 

'DIM an instance of the class

dim adow as ADODBOleWrapper

 

'pass the class into the ole.create() call

dim conn as p = ole.create("adodb.connection" , adow )

conn.Open("driver={SQL Server};server=LOCALHOST;database=Northwind")

conn.Execute("select * from customers")

conn.Close()

 

'show the value of the class instance 'traceEvents' property
showvar( "Events " + crlf() +adow.traceEvents )
 

 

 

This next example is a different take on the previous example in which .open(), .execute() and .close() are implemented as methods of the class instance.

 

 


define class ADODBOleWrapper2
dim conn as p
dim traceEvents as c

function TraceEvent as v(event as c)
self.traceEvents = self.traceEvents + event
end function

implementation EventHandler as OLE::A5Events
function begintranscomplete as v(TransactionLevel as N,pError as a,adStatus as a,pConnection as p)
self.TraceEvent("begintranscomplete "+TransactionLevel+crlf())
end function


function committranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("committranscomplete "+crlf())
end function


function connectcomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("connectcomplete "+crlf())
end function


function disconnect as v(adStatus as a,pConnection as p)
self.TraceEvent("disconnect "+crlf())
end function


function executecomplete as v(RecordsAffected as N,pError as a,adStatus as a,pCommand as a,pRecordset as p,pConnection as p)
self.TraceEvent("executecomplete "+crlf())
end function


function infomessage as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("infomessage "+crlf())
end function


function rollbacktranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("rollbacktranscomplete "+crlf())
end function


function willconnect as v(ConnectionString as C,UserID as C,Password as C,Options as a,adStatus as a,pConnection as p)
self.TraceEvent("willconnect "+crlf())
end function


function willexecute as v(Source as C,CursorType as a,LockType as a,Options as a,adStatus as a,pCommand as p,pRecordset as p,pConnection as p)
self.TraceEvent("willexecute "+crlf())
end function
function ping as v()
self.TraceEvent("PING "+crlf())
end function

end implementation

function adodbolewrapper2 as v ()
self.conn = ole.create("adodb.connection",self)
end function

function Open as v( connectionString as c )
self.conn.Open(connectionString)
end function


function Execute as v( sqlStatement as c )
self.conn.Execute(sqlStatement)
end function


function Close as v( )
self.conn.Close()
end function
end class
 

 

 

To test this example:


 

'dim an instance of the class. this class has a constructor function

'which will execute when the class is dimmed
dim adow as ADODBOleWrapper2
 

'now call the methods of the class instance
adow.open("driver={SQL Server};server=localhost;database=Northwind")
adow.execute("select * from customers")
adow.close()

showvar( "Events "+crlf() + adow.traceEvents )
 

 

Alpha Anywhere V3.1 - Build 2614-4409 18-Dec-2014

Videos

UX Component Tutorial - Uploading Files using the File Upload - User Defined Action There are two different actions in Action Javascript for uploading files from a UX component. If the UX component has been 'data bound' then the 'File Upload' action is appropriate. But if the UX component is not data bound, or if you want to write your own handler for the binary data that was uploaded to the server, the 'File Upload - User Defined' action should be used.

When you use the File Upload - User Defined action, an Xbasic function that you define is called after the file (or multiple files if you choose to allow multiple files to be uploaded) has been uploaded. Your Xbasic function is free to process the uploaded data in any way.

In this video we show how the File Upload - User Defined action can be used to save the uploaded data to a file on the server.

Watch Video - Part 1
Watch Video - Part 2
Download Component

Date Added: 2014-10-02
UX Component Tutorial - Uploading Files and Images to a Data Bound UX Component When you upload a file or an image to a data bound UX component, the assumption is that you want to store the uploaded image or file in the record to which the UX component is bound. You can either store the binary data that was uploaded in a field in the record, or you can save the binary data that was uploaded into a file on the server and then store the filename of the file in a character field in the record.

In this video we show how image upload and file upload to a data bound UX component can be done. Images and files are uploaded to both binary and character fields in the record.

Introduction
Watch Video - Part 1

File Upload to a Character Field
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4


File Upload to a Binary Field
Watch Video - Part 5
Watch Video - Part 6

Image Upload to a Character Field
Watch Video - Part 7
Watch Video - Part 8

Image Upload to a Binary Field
Watch Video - Part 9

Download Component
(Note: The zip file also contains the MySQL SQL script to create the table that the UX component is based on.)

Date Added: 2014-10-02
UX Component Using the CSS Calc() Function Instead of Flex Layout Containers to Create Dynamically Sized Controls A common requirement when building UX components is to create a row of controls where some of the controls are fixed size and the other controls dynamically contract or expand to consume the remaining space on the row.

Typically, the Flex Layout container is used to achieve this design goal, but the built-in CSS calc() function is an alternative (and simpler) way for achieving the same result. The drawback of the calc() function is that not all versions of the Chrome browser on older Android devices support the CSS calc() function.

In this video we contrast the use of Flex Layout containers and the CSS calc() function.

Watch Video
Download Components

Date Added: 2014-10-12
UX Component Getting the Display Value in a DropdownBox Control When you define the choices in a Dropdownbox Control you can specify both the display value and the stored value for each choice in the control. When you read the value from the control (using the .getValue() method), the stored value is returned. In some cases you might want to read the 'display' value.

In this video we show how you can write a small amount of Javascript to read the dropdownbox control's display value.

Watch Video
Download Component

Date Added: 2014-10-13
UX Component Intro to JSON JSON is ubiquitous in Web application development. Having a good understanding of JSON is very helpful in building web applications. In this series of videos we introduce you to various ways in which you can work with JSON on the server side (using Xbasic) and on the client-side (using Javascript).

We show how JSON is the ideal way for sending complex data from the client to the server, or from the server to the client (in an AJAX callback).

Using Xbasic on the server-side to work with JSON
Watch Video  - Part 1
Watch Video - Part 2
Watch Video - Part 3

Using Javascript on the client-side to work with JSON
Watch Video - Part 1
Watch Video - Part 2

Using JSON to send complex data to the server from the client
Watch Video - Part 1
Watch Video - Part 2

Using JSON to send complex data from the server to the client
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

Advanced example - sending complex data from the server and formatting the data for presentation on the client side using a template
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4

Download component

Date Added: 2014-10-15
UX Component - Disconnected Applications Showing Which Fields Have Been Edited When you have a List with an associated Detail View and you edit the data in one of the rows of the List, an icon (whose appearance you can customize) is shown in the List row to indicate that the List row has data that has been edited, but not yet synchronized.

In this video we show how you can indicate the dirty fields in a List row that has been edited. You can specify a custom CSS class to apply to the Detail View control if the field value has been edited.

Watch Video
Download Component

Date Added: 2014-10-18
UX Component - Mobile Applications Panel Navigator with a Button Bar To Select Active Panel - Quick Start Templates A common design pattern when building mobile applications is to use a button bar in the footer of the screen to select the active 'page' in the application. The selected button should be highlighted so the user knows which button corresponds with the current page.

In this video we show how you can use a built-in template to get a quick start on your application if you want to use this pattern. We explain what's going on behind the scenes so that you understand how the component works.

Watch Video - Part 1
Watch Video - Part 2

In the next video we show how the component can be extended to allow for more navigation buttons that can been seen at once on a phone. The user can drag scroll horizontally on the button bar to see the other buttons.

Watch Video


Date Added: 2014-10-28
UX Component Video Player Control The UX Component now includes a Video Player control. Previously, to include videos in the UX component, you created a Video Player component and embedded the  Video Player component in a UX control. Using the new Video Player control is much easier. In addition, there are new actions in Action Javascript that allow you to perform actions on the Video Player control.

Watch Video
Download Component

Date Added: 2014-11-15
UX Component Embedded Components - Delay Render - Techniques (This video is aimed at advanced developers.) A common pattern in large applications is to design a UX component that has several embedded components. The embedded components are typically on different Panel Cards that are all wrapped in a Panel Navigator. The embedded components all have their 'Delay render till visible' property set to true so that the initial load of the parent UX is not slowed down.

However, while the user is working on PanelCard 1 (for example), you might want to fire off a Ajax callback to load PanelCard2's embedded components in the background so that when the user does eventually navigate to PanelCard 2, the embedded component has already been loaded and the user does not perceive any delay.

This video shows how this can be done.

Watch Video
Download Components

Date Added: 2014-11-19
UX Component Using a 'Slider' to Display the Value in a Numeric Field In a List control that display numeric values, instead of displaying the number, you might instead want to use a 'slider' to represent the numeric values.

This video shows how the template for the numeric field can be easily modified to display the number using a 'slider'.

Watch Video
Download Component

Date Added: 2014-11-19
UX Component - List Control Displaying a Google Map in Each Row of a List In this video we show how you can add a Google Map to each row in a List to display the position of a point in the current row on a map.

Watch Video
Download Component

Date Added: 2014-11-19
UX Component Printing a Report Using Same Filter/Order as a List Control A common pattern in Grids is to have a button on a Grid that prints a report showing the same records that are in the current Grid query. Now you can use a similar pattern for List controls on a UX component.

In this video we show a UX with a List control. The List control is based on a SQL query and the UX has a button that allows you to perform a server-side filter on the List (for example, search for all records in France or Denmark).

The UX has a button that prints a report that is based on the same SQL tables as the List and automatically uses the same filter for the report as the List.

Watch Video

Date added: 2014-11-27
Miscellaneous Javascript File Editor When you edit a Javascript File from the Web Projects Control Panel, the editor used to edit the file was previously a modal editor. It has now been rewritten to use a MDI window, which means you can leave the editor open while you work on other files. Also, the editor has an integrated Interactive Window that allows you to test Javascript code.

Watch Video

Date added: 2014-11-30
UX and Grid Component Xbasic Function Library When a component makes an Ajax callback, an Xbasic function that you define handles the callback. This function is typically defined within the component (in the Xbasic Function Declarations section). This means that the function definition cannot be used in some other component.

By defining the function in an Xbasic Function Library that is linked into the component, you can now easily define Xbasic functions that can be shared among multiple components.

NOTE: Xbasic Function Libraries are an alternative to compiling your functions into an .aex file.

Watch Video

Date added: 2014-11-30
Miscellaneous Xbasic Modules An Xbasic Module is a file that contains Xbasic function and class definitions. The code defined in a module can be made available to other Xbasic code by using the require() function.

This video demonstrates how Xbasic Modules can be used.

Watch Video

Date added: 2014-11-30
UX Component - List Control Image Capture Using the Camera in the List Detail View - Disconnected Applications A common requirement in a mobile application is to be able to capture images using the camera on the device. It is also a common requirement that the application work when it is disconnected (i.e. there is no internet connection available).

In this video we show how to build a disconnected mobile application that supports image capture.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4


Watch Video - Converting the app to a mobile layout - Part 1
Watch Video - Converting the app to a mobile layout - Part 2

Download Component

Date added: 2014-12-18
     

 

Features

WorldPay API - A new XBasic class called WorldPayAPI::SoapActions has been added to support the WorldPay Online Commerce Suite. All of the documented methods of the WorldPay SOAP API are included in this class.

For more information on the WorldPayAPI Xbasic class, click here.

 

json_to_xml() Function - Convert JSON to XML - Takes a string of JSON data and converts it to XML.

Syntax

c xml = json_to_xml(c json, c attribute)

Example

dim json as c

json = <<%txt%

{

    "firstname" : "john" ,

    "lastname" : "public" ,

    "num" : [1,2,3] ,

    "flag" : true ,

    "place" : { "state" : "Texas"}

}

%txt%

 

dim xml as c

xml = json_to_xml(json,"person")

 

The resulting XML string looks like this:

 

<?xml version="1.0" encoding="UTF-8"?>
<person>
   <firstname>john</firstname>
   <lastname>public</lastname>
   <num>1</num>
   <num>2</num>
   <num>3</num>
   <flag>true</flag>
   <place>
      <state>Texas</state>
   </place>
</person>
 

 

 

UX Component - List - Detail View - Client-side Events - 'hasClientSideValidationErrors' - A new client-side event has been added. the 'hasClientSideValidationErrors' event fires when the user tries to save Detail View edits back to the List and one or more controls in the Detail View has a client-side validation error.

UX Component - Action Javascript - Camera - A new action has been added to Action Javascript to allow you to capture an image using the camera on a mobile device.

The 'Image Capture - Camera/Photo Library' action allows you to specify some Javascript code to execute once the image has been acquired. Your Javascript code can reference:

 

NOTE Contrast this action with the 'Image Capture for List-Detail View - Camera/Photo Library' which also allows you to capture an image using the camera. This action however, is specifically for an Image control in a List View with a Detail View. The  'Image Capture - Camera/Photo Library' action simply returns the image data (base 64 encoded) and the native file URL (in the case where PhoneGap is being used). It is up to the developer to decide what to do with the base64 encoded data or file URL.

 

 

 

 

 

UX Component - Detail View - New Records - Default Values - When you define a List control with a Detail View you can specify Javascript code to return the default value for a field when a new record is created in the Detail View. A new option has been added to the List builder to allow you to automatically use the default value that was defined for the control to which the List field is bound for new record default values.

For example, assume:

When you click the New Record button in the List Detail View, the default value for the FIRSTNAME control (i.e. the control to which the FNAME List field is bound) will be set to 'Sam' because there was an explicit Default value rule set in the List builder. The default value of 'Sam' will be used even though the FIRSTNAME control defined a default value of 'Fred'.

However, assume that you now edit the List and delete the Default value Javascript code for the FNAME field. Now, when you create a new Detail View record, the default value shown in the FIRSTNAME control is governed by the setting of the 'Default values policy for new record in Detail View' property in the List builder.

This property can either be set to:

UX Component - List Control - Detail View - Image Capture using Camera/HTML5 - Disconnected Applications - You can now build mobile, disconnected applications, that include the ability to capture images using the camera on the device.  When running on a device that does not have a camera, the image to use can be selected from the file system.

To create a button to capture a new image for an Image control in a List Detail View use the 'Image Capture for List-Detail View - Camera/Photo Library' action.

 

 

 

For more information on capturing images in the List Detail View, click here and search for 'camera'.

 

Application Server - Report Server - HTML Reports - By default, the Report Server is only used for PDF reports. Now, you have the option of offloading your HTML reports to the report server.

To turn this feature on, go to the Project Properties dialog and check the 'Use for HTML Reports' property.

 

 

urlencode() Function - New Parameters to Make Signing Requests when Using oAuth Easier - The urlencode() function now takes optional arguments that are useful when working with APIs that require oAuth authentication. In many of these APIs, the request body must be specially encoded.

The flags that you can use are:

 

Examples:

? urlencode("text-value=foo bar;")
= "text%2dvalue%3dfoo%20bar%3b"
? urlencode("text-value=foo bar;","u")
= "text%2Dvalue%3Dfoo%20bar%3B"
? urlencode("text-value=foo bar;","s")
= "text%2dvalue%3dfoo bar%3b"
? urlencode("text-value=foo bar;","r")
= "text-value%3dfoo%20bar%3b"

? urlencode("text-value=foo bar;","o")
= "text-value%3Dfoo bar%3B"


 

rsa_hash() function - Generates a RSA digital signature of the data using the key and SHA1, or any other signing method supported by the .NET framework.

Syntax

c result = rsa_hash(c data, C key [, c algorithm])

 

 

Example

dim parameters as b = "name=some url parameters"

' Pull the RSA private key out of the file
dim pemFile as c = file.to_string("c:\<somefolder>\<privatekeyfilename>.pem")
pemFile = word(pemFile,2,"-----BEGIN RSA PRIVATE KEY-----")
pemFile = word(pemFile,1,"-----END RSA PRIVATE KEY-----")
pemFile = alltrim(pemFile)

? rsa_hash(parameters,pemFile)
= "EA1c/M2q9QhxTE/EgV5gljzAzeg8Xhj+0DY/7qzF4RXskp5g6ZDimRGJu1f........."

 

UX Component - {dialog.object}.activateControlContainer(UXControl) Method - Previously this method would activate the Tab or Accordion pane in which the specified UX Control had been placed. Now, the method will also activate the PanelCard in which the control has been placed.

 

UX Component - List Control - Detail View - No Record in List is Selected Action - A new property has been added to the List control to allows you to specify the action if no record is currently selected (which can happen if the List's 'Allow null selection' property is not checked).

The options are:

Note: If you have not defined any default values for fields then there is little difference between the 'None' option and the 'NewRecord' option because in both cases the Detail View will be enabled and will not have any default values filled in. If the user edits data in the Detail View and then clicks the Save button, a new row will be added to the List.

 

Grid Component - Query By Example Menus - Internationalization - The menus that are shown in Query by Example can now be internationalized.

 

A new property in the Query-by-Example Row section allows you to specify if the entries in the menu should be wrapped in Language Tags (<a5:r>..</a5:r>) or Text Dictionary tags (<a5:t>..</a5:t>).

 

 

Once you have wrapped the menu strings in tags, you can go to the Language definitions or Text dictionary properties section in the Grid builder to define the replacement strings for each language you want to support.

 

Web Applications - Xbasic Function Libraries - When you build a web component that does Ajax callbacks, you typically define the Xbasic function that handles the Ajax callback in the component itself (in the Xbasic Function Declarations section of the component). Alternatively you can create a .AEX file that creates a library of global Xbasic functions that your component can call.

Now a new method is now available. The Web Projects Control Panel now has a new category called Xbasic Function Library.

 

 

An Xbasic Function Library is a text file with a .a5xbfl extension that is stored in your Web Project. This file contains definitions for one or more Xbasic functions.

Watch Video

To use an Xbasic Function Library in a component you must link the file by specify the Xbasic Linked files property in the component. You can link as many Xbasic Function Library files as you want.

 

 

The benefit of using Xbasic Function Library files over defining the Xbasic function directly in the component is that you can share function definitions across multiple components. Xbasic Function Library files are text files, which makes them easy to manage in a source control system (such as Git), and they are easier to work with than .aex files (which provide an alternative method for sharing Xbasic function definitions across multiple components).

NOTE: If an Xbasic function is defined in both the Xbasic Function Declarations section within a component and also in a linked Xbasic Function Library file, the locally defined function is used.

 

Web Applications - Xbasic Modules - The Web Projects Control Panel now has a new category called Xbasic Module.

 

 

An Xbasic Module is a text file with a .a5xbm extension. It is stored in the web project folder. The purpose of an Xbasic Module is to allow you to package Xbasic functions and class definitions so that they can easily be used in other Xbasic code you write.

Watch Video

NOTE: Xbasic Modules are very similar to the concept of Node modules.

An Xbasic Module must end with an exports command that defines which functions and classes the Module 'exports' (makes available to the calling code).

To use an Xbasic Module in your Xbasic code you use the require() function to 'register' the Module.

The require() function can take an optional CRLF delimited string of search paths. By default the require() function will look in the Web Root (if you are running live) and in the Web Project Folder (if you are in Working Preview). If the file is not found there, it will search for the module in the <ExeFolder>\xbasic_modules folder. If you pass in a CRLF delimited string of folder names as the second parameter to the require() function, these folders will also be searched for the module.

For example, assume you had defined the following Xbasic Module called MyXBModule.a5xbm.

The module file was defined as follows:

function greeting as c (name as c )

    greeting = "Hello " + ut(name) + " the time is now: " + currentDate()

end function

 

function currentDate as c ()

    currentDate = date()

end function

 

exports.sayHello = greeting

 

Notice that the module defines two functions, but only the greeting() function is 'exported' (i.e. made public). Also notice that the greetings() function was exported as sayHello. This means that to the calling code the function sayHello() can be called (but not the internal greetings() function).

 

Now assume you had define an .a5w page with this code:

 

<%a5
dim pxb as p
pxb = require("myxbmodule")
?pxb.sayHello("jim")
%>

 

The Xbasic code in the .A5w page uses the require() function to register the 'myxbmodule' Xbasic Module and assigns the function to a namespace called pxb. Then, to call any of the exported functions, you must use the pxb prefix.

Modules can be loaded recursively. For example, in the definition of a module can reference another module.

 

What is the Difference between an Xbasic Function Library and an Xbasic Module?

On the surface an Xbasic Function Library and an Xbasic Module seem similar in that they are both files in which you can define multiple Xbasic functions.

However an Xbasic Module only makes 'public' certain of the functions and classes it defines (through use of the 'exports' keyword) and the exported functions are all in their own namespace and must be called using the namespace prefix.

On the other hand an Xbasic Function Library must be linked into a component before any of the functions defined in the library can be called. The functions defined in the Xbasic Function Library are in the same namespace as any locally defined functions in the component itself.

 

 

CSS Files - MDI Editor - When you edit a CSS file in the Web Projects Control Panel, the editor is now an MDI window. Previously, a modal window was used. Because the window is a MDI window, you can edit multiple CSS files at once and you can keep the CSS editor open while you edit other files.

Javascript Files - MDI Editor - When you edit a Javascript file in the Web Projects Control Panel, the editor is now an MDI window. Previously, a modal window was used. Because the window is a MDI window, you can edit multiple Javascript files at once and you can keep the Javascript editor open while you edit other files.

Also, while you are editing Javascript files you can test your code by executing it directly in the code editor. You can also switch to the Interactive Windows to test different Javascript code snippets.

NOTE: When you test code in the Javascript editor you are not testing it in the context of the browser. That means you can't test code that assumes that the DOM is present. Also certain Javascript global objects such as window and document are not defined. The alert(), function is also not defined.

The Interactive Window pane in the Javascript editor is shown below. The window is divided into two sections. The top section is the Javascript code that you want to test and the bottom window shows results.

You can print text to the results window by using any of the following functions in your Javascript code:

 

NOTE: When you are done testing your Javascript, be sure to remove or comment out any print(), printJSON() or printJSONCompact() functions in your code as these functions only are defined in the context of the Javascript editor.

 

 

 

Watch Video

 

 

UX Component - Lists - Printing Reports Using Same Filter as List - A common pattern in Grids is to have a button on a Grid that prints a report showing the same records that are in the current Grid query. Now you can use a similar pattern for List controls on a UX component.

NOTE: This feature is only for Lists and Reports based on SQL tables.

 

When you define the filter and order for the report in the Action Javascript genie you can use these special functions

currentListFilter("NameofList")

currentListOrder("NameOfList")
 

For example, if your UX component has a List called CUSTOMERS, you might specify the report filter and order as :

currentListFilter("CUSTOMERS")

currentListOrder("CUSTOMERS")
 


Watch Video
 

Reports - Custom Data Sources - Previously, when you created a Report in Alpha Anywhere you could choose to base the report on a SQL data source, or a native .dbf table.

Now you can specify that the report is based on a Custom data source.

 

 

NOTE: When creating 'Project reports' (Reports defined in the Web Projects Control Panel), the option to base the report on a .dbf table is not available.

 

When you specify a custom data source the following dialog appears:

 

 

You specify the name of an Xbasic function that will return the data to be printed by the report.

The Xbasic function can return data in one of two formats:

In both cases, the Xbasic function returns a string of data (that is either in delimited or JSON format - explained below).

The function prototype for the Xbasic function is (assuming you specified that the Function name was myDataFunction in the Function name property in image shown above):

 

function myDataFunction as c (e as p)

myDataFunction = <<%txt%

......the delimited, or JSON format data goes here

%txt%

 

end function

 

Notice that the function takes a single input parameter, e.

The e object that is passed into the function includes the value of any arguments that were passed into the report.

For example, assume that you specified that the Custom Data Source uses an argument called whatCountry. Your Xbasic function can reference the value in this argument as follows:

dim country as c

country = argVal(e.arguments,"whatCountry")

 

 

Understanding the Format of the Delimited Data Your Custom Function Must Return

 

The delimited option allows you to return a CR-LF delimited list of data. Each row in the data that are returned represents a row of data in your report. The 'fields' in the data are typically delimited with a pipe character (e.g. |), but you are free to specify any delimiter. For example, here is how a simple Xbasic function could be defined to return some data for a report.

 

function myXBfunction as c (e as p)

 

dim txt as c

txt = <<%txt%

Firstname|Lastname|City

Fred|Smith|Boston

John|Jones|London

%txt%

myXBfunction = txt

 

end function

 

Notice that the first row of data in the string that is returned by the function are the field names. In this example, the field names are Firstname, LastName and City.

 

The first row of data can optionally include additional information that defines the data type and size of each field.

For example:

function myXBfunction as c (e as p)

 

dim txt as c

txt = <<%txt%

Firstname=C20|Lastname=C30|City=C20|DOB=D|Salary=10.2

Fred|Smith|Boston|12/6/1972|86500.00

John|Jones|London|11/5/1982|76000.00

%txt%

 

myXBfunction = txt

end function

 

For Character fields, the format is defined as Cw where 'w' is the size of the field. For Numeric fields, the format is defined as Nw.d where 'w' is the size of the field and 'd' is the number of decimal places.

The following field type codes can be used:

 

 

Understanding the Format of the JSON Data Your Custom Function Must Return

 

The JSON data that your function returns can be Simple or Complex.

Simple JSON

For Simple JSON, the string that you return is just an array of JSON objects, For example:

function myjson as c(e as p)
myjson = <<%json%
[
	{"Firstname" : "Fred", "Lastname" : "Smith"},
	{"Firstname" : "Harry", "Lastname" : "Jones"}
]
%json%
end function 

 

In this case since no schema is supplied the data are all considered to be character type of length 1024 characters. While the advantage of this format is that is extremely simple, it does mean that you will need to adjust the size of each field you place on your report because its default size will likely be too large.

Complex JSON

For Complex JSON, the string that you return is an object with two properties, schema and data. The schema object defines the schema of the data (for example, field type, size, etc.) and the data property is an array of JSON objects that define the data for the report. For example:

function myjson as c(e as p)
myjson = <<%json%
{
	"schema" : { "firstname" : { "type" : "C" , "width": 30 } 
	           , "lastname" : { "type" : "C"  , "width": 30} 
	           , "company" : { "type" : "C"  , "width": 30} 
	           , "age" : { "type" : "N" , "width" : 3, "decimal" : 0 }
	},
	"data": 
		[
			{"firstname":"Fred", "lastname":"Smith", "company" : "Alpha Software", "age" : 30},
			{"firstname":"John", "lastname":"Jones", "company" : "Beta Software", "age" : 23}
		]
}
%json%
end function 

 

In the above example, we have specified the size and type of each field in the data array. Notice that we have also specified the number of decimal places for the numeric field.

The data types supported in the schema are:

Note: If you specify that a field uses the Date (D), Date/Time (T) or Short time (Y) format in the schema, the data in the data array must be a string in UTC date format. For example: 2014-10-27T23:06:50.361Z. The date part format is yyyy-mm-dd and the time part uses GMT. In the case of a Short time field, the date portion of the UTC date string is ignored.

 

 

The schema also allows you to extract data from objects within each row and to map property names in the data array to different names. For example in the data shown below, the address property is an object with two sub-properties.

{
   "name": "Fred Smith",
   "company" : "XYZ Corp",
   "address": {
       "street": "Main Street",
       "number": 23
    }
}

 

Shown below is how the function would be defined to return the JSON data. Notice that the JSON object has both a schema and a data property. The schema indicates what fields will be available to the report. The list of fields specified by the schema are: name, companyName, street and number.

Notice that the data array does not have a property called companyName. It has a property called company. So the schema property for the companyName field indicates that the source of this field is the company property in the data array. Similarly, the street field in the schema is mapped to the address.street property in the data array.

If the definition for a field in the schema omits the source property, then the source is the same as the item name. For example the definition for the name field in the schema shown below does not have a source property, therefore this field is mapped to the name property in the data array.

function myjson as c(e as p)
myjson = <<%json%
{
    "schema": {
        "name": {
            "type": "c",
            "width": 30
        },
        "companyName: {
        	"source": "company",
        	"type" : "c",
        	"width" : 30
        },
        
        "street": {
            "source": "address.street",
            "type": "c",
            "width": 40
        },
        "number": {
            "source": "address.number",
            "type": "n",
            "width": 5,
            "decimal": 0
        }
    },
    "data": [
        {
            "name": "Fred Smith",
            "company" : "XYZ Corp",
            "address": {
                "street": "Main Street",
                "number": 23
            }
        },
        {
            "name": "John Jones",
            "company" : "ABC Corp",
            "address": {
                "street": "Corner Road",
                "number": 3
            }
        }
    ]
}
%json%
end function 

 

In the next example, we show how the JSON object that you specify can include image data. The binary data for the image are encoded as base64 strings. The example shows the complete function definition. Notice that the schema indicates that the image field will be stored as a PNG. Notice also that in the first record, the base64 encoded data in the image property does not include the MIME type at the start of the base64 encoded data. This data is therefore presumed to be a PNG image since the schema indicates that the image is a PNG type. Notice however, that the second row of data in the data array has a MIME type prefix on the base64 encoded image data. The data for the image is for a BMP image. The image will therefore be converted from BMP to PNG automatically.


function myjson as c(e as p)
myjson = <<%json%
{
   "schema" : {
      "name" : { "type" : "C" , "width": 30 }, 
      "image" : { "type" : "Png" }
	},
	"data": 
       [
          {"name":"John Smith", "image" : "iVBORw...(data truncated for readability)....AAAElFTkSuQmCC" },
          {"name":"Jane Smith", "image" : "data:image/bmp;base64,Qk02AwAAA...(data truncated for readability)....AAAADYAAAAAA=="}
       ]
}
%json%	
end function

 

 

 

UX Component - Action Javascript - Dial Telephone Action - A new action has been added to Action Javascript to allow you to dial a telephone number.

The number to dial can either be static (i.e. specified at design time), or it can be read from controls on the UX, columns in a List, or returned by a Javascript function.

 

Apperian EASE Integration, Mobile Application Management -Added support for Apperian which allows you to publish your PhoneGap apps directly to the Apperian EASE platform.

The Apperian EASE platform can secure, manage and deploy enterprise mobile apps for all platforms.

Apperians mobile application management platform provides:


To publish apps to the Apperian Ease platform, you will need to setup an Apperian account. See the Apperian Web Site for more information.

To enable the Apperian features, from within the PhoneGap App Builder, check the Enable Apperian EASE Integration Options.

Next, enter your Apperian account credentials and make sure to specify the correct Apperian server. Different servers are used for US and non US accounts.

Once the Apperian features have been enabled, a number of optional items are enabled within the PhoneGap App Builder.


The Apperian Admin Console will display all of the apps you may have previously published to the Apperian EASE platform.

To Add A New App To Apperian

Make sure to download and save the app bundle for the target platform. The app bundle files will be automatically saved to the appDownloads folder of the PhoneGapProjects target project directory.

Next click the Add App button and fill out all of the required information for submission to Apperian. All of the fields must has valid data and the version number should include a decimal, ie: 1.20, 0.20, 2.52, etc. The app.bundle.id will be automatically retrieved from the app bundle.


To Update An Existing App

Click the update button. You do not need to upload a new app bundle unless the files have changed. You can simply edit the information and save.

To Access the Apperian EASE Platform

Log in to your Apperian EASE account at Apperian. Once you've logged in, you will see the files and data that have been uploaded from Alpha Anywhere. Further deployment options will be set within the Apperian EASE Management Console.

Keep in mind that you can update the app within Alpha Anywhere and update the app bundle and app meta data anytime.

 

AlphaDAO Connection Strings - Mask Passwords - Previously, the connection string builder masked (i.e. obfuscated) the password by using high order characters. For example, a password of 'alpha' would be masked as ''. Now, the connection string builder uses a different technique to mask password that does not use high order characters. The reason for this change is so Alpha Anywhere IIS server can correctly interpret the connection strings.

Passwords masked using the new scheme will now have the 'A5:B64' prefix.

If you edit an existing connection string, the existing masked password will be masked using the new scheme.

NOTE: The reason that the connection string builder masks passwords is so that someone looking over your shoulder as you define a new connection string will not see the real password. This is much like the way a login dialog will mask your password as you enter it.

You do not have make any changes to your existing applications because of this change.

However, if you edit an existing connection string, or you add a new connection string and then publish your application, you will need to ensure that the server is also running this build or a higher build.

There are two methods on the SQL::Connection object that allow you to mask and unmask as string

For example:

dim cn as sql::connection

?cn.MaskPassword("alpha")

= ":A5:B64:YWxwaGE="

 

?cn.UnMaskPassword(":A5:B64:YWxwaGE=")

= "alpha"

 

 

PDF Reports - Set Maximum Allowed Time - You can now set a timeout for PDF reports. This is useful to prevent tying up the Application Server (or Report Server if the Report Server is enabled) for a long time in the event the user requests a report that might take too long to process.

To set the maximum allowed time for a PDF report, open the Project Properties dialog from the Web Control Panel. By default, the timeout is set to 0 seconds (which means that reports will run to completion, regardless of how long they might take).

It is recommended that you set this property to a non-zero value.

 

UX Component - Video Player Control - The UX component now includes a built-in video player control. Previously, to add video playing functionality to a UX component, you had to first create a stand-alone Video Player component and then embed the Video Player component into your UX component.

 

 

 

The Video Player Control supports YouTube, Vimeo, Viddler and HTML5 video players.

The player supports many options specific to the type of player used.

NOTE The 'auto play' option does not work on mobile devices as it is disabled in an effort to conserve bandwidth.

An 'automatic sizing' option is included to adjust the video player size on device orientation change. This feature is important on Android devices.

A typical use case is to include a panel navigator with two panel cards. The first panel card contains a list control that may display the video title, the second panel card includes the video player control. When the user taps on a row in the list, the second panel card is transitioned into view and the video may be played. Download a sample component that demonstrates this use case.
 

Watch Video
 

HTML Reports in Components - Display limit - Large reports (more than 1,000 records) may be slow to open when created as HTML reports. This will add load to the application server and slow the server response. You can now set a limit on the number of records to display in a report opened as HTML. This will allow a large report to open faster as a preview of data in the report. If the report is then printed as PDF or exported, the full number of records will be in the final report.

The HTML Report Viewer Options will show an option for 'Maximum records to display' if the initial view is HTML. An embedded report in a UX will show the property in the Report definition. Set the value to 0 to show all records, or set a value to limit the maximum records to display. The limit only applies to HTML reports. A reasonable upper limit is 1,000 records as larger reports may be slow to generate.

You can set a 'More records' message with placeholders and a style for the message container. This message will be added to the bottom of the report if the number of actual records in the report is greater than the display limit. The message will not be shown if the number of records in the report is less that then display limit.

 

 



 

UX Component - Data-Bound Image Field - Image File Transformation Template  - If you have image fields that are bound to a character field (that contains the image filename), you need to define the 'Image File Transformation Template' to resolve the image name stored in the table. The Image File Transformation Template can now include field placeholders. For example

{folder}\<value>

If the current record you were viewing had a value of c:\project1 for the 'folder' field, the images for this record would be found in the c:\project1 folder.

 

UX Component - Hide Container Window - New methods and actions in Action Javascript have been added to hide (i.e. close)  a 'container' window.

A 'container' window is a pop-up window that is defined in the UX by wrapping controls in a 'Container' and setting the sub-type to 'Window'.

Opening a container window has always been easy as there is an explicit method in Action Javascript to open a container window and there is a corresponding method ( {dialog.object}.showContainerWindow() ) in the UX object.

However, closing the window programmatically involved first getting a pointer to the actual window object that was created and then calling that object's .hide() method.

Now, the UX object has a new method:

{dialog.object}.hideContainerWindow(containerName);

 

 

UX Component - List Control - Client-side Display Format for Date, DateTime and Short-time Fields - A new property has been added to the 'Fields' pane in the List Builder to allows you to set the client-side display format for date, date/time and short-time fields.

 

 

The builder for the 'Date/time display format' field allows you to set the format to:

If you choose <None> then no client-side formatting rule is applied. This means that the date/time values will be displayed using the regional settings on the server from where the UX is loaded. So for example, if the server is located in Switzerland where the date format is dd.MM.yyyy, then dates in the List will be displayed like this: 12.31.2014.

If you choose <Default> (or <Default - date part only> for a date/time field), the client side display format will match the setting for the 'Date format property' (shown below). This property is set on the Properties pane in the UX builder. This property can be overwritten at run-time by setting a session variable (__protected__clientSideDateFormat) at the time a user logs into your application.

 

 

Grid and UX Component - Action Javascript - File Upload - User Defined Action - A new property has been added to the builder for the 'File Upload - User Defined Action'.

The 'Xbasic function arguments array mode' property can be set to either 'Filename' or 'Data'.

 

 

For all existing actions this property is set to 'Data'. For all newly defined actions, this property will default to 'Filename'.

When the upload is complete, the 'After upload' Xbasic function is called. This function gets passed an array (in the 'e' object that is passed into the function) that contains information about each of the files that was uploaded.

 

For example, if the 'Data' option is selected, and (say) the user uploaded two files. the e object passed to the 'After upload' function will contain these properties:

 

e.fileArray[1].file.characterSet - character set of the uploaded file
e.fileArray[1].file.contentType - MIME type (e.g. 'application/octet-stream')
e.fileArray[1].fileName - filename of the file on the client machine
e.fileArray[1].encoding - For text files, specifies the encoding type
e.fileArray[1].data - data that was uploaded.
e.fileArray[1].file.dataType = Either 'text' or 'binary'
 

 

e.fileArray[2].file.characterSet - character set of the uploaded file
e.fileArray[2].file.contentType - MIME type (e.g. 'application/octet-stream')
e.fileArray[2].fileName - filename of the file on the client machine
e.fileArray[2].encoding - For text files, specifies the encoding type
e.fileArray[2].data - data that was uploaded.
e.fileArray[2].file.dataType = Either 'text' or 'binary'
 

Note that the array has a .data property that contains the data that was uploaded.

 

On the other hand, if the 'Filename' option is selected the array will not have the .data and file.dataType properties. Instead it will have a property called 'tempFileUploadedData' that contains the filename of the temporary file on the server where the uploaded data was saved. So, in the case where the user uploaded two file, the e object will contain:

 

e.fileArray[1].tempFileUploadedData

e.fileArray[2].tempFileUploadedData

 

It is recommended that for your existing actions you edit the action and change the mode to 'Filename'. This will require that you also change your Xbasic function that processes the uploaded data because the array passed to your function will  no longer has a .data property.

 

The benefit of the 'Filename' option over the 'Data' option is that the uploaded data is never loaded into memory. If you use the 'Data' option, the uploaded data is read into memory. This consumes virtual memory on your server and may result in server errors if you have a large number of users uploading files (or just one user uploading a huge file).

With the 'Filename' option, your application will be able to handle larger file uploads, or more users concurrently uploading files.

 

 

 

Security Framework - Alternative Login - Microsoft Live Connect - The Alpha Anywhere alternative login feature now supports user authentication using Microsoft Live Connect.  

The developer site for configuring a new Live Connect application can currently be found at:

https://account.live.com/developers/applications

 

UX Component - New Quick Start Templates - When you create a new UX component, two new quick-start templates are available:

 

 

Watch Video - Part 1
Watch Video - Part 2
Watch Video- Part 3

 

Xbasic - UTC Date - Convert To and From - Xbasic functions have been added to convert UTC date strings to Xbasic date or time objects.

 

Examples:

 

? date_to_utc_date(now())
= "2014-10-28T17:23:27.681Z"

? date_to_utc_date(date())
= "2014-10-28"


? date_from_utc_date( "2014-10-28T17:23:27.681Z")
= 10/28/2014 01:23:27 68 pm

? now()
= 10/28/2014 01:23:36 06 pm

? date_from_utc_date("2014-10-28")
= {10/28/2014}

? date_from_utc_date( "2014-10-28T17:23:27.681Z" , "D")
= {10/28/2014}

? date_from_utc_date("2014-10-28","T")
= 10/27/2014 08:00:00 00 pm


 

Web Applications - Publishing Application - Command Line Options - Typically when you publish your web application you do it using the user interface in Alpha Anywhere. You start the process starts by clicking the Publish button on the Web Control Panel.

However, there may be cases where you would like to automate the process by creating a batch file that automatically invokes the publishing operation.

A new function, a5w_publish2() has been added to make it easier to do command line publishing.

This function takes either a dot variable or a JSON object that defines the publishing options. The function can be called from a batch file, as described below.

The a5w_publish2() function allows you to set values for the following publish options:

 

TIP: To view help for this function, enter the following command in the Interactive Window:

a5w_publish2("help")

 

The dot variable or JSON object that you pass into the a5w_publish2() function can set a sub-set of these properties.


To use the .dot variable syntax:
 

dim ops as p
ops.profile = "Profile1"
ops.publish_type = 1
dim flag as l
flag = a5w_publish2(ops)
 

 


To use the JSON syntax:


dim flag as l
flag = a5w_publish2("{profile: \"Profile1\", publish_type: 1}")
 

 

Assume that you have a Workspace called 'c:\MyWorkspaceFolder\MyWorkspace.adb' and you want to publish all files in the 'project1' folder using the 'profile1' web publishing profile.

You could create the following batch file to do the publish.

Note: The batch file would be all on one line. The line breaks shown below are not part of the code.



C:\Program Files (x86)\alpha5.exe "C:\MyWorkspaceFolder\MyWorkspace.adb" -COMMAND="a5w_publish2(\"{profile: 'profile1', projName: 'project1', publish_type: 1, exitAfterPublish: true}\")"

 

 

 

UX Component - Client-Side Events - securityNotAuthenticated and securityPermissionDenied Events - Two new client-side events have been added to the UX component.

When an Ajax callback is made and the server sends back a '401' status code in the response, the securityNotAuthendicated event will fire.

If the server sends back a '403' status code in the response, the securityPermissionDenied event will fire.

You can manually set the status code in an Ajax response (for example, if you want to test the events) by setting the

Response.StatusCode

 

property in the Xbasic function that handles the Ajax callback.

 

NOTE: Typically, when defining these events, you will also set the Security permission denied action property in the Other section of the UX properties to Fire client-side security events.

 

For example, assume you have a button on UX component that does an Ajax callback. The function that handles the callback is myXBFunction. Your could define the function as follows:

 

function myXBFunction as c (e as p)
Response.StatusCode = 401
end function
 

 

These events are primarily intended for use in a UX component that contains an integrated login section (for example in a mobile application where the UX has Panel Navigator with at least two Panel Cards and the Login controls are on Panel Card 1 and the afterLogin event sets focus to Panel Card 2).

In the case where the UX contains an integrated login section, these events can be used to direct a user back to a panel or section used for login on a UX component. For example, the UX may have login controls on a panel, PANELCARD_1. The securityNotAuthendicated event could set focus back to that panel.


{dialog.object}.panelSetActive('PANELCARD_1',true);

 


If the event was fired from a child component, the event in the child component could redirect the user back to the login panel.

 


var po = {dialog.object}.getParentObject();
if(po) {
    po.panelSetActive('PANELCARD_1',true);
}

 


If the child was opened in a window, the child event could also close the window. If the child UX had a control named 'list1', the event would be:

 

 

var po = {dialog.object}.getParentObject();
if(po) {
    var ele = {dialog.Object}.getPointer('list1');
    {dialog.Object}.closeContainerWindow(ele);
    po.panelSetActive('PANELCARD_1',true);
}

 

UX Component Security Permission Denied Action Property - The UX component has a new property to set the server permission denied action.

 

 

This is the action the security system will take when a request is made from this component and the request is denied because of security restrictions.

This can occur if a UX attempts to open another component that has login restrictions and no one is logged in, or the user has insufficient permission to see the component being requested. The security action will also be taken if the current component has login restrictions, the login has expired, and some request is made to the server, such as a request to refresh a control or do a server-side sort on a column in a list control.


The new property UX property is Security permission denied action in the Other section of the UX properties.

The default action is Redirect to login page. This action will allow the security to redirect to the login or insufficient permission page as set in the security settings.

The action Fire client-side security event will cause the server to return either a 401 status code if the login has expired, or a 403 status code if a user is logged in, but not allowed to access the requested component. This will fire either the securityNotAuthenticated or securityPermissionDenied client-side events.

This action is currently only available in UX components. The action applies to only Ajax requests made from the component. A UX component ('parent' component) can open other UX components ('child components'). If any of the child components have a login restriction, and this action is set to fire the client side events on any of the components, the recommended 'best practice' is to set the property to fire the client side event on all of the child components and the parent component. This should be set even if the parent component is always allowed.
 

 

UX Component - List Control - Templates - Date Formatting - Typically the data in a List control is all text data. So even though a column in the List might be displaying a date value, the actual data in the List data array for that column is still a string.

The only exception to this is if the List is populated using Javascript and in the Javascript array that was used to populate the List, the column was explicitly set to a Javascript data object. Or, the data in the column was explicitly cast to a date object by setting the Transform data type property on the Fields pane in the List builder.

The template used to display data in the list allows you to specify an optional format.

For example, say you have a column in the List called 'OrderDate', the template for that column in the List will be:

{OrderDate}

 

However, say you wanted the display format for the OrderDate to be yyyy-MM-dd (e.g. 2014-12-25), then you can add a format directive to the template. For example:

 

{OrderDate:date('yyyy-MM-dd')}

 

However, the above format directive only works if the data in the 'OrderDate' column in the List are a date object.

But, as previously discussed, in many cases, the data in the List are all strings of text, so you cannot use the above format directive unless you first cast the data to a date object. When working with Lists that have updateable Detail Views, casing date strings to date objects introduces other complexities and it would be desirable to not have to cast the date string to a date object, but rather to be able to simply format the date string.

To do this, a new format directive has been added. For example:

{OrderDate:dateString('MM-dd-yyyy','yyyy-MM-dd')}

 

This directive takes two date formats. The first date format is used to parse the date string into a date object and the second date format is the output format.

 

 

 

 

 

 

 

UX Component - List Control - Detail View - Showing Edited Fields - When you have a List with an associated Detail View and you edit the data in one of the rows of the List, an icon (whose appearance you can customize) is shown in the List row to indicate that the List row has data that has been edited, but not yet synchronized.

You can now indicate the dirty fields in a List row that has been edited by specify a custom CSS class to apply to the Detail View control if the field value has been edited.

For example in the image shown below, you can see that the first row in the List has been edited, and you can now also see that the field in that row that was edited was the city field that was changed to 'Frankfurt'.

 

 

To indicate the CSS class that you want to apply to dirty fields, open the List builder and set the 'Dirty control class name' property.

 

 

In the above example, the dirtyField CSS class was defined as follows:

.dirtyField {
    background: #f6f9c2;
}
 

 



Watch Video
Download Component

 

 

Export Data - .dbf Tables - Delimited Data - A new option has been added to the export operation so that you can optionally suppress escaping characters.

The 'Disable Character Escapement' property has been added to the export options.

 

 

Consider a table that has this data:

 

Name Comment
Fred "J" Smith This is a comment with a trailing \
Hank Kaplan No comment

 

 

If you export the data and specify that the fields should be quoted, the exported data looks like this:

 

"NAME","COMMENT"
"Fred \"J\" Smith","This is a comment with a trailing \\"
"Hank Kaplan","No comment"
 

Note that quotes in the data itself are escaped and that the trailing backslash in the data is also escaped.

This data could be successfully re-imported in Alpha Anywhere.

 

However, if you check the new 'Disable Character Escapement' property, the data will be exported as follows.

Note that the quotes in the data are converted to single quotes and the trailing backslash in the data is not escaped.

This data could NOT be successfully re-imported into Alpha Anywhere.

 

 

"NAME","COMMENT"
"Fred 'J' Smith","This is a comment with a trailing \"
"Hank Kaplan","No comment"
 

 

 

UX and Grid Component - File Download Action Javascript - You can now specify a dynamic 'client-side filename' by specifying the name of a Javascript function to call. For example, you can specify the following for the 'client-side filename':

function:myfunc

 

Where 'myfunc' is the name of the Javascript function you want to call to generate the client-side filename. You function must return a url encoded value.

 

AlphaDAO - Connection Strings - Dynamic - A dynamic connection string is a connection string that is resolved at the time the database connection is opened, rather than at the time the connection string is defined.

Alpha Anywhere has allowed for dynamic connection strings for some time now by allowing you to create a named connection that starts with DynamicConnection_. For example

DynamicConnection_MyCustomApplication

 

The actual value of the dynamic connection string is resolved by referring to a session variable called:

session.__protected__MyCustomApplication

which defines the actual connection string to be used.

The value of this session variable is typically set when the user logs into the application. For example, it might be set to:

::Name::User1Connection

 

Now, a new way of creating dynamic connection strings is available using the ::EVAL:: prefix in the named connection string, rather than the ::Name:: prefix.

Prefixing a connection string with ::EVAL:: causes the connection string to be evaluated as an Xbasic expression.

For example, consider the following connection string:

::EVAL::MyFunctionThatReturnsAConnString()

 

When an AlphaDAO connection is opened using the above string, the MyFunctionThatReturnsAConnString() is evaluated and the return value (which would typically be a named connection string with the ::Name:: prefix) is used as the connection string.

In this next example, the dynamic connection string uses an in-line Xbasic expression:

::EVAL::if(User = "Fred","::name::Fred","::name::EverybodyElse")

 

 

UX and Grid Components - Javascript Actions - Copy/Paste - You can now copy and paste Javascript Actions from one component to another component (of the same type). For example, you might have defined several Javascript Actions in component called 'UX1' and now you are building a new UX component and you would like to copy some of the Javascript Actions from 'UX1' to your new UX component.

Create PDF File from HTML - helper::HtmlToPdf Class - Xbasic now has a new class that allows you to convert HTML to PDF.

The helper::HtmlToPdf class has methods that allow you to convert HTML to PDF or a URL to PDF.

The following example code can be pasted into a new script in the Code editor and executed.

 

dim hp as helper::HtmlToPdf
dim html as c
html = <<%html%
<style>
.mystyle {color: red;}
</style>
<h1>This is So Cool</h1>
<h2>Generate PDF from HTML!</h2>
<p>This shows how you can turn <span class="mystyle">any</span> html into a pdf</p>
%html%

dir_create_recurse("c:\mypdffiles")
hp.SaveHTMLToPdf(html,"c:\mypdffiles\mypdf.pdf")
 

'now open the file
sys_open("c:\mypdffiles\mypdf.pdf")

 

 

 

The helper::HtmlToPdf class exposes these methods:

 

The helper::HtmlToPdf class exposes these properties:

 

 

 

Bugs

UX Component - List - Detail View - Client-side Validation - Client side validation was not being performed on all of the controls in the Detail View when the user tried to save Detail View edits back to the List. As a result, it was possible to save edits to the List when client-side validation errors should have prevented this. (The validation errors would still have been caught server-side when a sync operation was performed, and bad data could not have been entered into the database.)

UX Component - Android Mobile Devices - Keyboard - Responsive Events - Under some circumstances on Android mobile devices, if the device was in portrait mode and the keyboard came up, the UX would indicate that it was now in landscape mode even though the device orientation was still portrait.

Application Server - HTML Reports - Memory Leak - Fixed a memory leak in the Application Server when doing large HTML reports.

Application Server - Security Framework - SQL Tables for Security Tables - Postgres - Converting the security tables to use a Postgres database was failing. This is now fixed.

Label Reports = Setting an Image as the Background - In some case, setting an image as the background for a label was failing.

UX Component - List Control - Detail View - Incremental Refresh - Fixed an issue with incremental refresh in the case where the UX had multiple Lists in a parent-child relationship and the top-level parent List was based on a SQL statement that joined multiple tables and the top-level List pre-fetched the data for the child Lists.

UX Component - List Controls - Data Type Casting - The List Control allows you to cast the data type in any List column to a date object, number or logical value (by setting the Transform data type property on the Fields pane in the List builder). However, after data in the list was updated, or new rows were added to the List, the data casting rules were not being applied to the new data.

UX Component - List Control - Detail View - Editing a Value that Was Previously NULL - A change has been made in the SQL that gets generated when you edit the value in a field that was previously NULL.

UX Component - List Control - .getValue() method - Reading Value in List Column - The .getValue() method can get the value in a control, or in an individual column in a List control.

When reading the value in a control, there is no concept of a null value (since the UX does not have the concept of setting a control value to null).

However, List columns can contain null values and previously, when you read the value of a List column that contained a null value, .getValue() returned a null value, which was inconsistent with how .getValue() works when reading a control's value. Now, .getValue() returns a blank string when reading the value in a List column that is null.

 

For example

var = value = {dialog.object}.getValue('list::LIST1::CustNum');
 

now returns a blank string if the 'CustNum' column in LIST1 in the selected List row is null. Previously it returned null.

 

Note that you can still determine if a List column really does contain a null value as follows:

 

//get a pointer to 'LIST1'
var lObj = {dialog.object}.getControl('LIST1');

//get data in first selected row of the List
var _d = lObj.getData(lObj.selection[0]);

//read the value of the 'CustNum' property in the data object
var _v = _d['CustNum'];  //_v will be null if the data in the column is null

 

PhoneGap - Web Security Framework - Fixed an issue with the Web Security Framework when running in a PhoneGap shell. Redirecting to the login page after a session timeout, or after an attempt to load a resource for which you did no have permission was not working correctly.

UX and Grid Component - Wait Message - Fixed a case where the wait message was not getting cleared after an Ajax callback had completed.

UX Component - File and Image Upload - Internet Explorer - Fixed a case where a Javascript error was generated when the file or image upload window was opened. Only happened in IE when in the UX component.

UX Component - Panel Navigator - Opening a Child Component in a Panel Card inside a Navigator -  Fixed an issue where a child component was being opened in a Panel Card inside the Panel Navigator. After the child component was opened, the swipe gesture to move to a different Panel in the Navigator was causing a Javascirpt error.

Grid Component - Grid Based on Stored Procedure - If a Grid was based on a Stored Procedure and a surrogate Primary Key for query was defined, the _keys array in the Grid Object was not getting defined.

Tips

UX and Grid Component - Edit-Combo Control - Dynamically Populating Choices Using Javascript - The choices in an edit-combo control can be dynamically set using Javascript. For example, say you have an control on a UX called 'TEXTBOX1' and you want to dynamically set the choices in the edit-combo. The following code can be used:

 

var obj = {Dialog.object}.getControl('TEXTBOX1');

var newData = [

       {COMPANYNAME: 'Alpha Corp'},

       {COMPANYNAME: 'Beta Corp'},

       {COMPANYNAME: 'Gamma Corp'}

]

obj.setData(newData);

 

 

 

UX Component - List Control - Freeform Layout - Hyperlinks - When you create a free-form List layout you can use any HTML that you want to lay out each row in the List. Your HTML template will include placeholders for the various fields in the List.

 

For example:

 

<div>

    Name: {name}<br>

    Address: {address}

</div>

 

Because the template is HTML, you might expect to be able to add hyperlinks. For example:

<div>

    Name: {name}<br>

    Address: {address}<br>

    <a href="page2.a5w?{address}" target="_blank">Open Page</a>

</div>

 

This will not work because the List is configured to handle all events. However, you can make this pattern work by adding markup to your html to stop event propagation. For example:

 

 <a href="page2.a5w?{address}" target="_blank" onclick="$e.stopPropagation(event);" ontouchstart="$e.stopPropagation(event);">Open Page</a>

 

With the addition of event handlers for the onclick and ontouchstart events which stop event propagation, the hyperlink will work as expected.

 

UX Component - PhoneGap Applications - Ajax Callback URL - Setting Dynamically at Runtime - When you build a PhoneGap application you have to specify the URL for Ajax callbacks in the PhoneGap genie.

When you perform any action in your PhoneGap application, the callback is made to the server address specified in the URL for Ajax callbacks property in the PhoneGap genie.

However, you might be building an app where you don't know what server the app will be running on (i.e. you don't know what server the app will be making its Ajax callbacks to) and so you would like to be able to set the URL for Ajax callbacks after the app has loaded.

Here is how this can be done.

First, when you specify the URL for Ajax callbacks, set the URL to some placeholder value. For example:

replaceMe

 

Next, put a textbox on your UX component where the user can enter the address of the server to which they will be making callbacks. For example, assume that this text box is called: ServerAddress.

Then put a button on the UX to set the callback URL. The callback URL is a property of the UX object (i.e. {dialog.object}. It is called ajaxURL.

 

Define the following Javascript for this button:

 

 

//read the server address from the serverAddress textbox

var prefix = {dialog.object}.getValue('SERVERADDRESS');

 

//the address should look something like this:

//'http://www.myserver.com/folderWhereAppWasPublished/';

//notice that the server address has a trailing forward slash

 

//read the existing callback URL

//it will start with 'replaceMe' since that is what you specified

//in the PhoneGap genie
var url = {dialog.object}.ajaxURL

 

//replace the placeholder with the server address
url = url.replace('replaceMe/',prefix);

 

//set the URL
{dialog.object}.ajaxURL = url;

 

Having done this, Ajax callbacks made to the server will now work. But what happens the next time the user loads the application? The Ajax URL will be wrong. You would want the Ajax URL to be automatically set correctly without requiring the user to go through the steps of having to enter the server address again.

The solution to this problem is to store the callback URL in local storage and then to restore from local storage whenever the application is started.

To do this, you would add code like this to the end of the above Javascript:

 

localStorage.setItem('AJAXCALLBACKURL',url)

 

In the onRenderComplete client-side event, you would add this code to restore:

 

//read url from local storage.

var url = localStorage.getItem('AJAXCALLBACKURL');

//if value exist, set the UX's ajaxURL property

if(url != null) {

    {dialog.object}.ajaxURL = url;

}
 

 

 

 

UX Component - List Control - UX Component 'Dirty State' - Just like standard UX Components controls (such as Textbox, Textarea, RadioButton, etc), the List control is bound to a UX component variable. When the value in any control changes the UX component is considered to be 'dirty'. So for example, if you open a UX and then select a row in a List, ghe UX will go from 'clean' to 'dirty'.

In some use cases you might not want the UX go to 'dirty' when the user is making selections in a List. You can easily do this by adding some code to the onBeforeSelect and onSelect event in the List.

Here is the code to add to the List's onBeforeSelect event:

 

var flagUXIsDirty = false;

//see if the UX is already dirty
flagUXIsDirty = {dialog.object}._dirtyRows[0];

//store the dirty state of the UX in a variable in the List object
this._flagUXIsDirty = flagUXIsDirty;

 

Here is the code to add to the List's onSelect event:

 

 

//if the UX was not dirty when you selected the row

//set the UX state back to clean after the row is selected.

//you need to use a timeout with a small delay.

if(this._flagUXIsDirty == false) {
    setTimeout(function() {
        {dialog.object}._setRowState(1,false);
    },10);
}

 

Reporting - Group Breaks - mrec_eof() Function - The mrec_eof() function is useful if you want to put some conditional text in the header, detail or footer of the last group in a parent group.

 

The mrec_eof() function takes a group name as an argument and returns .t. or .f. depending on whether the you are in the last group within a series of groups.

Consider a report that has two levels of grouping. The top-most group is State and the inner group is City.

For a given state, there will be multiple city groups. For example, NY might have groups for Albany, Buffalo and New York City. E.g.

New York

    Albany

    Buffalo

    New York City

 

When the 'Albany' group is printing, the following function will return .f.

mrec_eof(grp->city)

 

When the 'Buffalo' group is printing, the function will also return .f..

But, when the 'New York City' group is printing, the function will return .t. because 'New York City' is the last group within the parent group ('State').

 

Assume further that the states in the report are:

New York

Oregon

Washington

 

When the New York and Oregon groups are printing, the following expression will return .f. because both New York and Oregon are not the last groups in the list of states.

mrec_eof(grp->state)

However, when the Washington group is printing, the function will return .t. because Washington is the last group in the list of states.

 

Say you wanted to put some text in the group footer for the City group, but only if you were printing the group footer for the last group in a given state. To do this you would define a calculated field that referenced mrec_eof(grp->state). For example:

calc1 = if(mrec_eof(grp->city), "Last city in state","More cities...")

 

Similarly, you might define another calc field:

calc2 = if(mrec_eof(grp->state), "Last state","More states...")

 

 

For example

 

NY

    Albany

    Group footer for Albany - calc1 = "More cities..."

 

    Buffalo

    Group footer for Buffalo - calc1 = "More cities..."

 

    New York City

    Group footer for New York City - calc1 = "Last city in state"

 

Group footer for NY - calc2 = "More states..."

 

....

 

Washington

   

    Olympia

    Group footer for Olympia - calc1 = "More cities..."

 

    Seattle

    Group footer for Seattle - calc1 = "Last city in state"

 

Group footer for Washington - calc2 = "Last state"

 

 

 

 

 


Disabling a Hyperlink - A Behind the Scenes Look At How The UX Binds Events

A user wrote about a case where he had a hyperlink control on a UX component. The hyperlink had an click event which displayed an alert and then 'disabled' the hyperlink by calling the .setDiabled() method of the UX component.

The actual code in the hyperlinks' click event was:


alert('I was clicked');
{dialog.object}.setDisabled('HYPERLINK_1');

 

When running the component in the UX builder with the Mobile Simulator turned on, or on a mobile device the behavior of the component was as expected. The first time the user clicked or tapped the hyperlink the alert would display and then the next time he clicked or tapped on the hyperlink nothing would display.

However, when running in a browser (or in the UX builder) with the Mobile Simulator turned off, the behavior was not as expected. Every time the user clicked the hyperlink the message displayed - the {dialog.object}.setDisabled('HYPERLINK_1') had no apparent effect.

Why?

Actually, there is a lot going on here behind the scenes.


First, if you run the component and then look at the source to see how the click event was bound to the hyperlink, you will see code like this:
 

$e.add('DLG1.V.R1.HYPERLINK_1',A5.d.evnts.click,function(e) {
    alert('click event');
    DLG1_DlgObj.setDisabled('HYPERLINK_1');
    },
this,false,'DLG1.V.R1.HYPERLINK_1');

 

The $e.add() function is a function in the Alpha Anywhere Javascript library that allows you to bind events to DOM elements. It is really just a wrapper around the built in Javascript .addEventListener() function, but it works with older browsers that don't support the .addEventListener() function.

We only need to focus on the first three arguments passed to $e.add()
 

First some background on events. The click event is fired when you click or tap on an HTML element. On a desktop browser, the event fires as soon as you click on the element. But on a mobile device there is a 300ms delay before the event fires. The reason for the delay is that the browser on the mobile device is a 'touch enabled' device and when you tap on the hyperlink it is not sure if the tap is really a tap, or just the start of some type of dragging gesture. So it waits for 300ms and then if it determines that you did not start some type of drag gesture, it decides that you really meant to fire the click event.

This 300ms delay makes your apps feel unresponsive. So Alpha Anywhere implements a special 'abstractclick' event on touch enabled devices that fires immediately when the element is tapped.

The A5.d.events.click variable is how we allow the user to define a generic click handler, but at runtime we either bind the code to the built-in 'click' event or to the 'abstractclick' event that Alpha Anywhere implements.

So, when running in a browser that is not touch enabled, A5.d.evnts.click resolves to 'click' and when running on a browser that is touch enabled, A5.d.events.click will resolve to 'abstractclick'.

However, when running on a browser that is not touch enabled, if you have the Mobile Simulator turned on, A5.d.events.click will resolve to 'abstractclick'.

So getting back to the $e.add() method that the UX uses to bind the event handler to the hyperlink. If you are on a non-touch enabled device, the code that is being executed is:


$e.add('DLG1.V.R1.HYPERLINK_1','click',function(e) { code to run when hyperlink is clicked });
 

And when on a touch enabled device (or when running in the Mobile Simulator):

$e.add('DLG1.V.R1.HYPERLINK_1','abstractclick',function(e) { code to run when hyperlink is clicked });
 

So now that we know which event is really firing when the user clicks/taps the hyperlink, lets try to understand why disabling the hyperlink only seemed to work on a touch enabled browser (or when running in a Mobile Simulator).

The way in which the code is 'disabling' the hyperlink control is by calling the UX component's .setDisabled() method. Here is how the .setDisabled() method is implemented internally in the Alpha Anywhere Javascript library:


HTML only allows you to disable form element. Form elements are input controls and buttons. A hyperlink is not an input control. There is no concept in HTML of a 'disabled' hyperlink.

So to be clear, the command:

{dialog.object}.setDisabled('HYPERLINK_1')
 

did nothing more than this:
 

var ele = {dialog.object}.getPointer('HYPERLINK_1');
//set the value of a 'disabled' property to true
ele.disabled = true;
 


We could just as easily have set the value of any other 'made up' property name. For example:


ele.myFicticiousProperty = 'some value';
 

In the case of the hyperlink element, the 'disabled' property is, in effect, a 'made up' property. As explained, there is no concept in HTML of a 'disabled' hyperlink.

So, why does it appear that disabling the hyperlink works on a touch enabled browser or in the Mobile Simulator, when, as we have discussed, hyperlinks cannot be disabled?

The reason, as it turns out, is that when Alpha Anywhere fires an abstract event on an element it checks first to see what the value of the element's 'disabled' property is. If the 'disabled' property ti set to true, it does not fire the event.

In other words, when an 'abstractclick' event is fired, the event will no do anything if the element's disabled property is true.

So now we understand what's going on here. When the component is run on a non-touch enabled device, the built-in HTML click event is bound and since hyperlinks cannot be disabled, the event fired every time the hyperlink is clicked.

But when the component is run in a touch enabled browser (on in the Mobile Simulator), the abstract 'abstractclick' event is fired and this event does honor the value of the 'disabled' property on the element.


So, how could the user have gotten this to work on both touch-enabled and non-touch browsers? Simple. Just add a line of code to the event handler:


if(this.disabled) return false;
alert('click event');
{dialog.object}.setDisabled('HYPERLINK_1');

 


After the .setDisabled() method has been called on the hyperlink, reading the element's 'disabled' property will return true. So this.disabled will be true after the .setDisabled() method has been called.

 

Build 2446-4365 1-Oct-2014

Bugs

UX Component - List Control - Detail View - A bug was introduced in build 2442 that caused the Detail View to not populate correctly in certain rare situations when a row in the List was selected.

Application Server - Reports - Under certain circumstances, a report would print correctly the first couple of times it was printed, and then start to fail.

UX and Grid Component - Grid Linked Content Section - .getParentObject() Method - If a UX or Grid was opened in a parent Grid's Linked Content Section, the child component could not use the .getParentObject() method to get a pointer to the parent Grid.

 

Build 2442-4362 29-Sept-2014

Videos

Tabbed UI Component Using Alternative Login The 'Alternative Login' feature allows a user to log in to an application using their credentials from a social network, such as Google, Twitter, LinkedIn, etc.

The UX component allows you to build Login dialogs that allow users to log into an application using an Alternative Login. The integrated login feature in the Tabbed UI, however, does not allow you to expose Alternative Logins. Therefore, if you want to allow a user to login into an application that uses the Tabbed UI, you must use a UX component in the Tabbed UI to do the log in.

In this video we show how this can be done.

Watch Video

Date Added: 2014-09-11
UX Component Downloading a Google Chart as a Bitmap In the video 'Using Google Charts as an Alternative to the Built-in Chart Controls' we showed how you can use Google Charts in a UX component. In this video we show how you can add a button to the UX to download a Google chart as a bitmap image. The user can then save the image to disk, or print the image.

Note: Not all Google chart types support this feature.

Watch Video - Part 1
Watch Video - Part 2
Download Component

Date Added: 2014-09-13
Xbasic Working with SQL Databases A common requirement in server-side events handlers (including custom Ajax callbacks) is to write some Xbasic code that manipulates data in a SQL database.

Xbasic has a very powerful set of objects (called AlphaDAO) for interacting with SQL databases.

In this video we give a quick overview to using Xbasic to work with SQL databases.

(For a full introduction and tutorial on using Xbasic to work with data in SQL databases, go to the Help, Open Documentation menu command and type 'Using Xbasic with SQL Tables' in the filter box.)

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Xbasic Calling Into Node.JS from Xbasic Node.js is a popular technology for implementing server-side utilities. Xbasic has very tight integration with Node and it is possible to create Node services that can be called from Xbasic.

In this video we show how a Node service can be defined and then called from Xbasic.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
     

 

Features

UX and Grid Component - Ajax Callbacks - OnComplete Javascript - A new option has been added to the method that makes an Ajax callback from the Grid and UX component. You can now specify Javascript to run when the callback is complete.

This option has been exposed in the Action Javascript Ajax Callback action as shown in the image below:

The Javascript that you specify is run after the callback is complete and after any Javascript returned by the callback function has executed.

To specify the after callback complete Javascript in the UX or Grid's .ajaxCallback() method, you set the onComplete property in the optional optionsObject passed in.

 

For example:

{dialog.object}.ajaxCallback('','','myXbasicFunction','','',{onComplete: function() {

        alert('callback is complete')

    }

})

 

Tabbed UI - Integrated Login Feature - When the Login window is opened, the User name field is now automatically given focus. Previously the user needed to explicitly click on the user name control. In addition, when the password field has focus, pressing the Enter key will now execute the Login button.

Security Framework - Importing Data into the User Table - The previous import method, a5ws_ImportUsersDBF(), did not support import into SQL based security tables. The import feature has been rewritten and a new method, a5ws_ImportUsers(), is available. The import will now properly add records into SQL security tables.

The a5ws_ImportUsers() method can be used to import data into either .dbf security tables or SQL security tables. When importing into .DBF tables security tables, this new method is up to twice as fast.

TIP: You can also now use the a5ws_ImportUsers() function from the Interactive Window of the Application Server control panel to import users into your security tables on your server. When you use this function from the Interactive Window it will display a list of all web projects that have security and you can select the project into which you wish to import data.

 

Xbasic - Node.JS - Extending Server-side Functionality using Node.js - Node.js is a popular program for writing server side utilities in Javascript. Alpha Anywhere now has tight integration with Node and you can now define your own Node modules that can be called from Xbasic.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

To create a new 'Node Service' that can be called from Xbaisc, you create a new .js file in the Node_Services folder in the Alpha Anywhere executable folder. The syntax for this .js file is the syntax you would use for any Node module.

To call a Node service from Xbasic, you:

 

In the following example, we have defined a trivial Node service that takes as its input two variables, 'firstname' and 'lastname' and sends back a string showing: Hello firstname lastname.

The Node service in this example is called 'hello'. Therefore the '_command' property of the JSON command object is set to 'hello'

You must also set an '_id' property in the JSON command object. This can be any value. Using a UUID for this value is convenient.

The Node service is called using the .NodeRequest() method and the result is returned as a JSON string with properties for the error text (if there was an error) and 'result' - the result of the request. The JSON response can be parsed to get Xbasic varibles, or the json_extract() function can be used to extract the 'result' property.

 

 

 

dim n as helper::V8
dim p as p

'generate an id for the request we are about to send to Node.

'we just use a GUID for convenience
p._id = api_uuidcreate()

 

'set the _command property. This is the name of the Node service we want to call
p._command = "hello"
 

 

'specify any variables you want to pass to the Node service

p.firstname = "Nellie"
p.lastname = "Jones"
 

'convert the Xbasic .dot variable to a JSON string.

dim jsonCommand as c

jsonCommand = json_generate(p)


?n.NodeRequest(jsonCommand)
= {"_id":"id1","error":"","result":"Hello Nellie Joness"}
 

 

Here is how the corresponding Hello.js file is defined. This file must be in the Node_Services folder in the Alpha Anywhere executable folder. This is a standard Node module. It can 'require' any other Node modules that you have written, or that have been installed using NPM (the Node Package Manager).

 

exports.handler = function(packet,response,sendResponse) {
    var e;
    var attachments = null;

    var msg = 'Hello ' + packet.firstname + ' ' + packet.lastname;
    response.result = msg;

    sendResponse(response,attachments);
};
 

 

If you edit the .js file in the Node_Services folder after having called it, your edits will not be seen until you shutdown the Node service. The next time you call the Node service you will see a short delay as Node starts up.

To shut down the Node service you can all the .NodeShutDown() method on the helper::V8 object instance. For example, in the above example the helper::V8 object instance was called 'n', so the following command will shut Node down.

 

n.NodeShutdown()

 

NOTE: Node.exe is automatically installed in the Alpha Anywhere executable folder when you install Node. You do not need to install Node yourself.

 

UX Component - Client-side Events - onPhoneGapReady - This event fires when the UX component is running in a PhoneGap shell and the PhoneGap library has been loaded.

NOTE: The existing onCordovaReady event has been deprecated and will be removed at some point. Move any code defined for the onCordovaReady event to the onPhoneGapReady event.

 

UX Component - {dialog.object}.phoneGapLoaded() Method - Returns true if the UX component is running in a PhoneGap shell.

 

List Control - Detail View - Disconnected Application - Count Records to Be Synchronized - A new method gives a count of the number of unsynchronized records.

 

Syntax:

object = {dialog.object}.countRecordsToSynch(listId)

 

Returns an object with properties showing the number of records that have not yet been synchronized with the server. The object has these properties: count, updatedRecords, newRecords, deletedRecords. 'count' is all dirty records (edits, inserts and deletes), 'updatedRecords' is all records that were edited, 'newRecords' is records that were added and 'deletedRecords' is records that were deleted.

 

Example:


var o = {dialog.object}.countRecordsToSynch(listOrders)
alert('You have ' + o.count + ' records to synchronize')

 

 

List Control - Detail View - New Events to Transform Data Before Display and Save - When you define a List control with a Detail View, two new properties are exposed for each List field.

 

These properties allow you to transform the data before it is displayed in the Detail View and before the Detail View is saved back to the List. The code you you specify in these two properties must 'return' the transformed value.

The Javascript for both of these properties can refer to

this._value

 

to get the default value that the Detail View control should be populated with when the user clicks on a Detail View row and to get the default value that the List should be updated with when the user clicks the Save button to save the Detail View back to the List.

For example, say that in the List data for row 2, the value for the Lastname field was 'Smith'.

In the onDetailViewPopulate event, you might specify this Javscript

return this._value.toUpperCase()

 

When the user clicked on row 2, the value shown for the Lastname field in the corresponding Detail View control would be:

SMITH

even though the actual data in the List for that field was 'Smith'.

Similarly, in the onListUpdate event, you might specify this Javascript:

return this._value.toLowerCase()

 

When Detail View edits were saved back to the List, the List would be updated with the the lowercase version of the data in the Lastname field


 

 

 

UX and Grid - Edit-Combo - Filter choices by searching anywhere in field -  Previously, in an edit-combo, as you typed into the textbox, the choices were filtered, starting the search with the first letter in the entry. Now, you can set the 'Search style' property to search anywhere in each entry.

 

For example, if the choices in the edit-combo were

 

Austria

France

USA

UK

 

and you typed 'U' in the textbox, the choices would be filtered to

USA

UK

 

Now, if you set the 'search style' to 'Anywhere in field', the choices will be filtered to

Austria

USA

UK

 

 

UX Component - HTML Editor - Toolbar Icons - You can now customize all of the icons used in the HTML editor toolbar.

Reports - SQL - Native SQL - Previously, if a report was based on a custom SQL statement and the SQL type was set to 'Native', during execution of the report the SQL statement was parsed (sometimes more than once). Parsing the SQL was necessary in order to determine if the report used arguments that were not defined (and therefore if a prompt should be shown for missing arguments) and in order to add in dynamic filters and order definitions.

In certain cases, the native SQL being passed to the report engine was so complex that parsing the SQL added a substantial delay to rendering the report.

Now, if you specify that the report data source uses native SQL the SQL query for the report will never be parsed. It will simply be passed to the database engine to execute.

As a result of this change if your native SQL statement uses arguments and you do not pass in values for all of the arguments used in the SQL, the report will no longer be able to dynamically prompt for missing argument values. Also if you are attempting to dynamically add a filter or order to the report at runtime, this will no longer work in the case were the report is based on native SQL.

 

UX Component - List Control - Scroller - Previously, the 'scroller' feature was only supported for Lists if the UX style was set to iOS7, AndroidDark or AndroidLight. Now, the scroller is supported for all styles.

Bugs

UX Component - Security Framework - Error Messages - Errors returned from the server-side Action Scripts to validate web security values, save web security values, and change web security passwords may not display property if the UX uses Panels, a placeholder is specified for the UX component validation errors, or the option to show errors in a popup window is selected. This is now fixed. The Action Scripting actions in the server-side events must be edited to apply the change. Select any of the web security actions in a server-side event and select "Edit action". Click OK to save and the code will be updated.

Grid Component - Oracle 9i - Fixed an issue using a Grid with Oracle9i.

UX Component - Textbox and Textarea Controls - Help Icon - Container With Layout Mode - If a textbox or textarea control had its help icon turned on, and if the icon was displayed left or right of the control and if the UX layoiut mode was set to 'Container width' (the default mode), the icon would show above or below the control. This is now fixed.

 

UX Component - Data Binding - Views - Auto-increment - Entering new records into a UX component that was bound to a View (rather than a Table) which had an auto-increment primary key would fail. The record was inserted, but not refreshed after insert.

UX Component - Display Wait Message on Ajax Callback - In some cases the wait message was not being cleared after the callback completed and the screen remained in a locked state.

UX and Grid Components - Lookup Grids  - SQL - Filter - If you defined a Lookup Field that used a Grid based on a SQL database and you specified that the Lookup Grid had both a static filter and a dynamic filter, you would get an error when opening the lookup Grid. The error only happened if the static filter was defined as a 'base' filter.

Grid Component - Image Download - Detail View - Image download of an image field in the Detail View part was not working correctly.

Grid Component - File Upload Action - New Record Rows - Uploading a file on a new record row caused an error.

UX Component - HTML Editor - Container Window - If you added a textarea control (configured as an HTML editor) into a Window Container, then when the window was displayed, the HTML editor was displayed, but you could not type into the editor.

Grid and UX Builder - Working Preview - Internet Explorer V10 and Earlier - If you had IE10 or earlier installed on your computer, in some cases you would get a Javascript error when testing a component in Working Preview.

 

Tips

AlphaDAO - Oracle - Returning a Resultset from a Stored Procedure - Returning a SQL::Resultset object from an Oracle stored procedure can be tricky depending on which version of Oracle you are using.

As an alternative to returning a resultset from a stored procedure, you can use an Oracle function.

In this example we show how a resultset is returned using an Oracle function.

NOTE: The Oracle database used in this example was created by using the Workspace Upsize Genie (see the 'Tool' menu when the Control Panel has focus) to upsize the sample Alphasports Workspace that ships with Alpha Anywhere.

 

 

dim cn as sql::Connection

dim flag as l
flag = cn.open("::Name::oracle_alphasportsUpsize")
 


dim sql as c
sql = <<%str%
create or replace FUNCTION REFCURSOR_CUST(p_city IN VARCHAR2) RETURN SYS_REFCURSOR AS p_recordset SYS_REFCURSOR;
BEGIN
OPEN p_recordset FOR select FIRSTNAME, LASTNAME, BILL_CITY from CUSTOMER where bill_city LIKE p_city;
return p_recordset;
END REFCURSOR_CUST;
%str%
 

 

'Oracle does not like CRLF in statements, so convert CRLF to spaces

dim sql2 as c
sql2 = stritran(sql,crlf()," ")
 

'Execute the SQL statement to define the function

flag = cn.Execute(sql2)

 

dim sql::arguments

args.add("Whatcity","Boston")
 

'Execute the function. Notice the 'from dual' syntax that Oracle requires
flag = cn.Execute("select REFCURSOR_CUST(:whatcity) from dual",args)
 

 

dim rs as sql::resultset

rs = cn.ResultSet
dim txt as c

txt = rs.ToString()

 

showvar(txt)

 

Here is what we see:


Mary McDonald Boston
Richard Queen Boston

 

If you are using Oracle 12, you have the option of using implicit cursors in a stored procedure.

The above function definition could be written as the following stored procedure:

 

CREATE OR REPLACE PROCESURE SP_GETCUSTOMERS (p_city IN VARCHAR2)

    AS

p_recordset SYS_REFCURSOR;

BEGIN

OPEN p_recordset FOR SELCT FIRSTNAME, LASTNAME, BILL_CITY FROM CUSTOMER WHERE BILL_CITY LIKE P_city;

DBMS_SQL_RETURN_RESULT(p_recordset);

END;

 

 

 

 

 

 

 

UX Component - In-Control Buttons - Delete Text - Only Show Icon if Existing Text  - The In-Control Button feature of a textbox allows you to embed icon inside a textbox. A typical use for for this feature is to allow the user to easily clear out existing text in the control.

You might want the icon to only show if there is existing text in the textbox, as shown in the the screenshots below.

 

 

In order to do this you will need to add code to t he Click action for the in-control button and to the onKeyUp event for the textbox control.

 

You will also need to add code to the onRenderComplete client-side event of the UX to set the initial state of the icon.

 

 

Here is the code you need to add to the Click action:

 

 

//clear the value in the control

{this}.value = '';
 

//get a pointer to the element that contains the icon and hide it
var ele = $('{dialog.ComponentName}.V.R1.TXT1.CUSTOMBUTTONSTATIC.0')
ele.style.display = 'none';

 

 

Here is the code to add to the onKeyUp event for the textbox.

 

//get a pointer to the element that contains the icon

var ele = $('{dialog.ComponentName}.V.R1.TXT1.CUSTOMBUTTONSTATIC.0');

//if there is text in the control, show the icon, else hide the icon
if(this.value == '') {
    ele.style.display = 'none';
} else {
    ele.style.display = '';
}

 

 

Here is the code for the onRenderComplete client-side event to set the initial state of the icon:

 

var ele = $('DLG1.V.R1.TXT1.CUSTOMBUTTONSTATIC.0')
ele.style.display = 'none';

 

 

Build 2399-4351  8-Sept-2014 - Alpha Anywhere Version 3

We are pleased to announce Alpha Anywhere Version 3. This release contains a huge number of new features, enhancements, performance improvements and bug fixes.

The standout feature in the release are the enhancements made to the List control to support building disconnected mobile applications. See the 'Features' section for details.

 

 

Videos

UX Component Tree Control - Populating Data using Javascript The data in a tree control on a UX component can easily be set using Javascript. In this video we show how to repopulate the entire tree, or dynamically add a node to an existing tree.

Watch Video
Download Component
UX Component Submitting all of the Data in a List Control on an Ajax Callback When an Ajax callback is made, the data in the variables on the UX are submitted, but the data in List controls are not submitted. There may be situations where you want to submit all of the data that are currently in a List control to the server.

In this video we show how you can 'harvest' the data that is in a List control and then submit that data to the server when you make an Ajax callback.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX and Grid Component Using Chrome for Working Preview - Debugging Javascript using the Chrome Debugger; When you are in the Component builders, the Working Preview window now allows you to choose whether you want to use Internet Explorer or Chrome.

Using Chrome has several benefits, including the ability to 'detach' the Working Preview window so that it can be moved to a second monitor and be kept open while you continue to design your component. You can also use the Chrome Debugger to debug your Javascript or inspect elements on the page.

Watch Video - Part 1
Watch Video - Part 2
UX Component List Control - Custom Control - Client-side When you define a List control in a UX component, one of the 'control types' that you can insert into the List is a 'Custom Control'. A 'custom control' is computed with an Xbasic function. Because Xbasic is used to render the custom control, it means that the custom control is rendered server-side when the List is initially rendered. If your UX component has code that modifies data in the List, the server-side custom control is obviously not re-rendered.

Therefore, you might want to define your custom control using client-side Javascript.

This video shows an approach to creating client-side custom controls in a List component.

Watch Video
Download Component
UX Component - List Control Vertically Justifying Data in a Row By default, data in a columnar List control is vertically top justified. In a Grid, on the other hand, data in a Grid row is vertically middle justified. In a Grid this is easily done because the generated HTML for a Grid uses an HTML table. The generated HTML for a List is not based on an HTML table, and so middle justifying the data is a little trickier.

In this video we show how you can vertically middle justify data in a List row.

Watch Video
Download Component
UX Component - List Control Displaying Data From Twitter The Twitter API returns data in JSON format. The List control on a UX component is easily populated with JSON data. The Twitter API, however, is a little tricky to work with because it requires an OAuth authorization before you can call the API functions. Xbasic contains two built-in functions that simplify this.

In this example we show how you can easily build a List control that displays Tweets that are retrieved by making a REST API call to Twitter.

In the example we use built-in Xbasic functions to get a 'bearer token' from Twitter. Once we have this token, we can make calls to the Twitter API to get data in a JSON format that is used to populate the List control.

IMPORTANT: The video shows selecting the Twitter List from the 'Defined Controls' section of the UX builder toolbox. This has been changed. You should now select the 'Twitter_Display_Tweets_in_a_List_Control' sample UX Component template in the dialog that appears when you create a new UX component.


Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Reports Suppressing Blank Rows in a Layout Table Report The Layout Table report editor exposes a property that you can set for each row in the Layout Table to suppress the row if it is blank.

In this video we show how blank lines in a Layout Table Report are suppressed. We also discuss how the report writer determines that a row is 'blank'.

Watch Video
UX Component Setting Content of Scrollable Containers/Windows Normally, you can set the content of an element in a component by simply getting a pointer to the element and then setting the element's .innerHTML property. However, if the element whose content you are setting has been configured to allow drag scrolling, setting the .innerHTML directly will destroy the drag scroll settings and the new content will no longer be scrollable.

The solution to this problem is to use the A5.u.element.setContent() function to set the element's content.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Edit-Combo Control - Specifying a Different Stored Value from the Display Value Dropdownbox controls allow you to specify that the stored value is different from the display value. For example, the control might display a 'ProductName' but the stored value in the control might be the 'ProductId'.

Edit-combo box controls can now also be configured to store a different value than their display value, just like a Dropdownbox control.

The benefit of using an Edit-combo control over a Dropdownbox control is that you can display multiple columns of data in the choice list and you can dynamically populate and filter the choices in the list with an Ajax callback every time the control is opened.

In this video we show how to configure an Edit-combo control to store a different value from its display value.

Watch Video
Interactive Window Executing Shell Commands Directly from the Interactive Window You can now execute shell commands directly from the Interactive Window.  You no longer have to open a separate CMD window to execute shell commands. This can be a very useful time saver for developers.

For example, when building an application that uses REST APIs, it is common for the API documentation to show how you can use CURL to execute the REST command. Using the Interactive Shell, CURL commands can be executed directly from the Interactive Window.

Watch Video - Part 1
Watch Video - Part 2
     
UX Component Dynamic Images - Client-Side When you add a 'Dynamic Image' column to a List control to display an image in the List that is based on other data in each List row you can specify if the computation of what image to show should be server-side, or client-side. If server-side, your expressions that define the conditional tests are specified in Xbasic. If client-side, your conditional expressions are expressed in Javascript.

The benefit of client-side dynamic images is that the image will be automatically recomputed when the data in a List row is updated.

In this video we show how client-side Dynamic Images can be defined and then we show another technique for creating client-side Dynamic Images using the List's Computed Columns feature. This second technique has the advantage of offering more flexibility.

Watch Video - Part 1
Watch Video - Part 2
Download Components
UX Component Client-side Template Tutorial Client-side templating allows you to generate HTML for display by merging a data object into a template. The client-side template library in Alpha Anywhere is extremely powerful and can be compared with similar functionality in 3rd party templating libraries, such as Mustache.js and Handlebars.js.

In this video we show how a complex template can be designed to display data (a list of Orders with OrderItems for each order) in a richly formatted display. The video shows how the templating system can compute values, including summary values.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
Watch Video - Part 9
UX Component - PhoneGap Displaying .PDF, .XLSX, .DOCX Files Unlike desktop browsers, the browsers on mobile devices typically do not have built-in handlers for displaying .pdf, .xlsx, .docx and certain other types of files.

If your mobile application is wrapped using PhoneGap you can easily use the built-in native document viewer on both Android and iOS devices.

In this video we show how to build a PhoneGap app that can display .pdf and Microsoft Office files.

Watch Video
UX Component - PhoneGap Using Native Transitions If you wrap a UX component in a PhoneGap shell you can now use native transitions to animate certain Panel Cards in your app into view. This feature relies on the Native Transitions PhoneGap plugin (iOS only).

In this video we show how the Native Transitions plugin can be called.

Watch Video
Web Security Framework Alternative Logins - Logging into an Application using Google, Facebook, LinkedIn or Twitter When the Application Server Security Framework is turned on you can require that a user must log into an application before they can use it. A user will enter the userid and password associated with their account in the Security Framework in order to log into the application.

You can provide an option for a user to login to their account using the credentials from a social network as an alternative to their account userid/password.

You can also allow someone to log into an application using social network credentials and then automatically create a new account in the Application Server Security Framework for that user.

These videos demonstrate this functionality. If you have not yet read the documentation on Alternative Login, it is recommended that you read the documentation before watching the videos. Click here to read the documentation.

Video 1 - Setting up the Providers
Video 2 - Creating Named Providers
Video 3 - Configuring Web Security
Video 4 - Adding Alternative Login to a UX Component
Video 4 - Testing Alternative Login
UX Component - List Control Dialing a Phone Number Shown in the List When running on a phone, it is a common requirement to be able to dial a phone number that is displayed on screen. For example, you might have a List control showing contact names and for each name you have an associated phone number.

In this video we show how you can configure a hyperlink control in the List to dial a phone number.

Watch Video
UX Component - List Control Displaying a Custom Message in the List if the List has No Records A common requirement in a List is to show a custom message if the List has no records.

The List control has built-in properties to make this easy. You can also automatically center the message horizontally and vertically in the List.

Watch Video
Video Finder Finding Videos in the Video Library There are a large number of videos that have been recorded to demonstrate and explain various features in Alpha Anywhere. The Video Finder application (accessed from the Help menu) allows you to search for videos. In Alpha Anywhere V3, the Video Finder application has been completely rewritten to make finding videos even easier and faster.

The new Video Finder application has been implemented as a UX component with two List controls - one for the list of categories, and one to list the videos in each category.

This video discusses the new Video Finder application.

Watch Video
     

 

UX Component - List Control Introduction to the List Control Detail View The List control can have an associated Detail View. The Detail View allows you to see details for the currently selected row in the List. The Detail View can be updateable, allowing you to update data that is in the List.

In this video we show how you can add a Detail View to a List. We show two different genies that you can use - one for setting up a List with a Detail View, and another for adding a Detail View to an existing List.

IMPORTANT: Lists with Detail Views are the essential building block for applications that can work while you are disconnected. For more information about the features of Lists with Detail Views, see the videos in the 'UX Component - Disconnected Applications' category. Even if you do not need to build mobile applications that work while disconnected, the information regarding Lists and Detail Views in these videos will be relevant.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07
UX Component - List Control Contrasting Data Binding at the UX Level with Data Binding at the List Level to Update a SQL Database When you want to update data in a SQL database using a UX component you previously could define Data Binding properties for the UX component, then define a server-side action that loaded the primary keys of the records you wanted to edit and another server-side action to save the edits back to the SQL database.

Now, using a List control with an updateable Detail View, you can perform edits on a SQL database using the List and its associated Detail View.

In this video we contrast the two methods of performing CRUD (create, read, update, delete) operations on a SQL database using Data Binding and List controls.


Watch Video - Part 1
Watch Video - Part 2


Download Components

Date Added: 2014-09-07
UX Component - List Control List Control Search Part The List control has a built-in Search Part that allows you to perform searches on the database that is used to populate the List. (This is very much like the Search Part in a Grid component).

The Search Part in the List can be configured in three different ways:
- individual fields for the Search Part (allowing the user for example to enter criteria in a Name, City or Country field)
- a single keyword field (allowing the user to enter criteria in a single field then then searching for matches in multiple fields)
- query by form (allowing the List's Detail View to be used to enter the search criteria)

In this video we show how the various options can be used to search a List.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4

Download Components

Date Added: 2014-09-07
     
UX Component - Disconnected Applications Introduction You can build applications that are designed to work when you are disconnected. The UX component and the List control are the fundamental building blocks of these types of applications.

In this video overview we show how a UX component is built using a List control with an associated Detail View to display and edit data, how the data in the List is persisted to Local Storage and then how the edits made to the List data are synchronized with the server. We also show how your disconnected data can be 'hierarchical' - i.e. a list of customers, with orders for each customer and order details for each order.

Watch Video 1 - Setting up a List with a Detail View using the Quick Setup Genie
Watch Video 2 - Editing Data and Persisting Data to Local Storage
Watch Video 3 - Introduction to Hierarchical Data Structures


For more information on building disconnected applications, click here.

Date Added: 2014-09-07
UX Component - Disconnected Applications Editing Data While Offline and then Synchronizing the Data When you build an application for disconnected operation, the List control is the basic building block for the application. The List control is used as the 'offline' data storage. The data in the List control can be thought of as an in-memory table. Edits to this data are persisted to Local Storage and then are pushed to the server to synchronize with the server database when a connection is available.

In this video we look at how data in the List are edited and then synchronized with the server database.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Editing Data While Offline - Behind the Scenes - What Data are Stored in the List In order to get a better understanding of how the data in a List control are stored to support disconnected operation, this video shows how you can debug into the internal data that is stored in the List when the user edits, enters and deletes records.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Errors - Validation Errors When a user synchronizes edits to data that were made while they were offline, there is the possibility of synchronization errors.

These errors can typically result because the user entered a value in a field that was rejected by some server-side validation logic, because of a write conflict, or because the database rejected the edit.

In this video we show how synchronization errors that result from server-side validation errors and database errors are handled.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Errors - Write Conflicts When a user synchronizes edits that were made while they were offline, there is the possibility that some other user edited and then synchronized the same data before the user had a chance to synchronize his/her edits.

If this happens a write conflict will occur and the user will be notified that the synchronize operation could not be completed. The user will have to choose how to resolve the conflict. The developer also has the option of handling write conflict errors programmatically.

In this video we show how write-conflict errors are handled.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3


Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Events When data in a List control is synchronized with the server database there are a number of events that fire (on both the client-side and the server-side) that give you a lot of control over the process and allow you to inject custom code to be executed.

In this video we discuss some of the events that fire when data are synchronized.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Custom Synchronization Handlers When the user synchronizes a List that is based on a SQL database, Alpha Anywhere automatically generates the SQL statements to perform the various CRUD (create, read, update, delete) operations.

However, if your List is based on a custom datasource (for example, a web service), then you must write your own functions to handle synchronization of the data.

In this video we show an example of how custom handlers can be written to synchronize data.

Watch Video - Part 1
Watch Video - Part 2

Download Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Incremental Refresh After a List has been populated with data from the server you can perform incremental refreshes on the List data to retrieve any edits that have been made to server data. Unlike a full refresh, only rows that have been edited are sent to the client, resulting in a much smaller payload being sent to the client compared to a full refresh of the List data.

You can also set a 'synchronization policy' in the List definition to specify that every time edits to the List data are synchronized with a server an incremental refresh of the List should also be performed.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Geographic Data - Capturing Location Information when the User Edits Data You can configure a List so that every time the user enters a new record, or edits a record, the user's location will be stored. This allows you to create applications where you capture the location of the device at the time a record was edited or entered.

In this video we show how this is done.

Watch Video - Part 1
Watch Video - Part 2

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Geographic Data - Capturing Location Information when the User Synchronizes Data In a  previous video we show how location information can be captured at the time the user edits a record in the List. But you can also capture location information at the time the user synchronizes the data.

In this video who show how to configure the List to submit location information at the time the user synchronizes the List.

Watch Video

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
     
UX Component - Disconnected Applications Geographic Data - Geocoding Data In order to perform geography searches on your data (for example, find all records that are within 5 miles of my current location), you need to geocode the data in your table. For example, if you have captured the address for the record, when the record is synchronized, you can make a call to a geocoding service to get the latitude/longitude for the record. Then when the record is written to the database you can also compute the location field value so that geography searches are possible.

In this video we discuss the features that the List control exposes to support working with geographic data.

Watch Video

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Setting Default Values for Fields in New Records When you enter a new record in a List with a Detail View you might want to set default values for certain of the fields in the Detail View.

The List builder allows you to execute Javascript code to compute the default value for each field in the List. This allows for sophisticated computations for the default value, including setting the default value for a field to the value that was just entered into the previously entered record.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronizing Data in Batches If the user has made a large number of edits while they were offline you might want to synchronize the data in batches, rather than sending all of the edits to the server at once.

In this video we show how you can configure the synchronization process so that data are sent to the server in batches.

Watch Video
Download Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Delaying Populate List Till Active Search In an application designed for disconnected usage, the user will typically load a subset of the database onto their mobile device while they have connection.

This is usually done by adding a Search Part to the primary List control in the component and specifying the the List should not be populated until the user has performed a search to retrieve the 'records of interest'.

TIP: For more information on how to set up the Search Part for a List control see the video titled 'List Control Search Part'.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Settings Maximum Number of Records that a Search Can Return In an application designed for disconnected usage, the List controls in the UX component hold the data that will be available while the user is offline. These Lists are populated when the user does a search to retrieve the 'records of interest' that they want to have available to them while they are on-line.

Since the amount of data that can be held on a mobile device is limited, you will typically want to ensure that the user does not enter search criteria that retrieve too many records.

In this video we show how you can set limits on how large a result a user search is permitted to return.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Persisting Data to Local Storage When you build an application for disconnected operation you need to be sure that the data in the application is persisted to Local Storage so that edits that are made to any data are not lost if the application is restarted before the user has had a chance to synchronize the data with the server.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3


Date Added: 2014-09-07
UX Component - Disconnected Applications Working with Hierarchical Data The data for disconnected applications are stored in List controls. In many types of applications the data you need to work with is hierarchical. For example, you might have a list of customers. Each customer has orders and each order has order details.

In a connected application, you can make an Ajax callback to the server when a user selects a different customer to fetch to orders for that customer. However, in a disconnected application you cannot make callbacks to the server, so when the user selects a customer, the orders for that customer must already have been retrieved from the server so that the data can be shown without making an Ajax callback.

The List control can easily be populated with hierarchical data. In this video we explain how a List control is populated with a customers, each customers' orders, and each order's details.

Watch Video - Part 1
Watch Video - Part 2

In this follow on video we show how new records can be added to child tables and how the new records are automatically linked to their parent. In the video we show how a new order is added for the selected Customer record and then how new order detail records are added for the new order. When the data are synchronized, the linking fields are automatically filled in - the customer Id is filled into the new order record and the order id is filled into the new order detail records.

Watch Video - Part 3

Download Component


Date Added: 2014-09-07
UX Component - Disconnected Applications Managing Local Storage When you build an application that is designed for offline use (i.e. a disconnected application), the data in the List controls, and the variables in the UX component are persisted to Local Storage.

In this video we show how you can manage the data in Local Storage using the built-in Local Storage manager and using methods of the UX component.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07

Features

Building Disconnected Mobile Applications - The UX component now allows you to build mobile applications that work while you are disconnected.

 

The following videos will give you a quick overview of building disconnected applications in the UX component:


Watch Video 1 - Setting up a List with a Detail View using the Quick Setup Genie
Watch Video 2 - Editing Data and Persisting Data to Local Storage
Watch Video 3 - Introduction to Hierarchical Data Structures
 

For detailed information about this feature, click here.

 

UX Component - List Control - Detail View and Search Part- List controls can now have an updateable Detail View and an integrated Search Part.

This feature is central to building disconnected applications, but should also be of great interest to developers of traditional desktop web application. (See the section in the detailed information - see link below -  that contrasts Data Binding with updateable Lists).

 

For detailed information about this feature, click here.

 

Application Server - 64 bit Machines - Alpha Anywhere is now compiled using a special compiler switch that allows access to more system RAM when running on a 64 bit machine. As a 32bit application, the amount of system RAM that Alpha Anywhere can access is limited to approximately 2GB. Now, up to 4GB of system RAM can be accessed. As a result of this change larger files can be uploaded, more simultaneous uploads can be performed, more sessions can be handled, and server restarts because of memory fragmentation should be needed less frequently.
 

 

Video Finder - The Video Finder (accessible from the Help/Video Finder menu) has been completely rewritten. The Video Finder now loads much more quickly and searches are much faster. Also, you can now click the 'Preferences' button on the toolbar to specify if the Video Finder should be opened in a MDI window or a modeless window. The modeless window option is useful if your computer has two monitors because it allows you to drag the Video Finder window to the second monitor and keep it open while you are working.

 

Watch Video

 

 

UX Component - List Control - Custom 'No Records in List' Message - A common requirement in a List is to show a custom message if the List has no records.

The List control has built-in properties to make this easy. You can also automatically center the message horizontally and vertically in the List. See image below.

Watch Video

 

 

 

UX Component - List Control - Hyperlink - Telephone - You can now configure a hyperlink control in a List to dial a telephone number. This is particularly useful in mobile applications that are run on a phone.

 

Watch Video

 

Assume you have a List control with this data:

name|phoneDisplay|phoneDial

John Smith (home)|(555) 555-5555|+15555555555

John Smith (mobile)|(555) 555-5556|+15555555556

 

The List data contains both the phone number to display in the List and the phone number to actually dial. Notice that the phone number that should be dialed includes the +1 prefix to indicate that this is a U.S. phone number. The phone number to be dialed must start with + and then the country code (1 in the case of the U.S.).

The phone number to be dialed can also include special directives. For example you can insert 'p' in the number to indicate a one-second pause and 'w' to indicate 'wait for dial tone'.

Using the sample data shown above, to configure the hyperlink to dial the telephone number in the 'phoneDial' field, but display the number shown in the 'phoneDisplay' field, you would set the 'Action type' property to 'Telephone', the 'Phone number' field to '{phoneDial}' (note that the placeholder is case-sensitive) and the 'Hyperlink text' property to '{phoneDisplay}', as shown in the image below.

It is permissible for the value passed in as the phone number to dial to include spaces and parentheses. For example, +1(555) 555-5555 is a valid number to dial.

 

 

If, for example, your List data had separate fields for the phone number (called 'phone' for example) and country code (called 'code' - without the leading + in the data), you could set the 'Phone number' field to:

+{code} {phone}

 

UX Component - List Control - Hyperlink - E-mail - You can now configure a hyperlink control in a List to open the associated e-mail client and fill in the 'to' address with a field.

To configure a hyperlink to open an e-mail client, set the 'Action type' to 'Email' and the 'Email address' to the value you want to put into the email client's 'to' address field. You can use placeholders in the 'Email address' property to refer to data in a field in the current row of the List.

 

 

UX Component - List Control - Hyperlink - Specifying a Target HRef - Previously, when you added a hyperlink control to a List, the action associated with the hyperlink was always some Javascript code. Now you can define standard HTML hyperlinks with an 'href' attribute that specifies the hyperlink target.

To specify a hyperlink target, set the 'Action type' to 'Href' and then specify the 'Hyperlink address'. You can use a placeholder for the address. For example if your List has a field called 'address', you can specify the 'Hyperlink address' as {address}.

The hyperlink address must include the protocol if the target is not a page in the application webroot. For example, to display bing.com, you would need to set the target to 'http://www.bing.com', but to display a page called 'page1.a5w' in the current webroot, you would just need to set the target to 'page1.a5w'.

 

 

 

 

Client-Side Template Tester - User Interface Improvements - The user interface in the client-side template tester window has been enhanced. The window is now resizable and has separate tabs for JSON Data, Template, Javascript and CSS.

As you edit in any of these windows the template preview is automatically updated in the right part of the window.

 

 

 

json_reformat_safe() Function - Reformats as string of JSON data with line-breaks and optional indentation.

Syntax:

c json_text = json_reformat_safe(json_text [, flagIndent = .t.])

 

For example:

 

dim json as c

json = <<%txt%

{firstname: 'Fred', lastname: 'Smith', Address: {
Street: '123 Main St',
City: 'Boston',
State: 'Ma'
}
}
%txt%

 

?json_reformat_safe(json)

= {
    "firstname": "Fred",
    "lastname": "Smith",
    "Address": {
        "Street": "123 Main St",
        "City": "Boston",
        "State": "Ma"
    }
}

 

NOTE: json_reformat_safe() wraps the lower level json_reformat() function. The json_reformat() function only accepts 'properly formed' JSON strings (property names must be double quoted and string values must be double quoted). json_reformat_safe() will automatically convert JSON strings where property names are not quoted and strings are single quoted.

 

json_extract() Function - Extracts a property from a JSON object .

Syntax

c text = json_extract( C json_text, c property_name)

 

NOTE The JSON text passed to the function must be properly formed (i.e. use double quotes on property and string names). You can use json_reformat_safe() to 'clean' up the JSON string before calling json_extract.

 

For example:

dim json as c

json = <<%txt%

{

    name: 'Fred',

    address: {

        street: '123 Main St',

        city: 'Boston',

        state: 'MA'

    }

}

 

'json_extract() requires properly formed JSON, so

'we first call json_reformat_safe()

dim json2 as c

json2 = json_reformat_safe(json)

?json_extract(json2,"name")

= "Fred"

?json_extract(json2,"address")

= "

{

        street: '123 Main St',

        city: 'Boston',

        state: 'MA'

    }

"

%txt%

 

 

Grid Component - Export - Comma Delimited ASCII - Quoting Fields with Commas - If the data you are exporting has commas in the data, the fields with commas are now quoted. If there are quotes inside a field, the quotes are escaped as double quote (e.g. "").

 

UX Component - Image Upload - Clear Image - Action Javascript has a method to upload an image and save the uploaded image in a field in the table that the UX is bound to. However there was no easy way to clear out a previously uploaded image - and set the field back to a null value. A new action in Action Javascript now support the 'Delete Image' action.

 

UX Component - Security Framework - Alternative Login - Login with Google, Facebook, Twitter and LinkedIn - You can now allow users to log into an Alpha Anywhere application using a 'social network' login.

The social network logins are referred to as 'alternative logins' because they provide an alternative way for a user to log into their account in the Alpha Anywhere security system using their social network credentials, rather than the userid/password associated with their account in the Alpha Anywhere security system.

The Alternative Login features are exposed as new actions in Action Javascript for use in a UX component.

For complete details on the Alternative Login feature click here.

 

Video 1 - Setting up the Providers
Video 2 - Creating Named Providers
Video 3 - Configuring Web Security
Video 4 - Adding Alternative Login to a UX Component
Video 4 - Testing Alternative Login

 

NOTE: In a previous pre-release build we added support for Google's OpenID protocol.Google has deprecated this protocol, and therefore we will not be supporting it in Alpha Anywhere.  If you attempted to test the OpenID protocol in a pre-release build, please send a bug report and we can provide instructions on removing the OpenID elements as they are not compatible with the current system, which is based on oAuth.

 

Xbasic - CURL - CURL is a popular utility that can be used for many tasks, such as making REST API calls. CRUL is now exposed as a top level Xbasic object, allowing you to execute CRUL commands from your Xbasic code.

Many APIs are documented using CURL examples.

You can use a built-in genie to convert a CURL command into an Xbasic script.

To get to the CURL genie, right click on white space in the Xbasic code editor and select the 'Genies...' command. The select the 'CURL command to Xbasic....' command.

 

 

 

This opens the CURL to Xbasic Genie where you can type in a CURL command then then click the 'Generate Xbasic' button to generate the Xbasic code to execute the specified CURL command.

For more information on the Xbasic CURL object, click here.

 

 

Xbasic - Parsing a Name/Value String - extension::URIQuery Class - Xbasic now has a new utility class that makes it very easy to parse name/value pairs in a 'query string'.

The following Interactive Window session demonstrates use of this class:

 

 

dim qs as c = "name=fred&city=boston&country=&age=25"
dim postQ as extension::URIQuery
postQ.ParseURIQuery(qs)
?qs
= "name=fred&city=boston&country=&age=25"

?postq.age
= "25"

?postq.country
= ""

?postq.ToJson()
= {"name":"fred","city":"boston","country":"","age":"25"}

 

Template Tester - Tools Menu - The Template Tester can now be opened directly from the Tools menu when the Web Control Panel has focus.

The Template Tester is useful when you are constructing templates that generate HTML by expanding data in an object. See 'Client-side Templates' in the Release Notes for information on templates.

NOTE: While templates are documented in a section called 'Client-side Templates' this is somewhat misleading because you can also use templates in server-side code using the a5_merge_JSON_into_template() Xbasic function.

 

Client-side Template Enhancements - Client-side Templates (first introduced in build 2091 - 4284 - see Release Notes for more information) have been enhanced.

 

The {*root} Tag

Previously if the data you passed into the  A5.u.template.expand() function was an array (as opposed to an object with an array as property of the object), you could not use the {*header} and {*footer} directives in your template to generate a header or footer for the array data.

Now, you don't have to artificially structure your data as a top level object with an array as a property of the object. The {*root} tag is now supported when the data passed in is an array.

 

Consider the following sample data:

var data = [
    {firstname: 'Fred', lastname: 'Smith'},
    {firstname: 'John', lastname: 'Jones'}
]

 

and the following template:

 

var template = [
                            '{*root}',
                            '{*header}There are {root.length} people<br />{/*header}',
                            '{firstname} {lastname}<br />',
                            '{*footer}Count: {root.length} {/*footer}',
                            '{/*root}'

                        ].join('');
 

This data and template will product this output:

 

There are 2 people
Fred Smith
John Jones
Count: 2

 

Because the template uses the {*root} tag, the data that is passed in is implicitly restructured as:

 

var data = {

    root: [
            {firstname: 'Fred', lastname: 'Smith'},
            {firstname: 'John', lastname: 'Jones'}
           ]
    }


 

Escaping the { and } Characters in a Template

The { and } characters in a template indicate placeholders for merged data. If you want to explicitly output either of these characters you can escape them using a leading backslash.

Assume that the data you pass to the template expander is:

{firstname: 'Fred'}

Assume that you want the output from the template to be

{Fred}

You would define your template as:

\{{firstname}\}
 

 

Pre-processing Arrays Before They are Expanded

You can now pre-process arrays before they are expanded.

For example, assume you have the following data:

 

var data = {

    company: [
        {firstname: 'Fred', lastname: 'Smith'},
        {firstname: 'John', lastname: 'Jones'},
        {firstname: 'Andrea', lastname: 'Jones'},
        {firstname: 'Margo', lastname: 'Jones'}
    ]
}
 

And the following template:

var template = [
    '{company}',
    '{firstname} {lastname}<br>',
    '{/company}'

].join('');
 

This template and data combination will result in this output:

Fred Smith

John Jones

Andrea Jones

Margo Jones

 

But, say you only wanted to output the top two customers. To do this you would need to pre-process the company array before it was expanded. You can specify the name of a function (which can be a global function, or a function in a namespace) to call before an array is expanded using the @functionName directive in the placeholder for the array.

 

For example, notice in the template below, the placeholder for the company array specifies that the processCompany function should be called before the data are expanded:

var template = [
    '{company@processCompany}',
    '{firstname} {lastname}<br>',
    '{/company}'

].join('');
 

The array pre-processor function gets called with three arguments

Your array pre-processor function must return the array that you want to render.

Here is how the processCompany array pre-processor function could be defined:

function processCompany(data,temp,root) {

    //limit to first two items in the array

    data = data.slice(0,2);

    return data;

}

 

The resulting output is now:

Fred Smith

John Jones

 

Now assume you want to first sort the data by the 'firstname' property, then return the top two entries. In this case, the array pre-processor function would be defined as:

 

function processCompany(data,temp,root) {

    //sort on the 'firstname' property

    data.sort( function(a,b) {
        if (a.firstname < b.firstname) return -1;
        if (a.firstname > b.firstname) return 1;
        return 0;
        }
    )
 

    //limit to first two items in the array

    data = data.slice(0,2);

    return data;

}

 

The resulting output is now:

Andrea Jones
Fred Smith

 

An important use for the array pre-processor function is to compute summary data for the array. See Using the Special "root" and "temp" Variables in Templates below. You can compute all of the summary values your template needs in a single function, rather than defining separate functions for each summary value your template outputs.

 

Using the Special "root" and "temp" Variables in Templates

You can use the special "root" and "temp" variables in a template by enclosing them in [ and ].

The example below demonstrates the use of both [root] and [temp] in the template.

Download component that demonstrates this example.

 

TIP: To watch a video of how the template used in this example was developed, watch these videos:

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
Watch Video - Part 9

 

For example, consider the following data set:

 

var data = [
    {

        orderId: 1,

        date: '1/1/2014',

        orderItems: [

                {itemId: 1, qty: 3, price: 23.4},

                {itemId: 23, qty: 2, price: 3.3},

                {itemId: 7, qty: 5, price: 5.3}

            ]

    },
    {

        orderId: 2,

        date: '1/2/2014',

        orderItems: [

            {itemId: 31, qty: 7, price: 3.8},

            {itemId: 17, qty: 4, price: 9.2}

        ]

    },

    {
        orderId: 3,
        date: '1/5/2014',
        orderItems: [
            {itemId: 11, qty: 9, price: 13.3},
            {itemId: 27, qty: 2, price: 19.2},
            {itemId: 6, qty: 19, price: 3.6},
            {itemId: 7, qty: 22, price: 9.1}
        ]
    }
]

 

The data are an array of order objects. Each order has a nested array called 'orderItems' that have the order items for that order.

Assume that you would like the template to render as shown below:

 

Order Id: 1 (Order number 1 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/1/2014
#Item IdQuantity PriceExtended Total
113$23.40$70.20
2232$3.30$6.60
375$5.30$26.50
Count: 3Avg Quantity: 3.33Avg Price $10.67Total: $103.30

Order Id: 2 (Order number 2 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/2/2014
#Item IdQuantity PriceExtended Total
1317$3.80$26.60
2174$9.20$36.80
Count: 2Avg Quantity: 5.50Avg Price $6.50Total: $63.40

Order Id: 3 (Order number 3 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/5/2014
#Item IdQuantity PriceExtended Total
1119$13.30$119.70
2272$19.20$38.40
3619$3.60$68.40
4722$9.10$200.20
Count: 4Avg Quantity: 13.00Avg Price $11.30Total: $426.70

Grand total for all 3 orders is: $593.40

 

There is a lot going on in this example. The template for this example is shown below.

Items of note in this example include:

Here is the template for this example:

var template = [
    '{*root}',
        'Order Id: {orderId} (Order number {[countOneBased]} of {[root].length} orders - for orders placed between <b>{[root][0].date}</b> and <b>{[root][-1].date}</b>) <br>',
        'Order Date: {date}<br>',
        '{orderItems@orderItemsPreProcessor}',
            '{*header}',
                '<table border="1" cellspacing="1" cellpadding="3" style="border-collapse: collapse;" >',
                '<tr>',
                    '<th>#</th>',
                    '<th>Item Id</th>',
                    '<th>Quantity</th>',
                    '<th>Price</th>',
                    '<th>Extended Total</th>',
                '</tr>',
            '{/*header}',
            '<tr>',
                '<td>{[countOneBased]}</td>',
                '<td>{itemId}</td>',

                '<td style="text-align:right;">{qty}</td>',
                '<td style="text-align:right;">{price:number(\'$#,###.00\')}</td>',
                '<td style="text-align:right;">{qty*price:number(\'$#,###.00\')}</td>',
            '</tr>',
            '{*footer}',
                '<tr>',
                    '<td>Count: {[temp].itemCount}</td>',
                    '<td></td>',
                    '<td>Avg Quantity: {[temp].averageQuantity:number(\'#.00\')}</td>',
                    '<td>Avg Price {[temp].averagePrice:number(\'$#,###.00\')}</td>',
                    '<td style="text-align:right;">Total: {[temp].totalExtendedPrice:number(\'$#,###.00\')} </td>',
                '</tr>',
                '</table><br>',
            '{/*footer}',
        '{/orderItems}',
        '{*footer}',
            'Grand total for all {[root].length} orders is: {[temp].grandTotal:number(\'$#,###.00\')}<br>',
        '{/*footer}',
    '{/*root}'
].join('');
 

The array pre-processor function for the 'orderItems' array is defined as follows:

 

function orderItemsPreProcessor(data,temp,root) {
    var totalQuantity = 0;
    var totalPrice = 0;
    var totalExtendedPrice = 0;
    var extendedPrice = 0;
    var _d = '';
    for(var i = 0; i < data.length; i++) {
        _d = data[i];
        extendedPrice = _d.qty * _d.price;
        totalExtendedPrice = totalExtendedPrice + extendedPrice;
        totalPrice = totalPrice + _d.price;
        totalQuantity = totalQuantity + _d.qty;
    }

    //the first time this function is called temp.grandTotal will be undefined

    //so we initialize it to 0
    if(typeof temp.grandTotal == 'undefined') temp.grandTotal = 0;

 

    //we can then accumulate the grand total for all orders
    temp.grandTotal = temp.grandTotal + totalExtendedPrice;
 

    temp.averagePrice = (totalPrice / data.length);
    temp.averageQuantity = (totalQuantity / data.length);
    temp.totalExtendedPrice = totalExtendedPrice;
    temp.itemCount = data.length;
    //it is CRITICAL that the pre-processor function return an array to be expanded
    //even though this function has not modified the data in the 'data' array,

    //it must still return the 'data' array
    return data;
}

 

Templates Can Reference Functions in Any Namespace and Can Take Arguments

Previously, when a template referenced a function, the function needed to be defined as a global function. Now, templates can reference functions an arbitrary namespaces.

Consider the following simple example:

Data:

 

var data = [
    {firstname: 'Fred', lastname: 'Smith'},
    {firstname: 'John', lastname: 'Jones'}
]
 

 

Javascript function definition:

(Notice that the function takes two arguments and is in the 'obj' namespace.)

var obj = {
    fullname: function(fn,ln) { return 'Hello <b>' + fn + ' ' + ln + '</b>'}
}
 

Template:

(Notice that the template calls the function in the 'obj' namespace and passes in argument values from the current row.)

var template = '{firstname} {lastname} Function call is output here: {@obj.fullname(firstname,lastname)}<br>'

 

The output HTML produced is:

Fred Smith Function call is output here: Hello Fred Smith
John Jones Function call is output here: Hello John Jones

 

Defining Custom Formatters

Templates can format data before it is output using the built-in format directives. For example, you can format a number so that it has $ and two decimal places by using the :number() format directive.

For example:

{price:number(\'$#,###.00\')}

 

However, you can also define your own custom format directives. This is done by adding functions to the A5.u.template.formats object.

Consider the following example:

 

Data:

var data = {

    company: [
        {firstname: 'Fred', lastname: 'Smith', phone: 7815551234},
        {firstname: 'John', lastname: 'Jones', phone: 2125551234},
        {firstname: 'Jane', lastname: 'Jones', phone: 4155551234},
        {firstname: 'Margo', lastname: 'Jones', phone: 4325551234}
    ]
}
 

Template:

var template = [
    '{company}',
    '{firstname:formatName(\'l\')} {lastname:formatName(\'u\')} {phone:phoneNumber}<br>',
    '{/company}'

].join('');
 

Notice the template uses custom formatters for the each of the fields. Both 'firstname' and 'lastname' use a custom formatter called 'formatName' and in one case an argument value of 'l' is passed in (to format the data as lower case) and in the second case, an argument value of 'u' is passed in (to format the data as upper case).

The 'phone' field uses a custom formatter called 'phoneNumber'. This formatter does not take any arguments.

To define these two custom formatters, the following Javascript is used to add the format functions to the A5.u.template.formats object:

 

A5.u.template.formats.formatName = function(value,flag) {
    if(flag == 'u') return value.toUpperCase();
    else if(flag == 'l') return value.toLowerCase();
    else return value;
}

 

 

A5.u.template.formats.phoneNumber = function(value) {
    return value.toFormat('=(###)-###-#####');
}

 

Notice that the custom format functions all get passed 'value' - the value to be formatted.


Arguments Passed to Template Functions

If a template function does not explicitly specify arguments, the implicit arguments passed to the function now include the special 'temp' and 'root' variables.

For example, consider the following template snippet:

{@myCustomFunction}


This template function does not specify any arguments. Therefore the 'implicit' arguments for the function called are:

Previously, only 'data' and 'context' were passed to the function.

Where context is a string with the name of the variable that the function was being called in the context of. For example, in a {*header} or {*footer} directive for an array called 'company' the 'context' would be 'company'. Hhowever in an individual item in the company array, the context would be blank (as the context is implicit).

 

 

UX Component - List Control - Dynamic Images - Client-Side - The List control now allows you to define client-side Dynamic Image fields.

Previously, Dynamic Images were computed on the server. This meant that if the List was populated dynamically using Javascript code, the Dynamic Images would not be computed.

The Dynamic Image builder now allows you to specify the type of Dynamic Image.

 

If you choose the 'Client-side' option, then you must enter the condition expressions using Javascript. Keep in mind that Javascript is case-sensitive, you must use double equals (i.e. ==) and not a single equals for equality tests, and that strings must be single quoted. Also, when referring to a field in the current row, the field name is prefixed with data. .

The major benefit of client-side dynamic images is that if the data in a List row is edited, the Dynamic Image is immediately recomputed.

Watch Video - Part 1
Watch Video - Part 2
Download Components

 

 

UX and Grid Components - Javascript - Trapping Syntax Errors - When you save a component, Javascript function declarations are checked for syntax errors. Also when you edit the Javascript for an event handler, the syntax is checked for syntax errors. Previously this functionality was available, but was turned off by default. Now, it is turned on by default because a more robust method for checking Javascript syntax is used. (Based on the Node.JS 'Grasp' module).

If you want to disable Javascript syntax checking, go to View, Settings, Preferences, Javascript.

 

 

OLE Automation - Named Parameters - You can now use named parameters in an OLE automation call. The technique for doing this involves defining a dot variable with the parameters, then passing in the dot variable to the OLE method.

Previously, if you want to specify a value for an optional parameter you had to supply values for all of the optional parameters preceding the one you wanted to define. This could be very tedious.

For example, consider the function prototype for the Microsoft Word .open() method.

 

.Open(FileName, [ConfirmConversions], [ReadOnly], [AddToRecentFiles], [PasswordDocument],
 [PasswordTemplate], [Revert], [WritePasswordDocument], [WritePasswordTemplate], [Format],
 [Encoding], [Visible], [OpenAndRepair], [DocumentDirection], [NoEncodingDialog],
 [XMLTransform])
 

As this prototype shows, only the first argument (FileName) is required. All other arguments are optional. If you wanted to supply a value for (say) the 'ReadOnly' argument, you would need to specify a value for the 'ConfirmConversions' property as well.

Now, you can define a dot variable and define property values for just the arguments you want to set.

For example:

 
Dim wrdApp As P 'Word.Application
Dim wrdDoc As P 'Word.Document
wrdapp = ole.create("word.application")
 

'define a .dot variable and define the arguments you care about

dim args as p
dim args.FileName as c = "e:\files\hello.docx"
dim args.ReadOnly as l = .t.

 

'pass in the .dot variable to the OLE .open() metehod
wrdDoc = wrdapp.Documents.Open(args)
 

 

OLE Automation - Bubble-help for OLE Methods - The Xbasic editor and Interactive window now show the argument list for OLE methods. This is especially useful when you want to use named parameters and pass in a dot variable to the method because it lets you see the argument names, which you will use in the dot variable.

 

 

 

Interactive Window - Shell Commands - You can now execute shell commands directly from the Interactive window. Examples of the different use cases for this feature include:

Watch Video - Part 1
Watch Video - Part 2

 

Any command with a $ prefix that you enter in the Interactive window is considered to be a shell command. For example, type the following in the Interactive window:

$dir c:\windows

 

For detailed information on the Interactive window shell commands click here.

 

 

 

Action Javascript - Open .a5w Page Action - Page URL - If the page URL is specified by a placeholder that references fields in the current component, or uses placeholders in the URL, you can now specify that the value in individual placeholders should not be URL encoded by entering the placeholder name as:

{nourlencode:placeholderName}

For example:

{nourlencode:field1}

By default all placeholder values are URL encoded when they are replaced in the URL.

 

UX Component - Edit-Combo Control - Specifying Different 'Stored' and 'Display' Values - Dropdownbox controls allow you to specify that the stored value is different from the display value. For example, the control might display a 'ProductName' but the stored value in the control might be the 'ProductId'.

Edit-combo box controls can now also be configured to store a different value than their display value, just like a Dropdownbox control.

NOTE: If you configure an Edit-combo to have a different stored value from its display value, then you must check the option to only allow the user to select values in the choice list. The user cannot type arbitrary values into the control.

 

The benefit of using an Edit-combo control over a Dropdownbox control is that you can display multiple columns of data in the choice list and you can dynamically populate and filter the choices in the list with an Ajax callback every time the control is opened.

Watch Video

 

jQuery - Make Safe for Alpha Anywhere - a5_make_jQuery_safe() Function - Many jQuery Javascript files are written using the $ object as a proxy for the jQuery object. This makes it impossible to use these files in AlphaAnywhere without first editing the files and changing the $ object to the jQuery object. This can be a tedious process because a simple search and replace will not work as that would replace the $ string literal.

The a5_make_jQuery_safe() function converts all references to the $ object to 'jQuery' while leaving $ in variables names and strings unchanged.

NOTE: This function is built on top of the Node.JS GRASP module.

Syntax:

L flag =a5_make_jquery_safe(c filename [, flagCreateBackup = .t. ])

 

If fileCreateBackup is .t. a file with the extension of .old is created with the original text in the file.

 

 

HTML Reports - No Records in Report - If an HTML report has no records in it, it previously displayed a blank page. Now a 'No records in report' message is shown.

UX Component - A5.u.element.setContent() Function - Normally, you can set the content of an element in a component by simply getting a pointer to the element and then setting the element's .innerHTML property. However, if the element whose content you are setting has been configured to allow drag scrolling, setting the .innerHTML directly will destroy the drag scroll settings and the new content will no longer be scrollable.

The solution to this problem is to use the A5.u.element.setContent() function to set the element's content.

Watch Video - Part 1
Watch Video - Part 2
Download Component

 

Syntax

A5.u.element.setContent(element,html [, options])

 

Where:

Example:

//get a pointer to the 'CONTAINER_1' container

var ele = {dialog.object}.getPointer('CONTAINER_1');
var string = 'define some long string of html here';
string = string + '<span id="span1">end of string</span>';
var settings = {animation: {allow: true}};

var settings: {
    fireEvent: false, //fire the scroll event
    mode: 'into-view', //mode can be 'into-view', 'top', 'bottom'
    axis: 'both', //which axes do you want to scroll on
    offset: {x: 0, y: 0}, //offset from the element that you are scrolling to
    animation: {allow: true, duration: 300} //animation
}
//scroll the element 'span1' into view
var obj = {element: 'span1', settings: settings};
A5.u.element.setContent(ele,string,obj);
 

//in this next example, instead of scrolling an element into view,

//we scroll to position 0,0 in the new content

//get a pointer to the 'CONTAINER_1' container

var ele = {dialog.object}.getPointer('CONTAINER_1');
var string = 'define some long string of html here';
string = string + '<span id="span1">end of string</span>';
var settings = {}
var obj = {x: 0, y:0, settings: settings};
A5.u.element.setContent(ele,string,obj);
 

 

 

Temp File Folder - Temporary Files - Code has been added to more aggressively clean up any temporary files that Alpha Anywhere created in the temp file folder. To turn on this feature for the development version go to the View/Settings/Preferences menu and set the value for the 'TEMP files' property.

To specify the setting in the Application Server (or the Development Server), go to the 'Advanced' tab in the server control panel.

 

 

Reports - Layout Table Reports - Suppress Blank Rows - A new property has been added for each row in a Layout Table report that makes it easy to suppress the entire row in the report if all of the columns in that row are blank.

Watch Video

To set the property, click in the vertical ruler to the left of the row whose property you want to set.

Then, in the property sheet, set the 'Suppress Blank' property.

 

 

 

A row is considered to be blank if the expression that defines the contents for each column in the row is a NULL value (i.e. equals the value returned by the null_value() function).

Note that:

 


 

 

 

UX Component - List Control - Show/Hide List Footer - .rowExpander() Method -  Each row in a tabular List layout can have an optional 'List Item Footer'. (Similar to a row expander in a Grid component). The initial state of the List Item Footer can be opened, or closed. The <listObject>.rowExpander() method can be used to show, hide, or toggle the show/hide state of the List Item Footer. The show/hide can optionally be done using animation.

Syntax:

<listObject>.rowExpander([rowNumber, [animationObject [,mode]]]);

 

Where:

 

Twitter - New functions have been added to make working with the Twitter API easier. Working with the Twitter API now requires that you use OAuth. The following two functions have been added:

 

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4

 

twitter_getBearerToken() Function - Gets a 'bearer token' from Twitter.

Syntax:

c bearerToken = twitter_getBearerToken(C client_id, C client_secret)

 

The client_id and client_secret must be obtained from Twitter. Go to dev.twitter.com and create an application. Once you have created an application, you can get the keys.

The bearerToken that is returned will allow you to make Twitter API calls.

Typically you will only need to get the bearerToken once in your application. You can then save it in a session variable for use throughout your application.

The source code for the twitter_getBearerToken() function might be of interest to some developers, and is shown below:

 

 

function twitter_getBearerToken as c ( client_id as c , client_secret as c )
'DESCRIPTION:Uses OAuth 2.0 to get a bearer token from Twitter.
'LIMITATIONS:X
dim bl as b = client_id+":"+client_secret
dim cf_1 as extension::CurlFile
dim flag_1 as l
dim slist1[2] as c
slist1[1] = "Authorization: Basic "+base64encode(bl)
slist1[2] = "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
dim ce as extension::Curl
ce = extension::Curl.Init()
ce.setOpt("URL","https://api.twitter.com/oauth2/token?grant_type=client_credentials")
ce.setOpt("NOPROGRESS",1)
ce.setOpt("USERAGENT","curl/7.34.0")
ce.setOpt("HTTPHEADER",slist1)
ce.setOpt("MAXREDIRS",50)
ce.setOpt("CAINFO",a5.Get_Exe_Path()+"\caroot\ca-cert.pem")
ce.setOpt("CAPATH",a5.Get_Exe_Path()+"\caroot")
ce.setOpt("CUSTOMREQUEST","POST")
ce.setOpt("TCP_KEEPALIVE",1)
ce.SetOpt("FILE",cf_1)
flag_1 = ce.Exec()
if flag_1 then
dim result as p = json_parse(cf_1.GetContent())
twitter_getBearerToken = result.access_token
end if
ce.close()
end function

 

 

twitter_clientApiCall() Function - Allows you to call a REST API function in Twitter.

Syntax

C result = twitter_clientApiCall( c bearerToken, c request)

 

The bearerToken must have previously been obtained using the twitter_getBearerToken() function.

 

Example:

The following Interactive window session shows how you can get 10 tweets for 'London'

 

dim bt as c = getBearerToken("YourUserKeyHere","YourUserSecretHere")
dim url as c
url = "/search/tweets.json?q=london&count=10&lang=en&type=recent"
json = twitterClientApiCall(bt,url)
'make the JSON 'pretty'
json = json_reformat(json,.t.)
json = convert_utf8_to_acp(json)
showvar(json)
 

This example gets a user time line

 

 

dim bt as c = getBearerToken("YourUserKeyHere","YourUserSecretHere")
dim url as c
url = "/statuses/user_timeline.json?count=100&screen_name=twitterapi"
json = twitterClientApiCall(bt,url)
'make the JSON 'pretty'
json = json_reformat(json,.t.)
json = convert_utf8_to_acp(json)
showvar(json)
 

 

The source code for the twitter_clientApiCall() function might be of interest to some developers, and is shown below:

 

function twitter_clientApiCall as c ( bearerToken as c , request as c )
'DESCRIPTION:Make a REST call to the Twitter API using a bearerToken that was obtained using the twitter_getBearerToken() function
'LIMITATIONS:X
dim slist1[1] as c
slist1[1] = "Authorization: Bearer "+bearerToken
dim cf_1 as extension::CurlFile
ce = extension::Curl.Init()
ce.setOpt("URL","https://api.twitter.com/1.1"+request)
ce.setOpt("NOPROGRESS",1)
ce.setOpt("USERAGENT","curl/7.34.0")
ce.setOpt("HTTPHEADER",slist1)
ce.setOpt("MAXREDIRS",50)
ce.setOpt("CAINFO",a5.Get_Exe_Path()+"\caroot\ca-cert.pem")
ce.setOpt("CAPATH",a5.Get_Exe_Path()+"\caroot")
ce.setOpt("TCP_KEEPALIVE",1)
ce.SetOpt("FILE",cf_1)
flag_1 = ce.Exec()
if flag_1 then
twitter_clientApiCall = cf_1.GetContent()
end if
ce.close()
end function
 

 

UX and Grid Component - Tab/Accordion Control - onLeave and onBeforeLeave Events - Two new events have been added to the Tab and Accordion Control. The events can be defined at the control level or at the individual pane level.

Report Server - Logging - A new logging feature has been added for the Report Server. The report server log is turned on automatically when the logging is active on the server, which turns on the access and error logs. With these logs on, be sure to set the logging to rotate on size and daily to keep the files sizes under control and easier to manage.

The report Server log data will look like this

 



[Fri Jul 11 06:58:34 2014] StartRpt bb8f711ef8a8487f87a528b315827120 C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf


[Fri Jul 11 06:58:35 2014] Finished bb8f711ef8a8487f87a528b315827120 C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf
 

 

Value Description
[Fri Jul 11 06:58:34 2014] Date and time of the action
StartRpt The action, which will be "StartRpt", "Finished ", or "RptError" if no error was reported, but the report was not created.
bb8f711ef8a8487f87a528b315827120 A unique identifier that is assigned to each report at build time
C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt The report definition requested
C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf
 
The physical file created - often a temp file as shown here
 


 

By matching the identifier, the time to build a report can be calculated from the timestamp. This can help identify reports that are slow to build.

If a report has a start action, but no finished or error action, that would indicate the report server has not finished the report.

If the action is "RptError", this error may be noted in the Xbasic error log and a special mini-dump file created in the Xbasic log folder. This mini-dump file will have a name syntax similar to "A5ReportServer_20140710115412520.a5dmp" This file can be used by Alpha Software to evaluate the report properties of a failed report.

 

UX Component - List - Client-side Events - New events have been added.

 

 

Xbasic - MongoDB - NoSQL document databases are becoming popular for certain types of applications. A new MongoDB class has been added to Xbasic to make it easy to query, update and manage a MongoDB database from Xbasic.

Click here for information.

Technical Note: The Xbasic mongo class it built on top of the MongoDB node.js driver.

 

Xbasic - CouchDB - You can  now query, update and manage a CouchDB NoSQL database from Xbasic.

Click here for information.

 

 

Performance Improvements in Following Functions  and Methods - Major performance improvements in

Web Applications - Security Framework - Active Directory - The Security Framework for Web Applications now supports Active Directory. That means you can authenticate a user using an Active Directory server.

Click here for information.

 

UX, Grid, TabbedUI and PageLayout Components - Working Preview - Chrome - When you use Working Preview you now have the option of using either Internet Explorer, or Chrome. Previously, Working Preview automatically used Internet Explorer.

The benefits of using Chrome for Working Preview include:

 

Watch Video - Part 1
Watch Video - Part 2

 

 

The Working Preview window now has new hyperlinks at the bottom of the screen.

When Internet Explorer is being used, the menu looks like this:

 

Clicking on the Internet Explorer hyperlink will bring up a dialog that will allow you to change to Chrome. Your choice is stored as part of the component definition. You can choose to use Internet Explorer for some components and Chrome for others.

 

When Chrome is used for Working Preview, the menu has more options.

The 'Detach Working Preview Window' is particularly useful because it creates a separate, detached window for Working Preview. This window can be moved to a second monitor and be left open while you return to the Design pane to continue editing your component.

You can set the Detached Working Preview window to update immediately every time a property is changed.

NOTE: For very large components, setting the Detached Working Preview to automatically update is not recommended as the delay in updating the Working Preview window will make setting properties seem sluggish.

 

 

Debugging Javascript Using the Chrome Debugger

 

To use the Chrome Javascript debugger, you must insert the

debugger;

command into the Javascript that you want to debug.

You must also, click the 'Open Chrome Debugger' hyperlink before you execute the code you want to debug. This will open the Chrome Debugger in a background window.

You can then invoke the code that you want to debug. When the debugger; command is hit, the Javascript will pause and the Working Preview screen will show:

 

 

You can then click the 'Open Chrome Debugger' hyperlink again, and it will bring the Chrome Debugger window to the forefront:

 

 

 

 

UX Component - List Control - New Methods - New method have been added to the List control that fire when the data in the list are changed. The methods are:

 

The events fire when the .populate(), updateRow(), appendRows() and removeRows() methods are called.

If the 'before' events return false, the corresponding action does not occur.

 

 

UX Component - Mobile Simulator - Now includes iPhone5 option in dropdownbox to select simulator size.

UX Component - Action Javascript - Wait Message - Auto Close After Setting - You now have control over how long to wait before the wait message is closed. By default, the setting is 5000 milliseconds.

 

email_send_mandrill() function - Sender Name Alias - Support for specifying an alias for the sender name has been added. The dot variable that is passed into the email_send_mandrill() function can now have a .from_name property.

For example:

ms.from_name = "Sales at Alpha" 'friendly name - optional

 

Here is a complete example

'create a .dot variable to define the message

dim ms as p
ms.send_to = "john@acme.com:John Smith,sally@acme.com:Sally Jones"
ms.from_email = "sales@alpha.com"

ms.from_name = "Sales at Alpha" 'friendly name - optional

ms.subject = "Information You Requested"
ms.message_html = "Here is the <b>information</b> you requested."
dim pResult as p

pResult = email_send_mandrill("mysecretkey",ms)

 

UX Component - List Control - .scrollToClosestValue() Method - Scrolls to the closest record in the List.

Syntax:

<listObject}.scrollToClosestValue(value [, flagCaseInsensitive [, position [, animationObject]]])

 

Where

Example:

Scroll the List so that the first Customer with a Lastname starting with 'M' is shown at the top of the List

var lObj = {dialog.object}.getControl('list1');

lObj.scrollToClosestValue('m',true,top,{allow: true, duration: 200})

 

 

UX Component - List Control - Tabular Layout - Sorting Columns - Custom Javascript - When a user clicks on a column heading in a List to sort the data on that column, you can specify if the sort should take place client-side or server-side (only appropriate if the List is based on a SQL or DBF data source). Now, a new option has been added to the list of choices. The 'Javascript' option allow you to specify your own Javascript code to execute.

 

UX Component - Repeating Sections - Set Active Row - setRepeatingSectionActiveLogicalRow() Method - A new method is now available for setting the active row in a Repeating Section.

{dialog.object}.setRepeatingSectionActiveLogicalRow(sectionName,logicalRowNumber)

 

The logical row number of a row in a Repeating Section and its physical row number are the same, unless rows have been deleted from the Repeating Section. When a row is deleted from a Repeating Section it is not really deleted, it is only hidden.

So, for example, assume that a Repeating Section had 5 rows to start with and then the first three rows were deleted. There would now be two visible rows, (logical row number 1 and 2), but the physical row numbers for these two rows would be 4 and 5. In order to set focus to the last visible row in the Repeating Section (logical row 2, but physical row 5) you can now use the new .setRepeatingSectionActiveLogicalRow() method.

This is more convenient than having to first call the ._repeatingSectionLogicalToPhysicalRow() to convert the logical row number to a physical row number, and then calling the .setRepeatingSectionActiveRow() method.

UX Component - List Control - .getVisible() Method - Returns an object with two properties 'start' and 'end' which contain the zero based row numbers of the rows in the List that are currently visible.

var lObj = {dialog.object}.getControl('list1');
var obj = lObj.getVisible();
alert(obj.start + ' to ' + obj.end);
 

 

UX Component - List Control - onNavigate Event - The onNavigate event fires when the List has been scrolled. The e object passed into the event handler has two properties:

UX Component - Hide/Show Controls - .setControlDisplay() Method -  A new method is exposed that can be used to show/hide controls. The method will hide/show the control and also its label (if the control has a label).

{dialog.object}.setControlDisplay(name, flag [, mode [, animatationJSON]])

 

The animJSON object has two properties:

 

NOTE: If you specify animation, you must load jQuery. To load jQuery, go to the Web Project Properties dialog and turn jQuery on.

Example:

{dialog.object}j.setControlDisplay('FRAME_1',false,'d',{type: 'fade',duration: 3000});

 

 

UX Component - Validation - Show/Hide Expressions - If a control has been hidden by a client-side show hide expression, the control is no longer validated.

 

 

AppLauncher Component - Browser Flags - A new option allows the query string that loads the target component to suppress the browser flags from showing in the query string. Instead, the browser flags are stored in a session variable called session.__browserFlags.

 

 

UX Component - List Control - .scrollToItem() method - This method now has new options that allow you to control where the target row will be in the List. Previously, the List was scrolled so that the target row became visible. But you could not control whether the target row was positioned at the top, or bottom of the List.

Now, you can pass in an optional object to the method with settings. For example:

 

var listObj = {dialog.object}.getControl('list1');

listObj.scrollToItem(50,{mode: 'top' ,animation: {allow: true, duration: 200},offset: {x: 0,y: 0}});
 

 

Options for 'mode' are: top, bottom, in-view

The offset settings control the number of pixels at the top or bottom of the list between the List edge and the scrolled to row.

 

UX Component - ButtonList Control - Static JSON - A new option has been added to populate a ButtonList control. The Static JSON option allows you to enter some static data in JSON format as the data source for the ButtonList.

UX Component - List Control - Get List Row Number from Element Method  - A new method of the List control allows you to get the List row number (zero based) from an element in the row.

For example, assume that you have a List with a freeform layout and a button in the freeform Layout with this code:

 

<button onclick="getRow(this);">What Row Am I On</button>

 

The getRow() function would be defined as:

 

function getRow(ele) {

    //get a pointer to the list - assume list is called 'LIST1'

    var lObj = {dialog.object}.getControl('LIST1');

 

    //get the row index by calling the .indexFromElement() method.

    //'ele' is a pointer to the button in the List row.

    var index = lObj.indexFromElement(ele);

}

 

 

 

PhoneGap Builder - Now uses a token based authentication feature so that once you have successfully logged into the PhoneGap build service, all further interaction with the PhoneGap build service is done using the token (until the token expires - currently set for 24 hours after login). The benefit of this approach is that interacting with the PhoneGap build service is faster as we no longer need to authenticate each time.

UX Component - List Control - Javascript Function Datasource - If a List control specifies a Javascript function as its data source, when the .refreshListMethod() is called an Ajax callback is no longer fired (as it was meaningless). Instead, the function that populates the list is called and the List is repopulated with the function results.

UX and Grid Component - Edit-combo and Auto-suggest Control - The height property was not being honored if it was set to a value that included the 'max' keyword.

 

UX Component - Testing if the Alpha Anywhere Server is Available - The UX component now supports a new method, .serverIsAvailable() that tests if the Alpha Anywhere server is available. This is a more comprehensive test than simply testing if an Internet connection is available.

 

NOTE: Contrast this method with the UX component's ._getOnlineStatus() method. This method merely tests if there is an internet connection. It does not make an ajax callback to the Alpha Anywhere server. Is merely uses the HTML5 navigator.online property. The .serverIsAvailable() method, on the other hand, does a lightweight callback to the Alpha Anywhere server to test if the server is available.

 

The syntax for the .serverIsAvailable() method is:

{dialog.object}.serverIsAvailable( [timeOut [, successFunction [, errorFunction]]);

 

If you don't specify a timeOut, the default value is 300 milliseconds.

The 'successFunction' parameter allows you to pass in an Javascript function to be called once it is determined that the Alpha Anywhere server is available.

The 'errorFunction' parameter is called if the server is not available.

The function will set these variables in the global A5 Javascript object:

_serverAvailable - true/false

_serverCheckTime - the time the server availability was last checked.

 

Example:

Execute the 'refreshList' action is the server is available.

function success() {

    {dialog.object}.playAction('refreshList');

}

 

{dialog.object}.serverIsAvailable(300,success);

 

 

Grid and UX Component - Search - QBE Syntax - Combining Multiple Wildcard Searches with AND -  If your search style is set to 'Exact match' and you enter search criteria that use wildcards, and you have QBE syntax turned on, then you can enter search criteria in the following form:

%string1%,%string2%

This will be interpreted as a search for any record that contains either string1 or string2 in the field.

However, you may want to find records that contain string1 AND string2. You can now do this using the && operator in your search definition, rather than the comma.

 

Application Server - The Application Server now uses an updated default SSL cipher list to enhance the security of SSL-enabled servers. The new cipher list is based on https://wiki.mozilla.org/Security/Server_Side_TLS


 

Bugs

UX Component - List Control - Frame - Modern - Show/Hide - If a List control was in a Frame container and the frame was defined as a modern frame that could be shown/hidden and if the initial state of the frame was hidden, the List controls in the Frame did not render properly when the frame was shown.

UX and Grid Components - Pop-up Modal Windows - Resizing - In some cases, when resizing a modal pop-up window, the window content would not redisplay properly after you stopped resizing the window.

Application Server - SSL - Test Certificates - Firefox - Certificate extensions are no longer generated into self-signed certificates when using the Application or Development Server Settings dialog to generate a self-signed certificate or calling directly from INET::SSLContext::CreateTestCertificate(). Version 31 of Firefox no longer accepts deprecated certificate extensions and this change corrects that problem.

IMPORTANT: You will have to regenerate your self-signed certificate.

UX Component - Map Control - onZoom Event - This event was not firing.

UX and Grid Component - Working Preview - Chrome - Memory Leaks - When using Chrome for Working Preview while building UX and Grids components there is a small memory leak that forces you to have to restart Alpha Anywhere occasionally. A number of these memory leaks have been fixed.

NOTE: This comment does NOT apply to the Application Server - it is only for the Development version.

UX Component - Logical Checkbox - Client-side Show/Hide - If you have defined a text label for the control, the text label was not being hidden when the control itself was hidden.

HTML Layout Reports - A number of minor bugs have been fixed. For example, scrolling HTML Layout reports in a mobile application when the report was shown in a pop-up window did not work the second time the report was opened.

Grid Component - File Upload - User Defined Action - Working Preview - Using this action in Working Preview had previously been supported, but got broken in a recent update. This is now working again.

UX Component - Tab Controls - Embedded Components - Server-side Show/Hide or Security - If a server-side show/hide expression or security group setting removed an embedded component from a tab pane at run-time, a Javascript error would occur.

UX Component - Panel Header/Footer - Container Height - The container height property was honored for a Panel Header or Footer.

Grid Component - Edit Row on Demand - afterRowSwitchFromEditable Client-side event - This event was not firing if the row you were editing was implicitly set to not-editable mode because the user clicked to edit another row and the Grid was set to edit one row at a time.

UX and Grid Component - Javascript Actions - Fixes a recently introduced bug where a Javascript Action that used Action Javascript to open a child component in a div on the parent component failed.

Report Editor - Layout Table Reports - Static HTML Cells - Now honor the font and alignment properties applied at the cell level.

Report Editor - Layout Table Reports - Row size to fit - Now works when row contains static HTML content.

UX Component - List Control - Client Side Summary - Client Side Filtering - Fixed an issue where the client-side summary values were not recalculated if a client-side filter was applied to the List.

UX Component - List Control - Client Side Summary - Fixed an issue where the items in the csSummary object were not upper case, as documented. Also, the count summary value was only being computed if the data in the field was numeric.

UX Component - Lookup Columns - Columnar Layout -  If there was no matching row in the lookup List, the data in the List would be misaligned in the List columns.

Grid and UX Component - Lookup Grids - Dynamic Filter - If a Lookup Grid had a dynamic filter, the filter was being applied as a 'user filter' rather than as a 'base filter'. This meant that if the user clicked the 'Clear Search' button on the Lookup Grid, the dynamic filter was removed.

Grid and UX Component - Javascript Actions - Fixed an issue that could have resulted in the .playAction() method invoking the wrong action.

UX Component - Slider - Date Values - Two Value Mode - When a two value slider was configured to show date values, the dates were off by when when you set the value on the date start/end.

Reports - Named Datasources - Fixed a recently introduced issue with reports that use named data sources (not to be confused with named connection strings which do not have any issues).

UX and Grid Components - Client-side Expressions - Date Fields - Client side expressions (for example, show/hide, enable and calculated fields) that are based on controls whose data type is set to 'Date' or 'Time' now treat the controls as true Javascript date objected.

For example, say you had a UX with two input controls (called say 'DATE1' and 'DATE2') and a button. Say you defined as show/hide expression for the button as follows:

DATE1 > DATE2

Assume that the client side date format was set to MM/dd/yyyy and that the values in the two controls were '04/20/2000' and '02/01/2000'.

Previously, this expression was evaluated as as string expression. So the string '04/20/2000' was compared to the string '02/01/2000'.

This might have led to the correct result in some circumstances, but would not have been correct in other circumstances. For example, say that the client side date format was set to dd/MM/yyyy. Now the two values for the date controls would be '20/04/2000' and '01/02/2000' and comparing these two values as strings would lead to a different result.

Now, the input controls are converted to real Javascript data objects (in other words, the date string values are automatically parsed using the setting for the client side date format) and the client-side expression is evaluated using true date values.

Previously, some uses might have implemented their own solution to this problem by defining a custom Javascript function to use in the show/hide expression. For example, the show/hide expression might have been specified as:

compareDates(DATE1,DATE2)

 

And the compareDates function would have been defined as:

 

function compareDates(d1,d2) {
    var _d1 = new Date();
    var _d2 = new Date();
    _d1.fromFormat(d1,'MM/dd/yyyy');
    _d2.fromFormat(d2,'MM/dd/yyyy');
    if(_d1 > _d2) return true;
    else return false;
}

 

If you had previously implemented this pattern, you will now get an error because the inputs to the compareDates() function (d1 and d2) are not date objects and not strings.

 

 

UX Component - List Control - Cascading Lists - DBF Tables - Allow Null Selection - If you had defined cascading List controls (i.e. a child List whose data depends on the selection in its parent List) and the List data source was .dbf tables, and the parent List was set to not allow a null selection, then when the UX initially rendered, the child List was not populated, as it should have been. The child List was only populated after the user clicked on a row in the parent List.

 

 

Tips

Edit-Combo, Auto-Suggest and List Controls - Web Applications - Touch Enabled Computers - Windows 8.* - If you are running a web application on a touch enabled computer under Windows 8.*, Edit-combo, Auto-suggest and List controls will not display a vertical scroll bar because the assumption is that the user will use touch gestures on the list to scroll the data.

This assumption is valid for a mobile application that does not support mouse interaction, but in a web application on a machine that does support mouse interaction, you would want to see a vertical scroll bar.

You can turn off drag scrolling (and thus cause the vertical scroll bar to appear), by executing the following Javascript code:

A5.u.drag.useDragScrolling = 'never';

 

If your application is running in a Tabbed UI, a good place to inject this code is in the Tabbed UI's 'Javascript to run on startup' property.

 

 

In the case of a Grid, you can use the onGridRenderComplete client-side event.

 

UX Component - Define Custom Watch Events - The client-side 'calculated fields', 'enable expression' and 'show/hide' expressions all generate watch expressions that automatically fire when the 'watched' variables change.

You can completely bypass these properties and instead define your own watch expressions.

For example, the following code can be placed on the client-side beforePrepare event to define a custom watch event that updates the value in 'TEXTBOX1' whenever the value in 'TEXTBOX2' changes.

 

 

{Dialog.Object}.dialogWatches['MY_WATCH_EVENT'] = {
    watch: ['TEXTBOX2'],
    variables: [],
    updateColumn: 'TEXTBOX1',
    onChange: function(data) {
        var dialog = {};
        var summary = {};
        {Dialog.Object}._getDialogVariables(dialog,summary,data);
        var txt2 = {dialog.object}.getValue('textbox2');
        {Dialog.Object}.setValue('TEXTBOX1',

            {dialog.object}._functions.myFunc2(txt2) );
    }
}
 

Using CSS Icon Images and Bitmap Images - A5.u.icon.html() Function - The Alpha Anywhere Javascript library contains a useful utility function that makes working with CSS Icon images and regular bitmap images easier.

The issue is somewhat complicated because the HTML markup to display a bitmap image uses the <img> tag, whereas the HTML markup for a CSS Icon image uses a <i> tag with special class names.

The A5.u.icon.html() function takes the name of the image you want to display and generates the appropriate HTML markup. It is also able to interpret the special syntax Alpha Anywhere uses to assign an in-line style to CSS Icons.

For example:

var icon1 = A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: blue;}');

will return the following HTML markup:

<i class="fa fa-align-center fa-2x " style=";color: blue;"></i>

and:

var icon2 = A5.u.icon.html('images/$$application.chrome.png.a5image');

will return this HTML markup:

<img src="images/$$application.chrome.png.a5image" />

 

UX Component - List Control - Using the Client-side Computed Columns Feature to Display Dynamic Images in a List - The Computed Columns property allows you to define computed (virtual) columns to display in a List. The computed columns can display dynamic images (i.e. images that are based on data in the current row). For example, you could define the following Computed Column:

 

data.DYNAMICIMAGE = function(data,index) {
    if(data.State == 'MA') {
        return A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: #f6b5b5;}');
    }
    else if(data.State == 'CA') {
        return A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: blue;}');
    }
    else if(data.State == 'NY') {
        return A5.u.icon.html('images/$$application.chrome.png.a5image');
    }
    else return 'Not Defined';
    }(data,index);

 

 

 

UX and Grid Component - Sending E-mail From the Client Using Mandrill - Alpha Anywhere has well documented methods for sending email from a web component. These method are all server-side method. An Ajax callback is made to the server and the e-mail is sent from the server. However, it is possible to send an e-mail directly from the client without involving the Alpha Anywhere server at all using the Mandrill Mail service.

The technique discussed here uses the XMLHttpRequest object to make a REST call to Mandrill.

 

function sendMailData() {
    //data for the message
    var url = "https://mandrillapp.com/api/1.0/messages/send.json"
    var json = {
    "key": "Your Mandrill key here",
    "message": {
    "to": [
        {
            "email": "test@gmail.com"
        }
    ],
    "from_email": "customerservice@gmail.com.com",
    "subject": "Message Subject",
    "html": "Message text here",
    "text": "Text form of message",
    "preserve_recipients": false
    },
    "asynch": false,
    "ip_pool": null,
    "send_at": null
    }
    var obj = {};
    obj.url = url;
    obj.json = json;
    return obj;
}

function sendMail() {
    var obj = sendMailData();
    var _url = obj.url
    var params = JSON.stringify(obj.json);
    var _xhr = new XMLHttpRequest();
    _xhr.open('POST',_url,true);
    _xhr.timeout = 5000;
    _xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    _xhr.setRequestHeader("Connection", "close");

    _xhr.ontimeout = function(e) {

        alert('error - timeout');
    }

    _xhr.onload = function(e) {

        if(this.status == 200) {

            alert('sent');

        } else {

            alert('failed')

        }
    }
    _xhr.send(params);

}
 

UX Component - Drag Scrollable Elements (including Lists) - Dynamically Turning Scrolling On/Off - You can dynamically turn scrolling on/off on certain elements, including List controls.

The basic steps are:

1. Get a pointer to the element

2. Call this code:

A5.u.drag.setDisabled(element,dragType,value)

 

 

For example:

//get a pointer to the List obj

var lObj = {dialog.object}.getControl('mylist');

//get a pointer to the scrollable part of the List

var ele = $(lObj.contId+ '.CONTENTWRAPPER');

//disable scrolling

A5.u.drag.setDisabled(ele,'scroll',true);

//now enable scrolling

A5.u.drag.setDisabled(ele,'scroll',false);

 

The dragType parameter can be 'scroll' or 'custom'. 'Custom' is used for 'drag' actions that are not 'scroll' actions. For example, a Carousel uses a custom drag, not a 'scrolling' drag.

 

 

Basic Authentication - How to Create an .A5W Page that Requires Basic Authentication - Basic Authentication is a simple HTTP form of authentication.

As defined in Wikipedia:

HTTP Basic authentication (BA) implementation is the simplest technique for enforcing access controls to web resources because it doesn't require cookies, session identifier and login pages. Rather, HTTP Basic authentication uses static, standard HTTP headers which means that no handshakes have to be done in anticipation.

If you create simple web services in Alpha Anywhere, you might want to use basic authentication on the .a5w page that implements your web service.

In the example page below, basic authentication is used. In this trivial example, the only user Id/password combination that is valid is Alpha/Anywhere. However, the example could easily be extended to do a database lookup to authenticate the user.

When this page is called (by some other program that is trying to consume the web service implemented by this page), it is assumed that the headers will have been set to supply the user id and password.

If you try to call this page from a browser, the browser will prompt for a user id and password

 

<%a5
if ("Authorization: Basic " $ Request.Headers)

    'extract the 'Authorization' from the request header
    dim EncodedUserAndPass as c = filter_string(Request.Headers,"Authorization: Basic ", crlf())
    EncodedUserAndPass = word(EncodedUserAndPass,2,": Basic")
    EncodedUserAndPass = alltrim(EncodedUserAndPass)
 

    'the authorization is base64 encoded. decode it.

    dim DecodedUserAndPass as b = base64decode(EncodedUserAndPass)
 

    'extract the username and password

    dim Username as c = word(DecodedUserAndPass, 1,":")
    dim Password as c = word(DecodedUserAndPass, 2, ":")
 

   

    'here is where you could do a database lookup to authorize the user

    if (Username = "Alpha" .and. Password = "Anywhere")
        ? "Authorized as " + Username

        'this is where you would implement the web service.

        'at this point, the user has been authorized.

        'for example, you might respond with some JSON data

        'e.g. data = "{name: 'alpha', city: 'Boston'}"

        '?data

       
    else
        ?"Bad username or password"

        'if you want to present the user with another change to log in, uncomment this

        'Response.StatusCode = "401"
        'Response.StatusDescription = "Not Authorized"
        'Response.Headers.Add("WWW-Authenticate", "Basic")
    end if
else
    Response.StatusCode = "401"
    Response.StatusDescription = "Not Authorized"
    Response.Headers.Add("WWW-Authenticate", "Basic")
end if
%>

 

 

UX and Grid Component - Edit-Combo - Dynamically Repopulate Choices - When you define an Edit-Combo control, the builder allows you to specify that the choices shown in the edit-combo should be computed at render time, or dynamically, by making an Ajax callback every time you open the edit-combo.

If you choose the option to populate the edit combo at render time, you might still want to programmatically change the choices in the edit combo.

Here is the Javascript showing how it can be done:

 

//get a pointer to the edit-combo for 'TEXTBOX1'

obj = DLG1_DlgObj.fieldHelpers['TEXTBOX1'];

//define the new date for the edit-combo
var _d = ['Red','Green','Blue','Orange'];

//call the .setData() method to repopulate the edit-combo
obj.setData(_d);
 

If you want to generate the new choices for the edit-combo by making an Ajax callback to the server, here is how the Xbasic function that handles the callback might be written:

 

 

This example is where the edit-combo shows a single column of data.

function xb_refreshData as c (e as p)
    dim cn as sql::Connection

    cn.open("::Name::northwind")

    sql = "select customerid from customers where country = 'uk'"

    cn.Execute(sql)

    rs = cn.ResultSet

    dim txt as c

    txt = rs.ToString()

    dim data as c

    data = js_list_to_array(txt)

    dim js as c

    js = "var obj = {dialog.object}.fieldHelpers['TEXTBOX1']; "

    js = js + "var _d = " + data + ";"

    js = js + "obj.setData(_d);"

    xb_refreshData = js

end function

 

 

 

This example is where the edit-combo shows a multiple columns of data.

 

 

function xb_refreshData as c (e as p)
    dim cn as sql::Connection

    cn.open("::Name::northwind")

    'note that we alias the columns in the SQL statement with field names

    'that are capitalized. this is because Javascript is case-sensitive and the

    'property names in the JSON data that is used to populate the edit-combo

    'are all capitalized. the column aliases will be uses for the property names

    'when the .ToJSONObjectSyntax() method is called.

    sql = "select customerid as [CUSTOMERID], contactname as [CONTACTNAME] from customers where country =  'uk'"

    cn.Execute(sql)

    rs = cn.ResultSet

    dim txt as c

    txt = rs.ToJSONObjectSyntax()

    dim data as c

    data = "[" + stritran(alltrim(txt),crlf(),"," + crlf()) + "]"

    dim js as c

    js = "var obj = {dialog.object}.fieldHelpers['TEXTBOX1']; "

    js = js + "var _d = " + data + ";"

    js = js + "obj.setData(_d);"

    xb_refreshData = js

end function


 

 

 

 

 

UX and Grid Controls - Button Icons and Text - Setting Dynamically - In the case of 'advanced' buttons (all buttons in a UX are, by default 'advanced' buttons and 'Action Buttons' in a Grid are 'advanced' buttons), you can dynamically set the button icon, or button text by setting properties in the underlying button object, then refreshing the button object.

For example:

var bc = {dialog.object}.getControl('MYBUTTON1');
bc.icon = 'cssIcon=FontAwsomeIconHere'; 

// optionally you can also set 'hoverIcon', 'pressedIcon', and 'disabledIcon'
bc.refresh();



 

 

UX Component - List Control - Cascading Lists - Delay Render - The UX component makes it very easy to create cascading Lists. For example, say you have 3 Lists:

You can easily configure the orders List to specify that the customer List is its parent List and the orderDetails List to specify that the orders List is its parent.

If you specify that a List has a parent, then when you click on a row in the parent List, ajax callbacks are automatically made to refresh the child Lists.

Now, assume that each List is placed in its own PanelCard and the PanelCards are wrapped in a PanelNavigtor. Further assume that for each List you have checked the 'Delay render till visible' property.

The desired behavior is that when the UX is initially rendered, ONLY the customer List is rendered. Then when the user clicks on a row in the customer List, a single ajax callback is made to populate the order List and the PanelCard that contains the orders List gets focus.

Next, when the user clicks on a row in the orders list, again a single ajax callback is made to populate the orderDetails list and the PanelCard containing OrderDetails gets focus.

However, if you set up your UX as described above, when you click on a row in the customer List, you will notice that there are two ajax callbacks and that the orders List is refreshed twice - not once as desired. The first ajax callback occurs because the customer List automatically refreshes all of its child Lists when the user selects a row in the List. The second callback occurs because the PanelCard that contains the orders List gets focus and the orders List was configured to render when it becomes visible.

To solve this problem here is how the setup of the UX component must be changed.

So, for example, in the onSelect event for List1 (the customer List), the following code is executed:


var l = {dialog.object}.getControl('list2');
l._hasBeenRendered = false;
var l = {dialog.object}.getControl('list3');
l._hasBeenRendered = false;
{dialog.object}.panelSetActive('PANELCARD_2');

 

This event sets the ._hasBeenRendered property for list2 and list3 to false, and then gives focus to PANELCARD_2. When PANELCARD_2 gets focus, list2 is rendered (an ajax callback is made). This is the only callback that is made. Because the orders List (list2) no longer has its 'Has Parent List' property set, no callback triggered by simply clicking on a row in the customer list.

 

Similarly, the onSelect event for List2 (the orders List), the following code is executed:

var l = {dialog.object}.getControl('list3');
l._hasBeenRendered = false;
{dialog.object}.panelSetActive('PANELCARD_3');

 

 

 

The sample component which uses Northwind demonstrates the concepts discussed in this topic.

 

 

UX Component - List Control - Sort Icon Position - By default, when you sort the data in a List column, the sort icon shows to the right of the Column heading. If you are working with a RTL language, such as Arabic or Hebrew, you might want the sort icon on the left of the column heading (as shown below):

 

Download Component

 

 

This is easily done by customizing the component style. You can either make a change to the style sheet (which will affect all of your components). Or you can make a local change to affect just the UX that you are designing.

To define the changes so that they are local to the current component, edit the 'Local sub-theme definition' as shown below:

 

 

Edit the Javascript as shown below.

You can start by clicking the 'Show style.js file for current style' hyperlink. The search for 'listbox'. Copy the JSON to the clipboard and paste into the editor. You will need to wrap the pasted text in opening and closing curly brackets as shown in the image. The make the edit shown in yellow highlight below.

 

You will also need to make this change to the CSS:

 

Of course, if you are not using iOS7, but some other style, you will need to use the appropriate style names.

 

 

 

 

UX Component - Tree Control - How to Save and Restore the Open/Close State of Tree Nodes - Consider a UX that has a tree control with multiple levels of nested branches. Assume that the user has carefully navigated in the tree, opening some branches, while leaving others closed. The user would then like to save the 'state' of the tree so that at a future time, they can easily restore the state of the tree to its current state.

This is easily done with some simple Javascript that captures and restores the state. Below are two function. The first captures the tree state and stores it in a variable in the Dialog object. The second restores the tree state.

 

function getstate() {

    //get a pointer to the tree control
    var t = {dialog.object}.getControl('tree1');

   

    //get the tree data and stringify it.
    var js = JSON.stringify(t.data);

 

    //store in a variable in a dialog object
    {dialog.object}.treeData = js;

}

function setstate() {
 

    //get a pointer to the tree
    var t = {dialog.object}.getControl('tree1');
 

    //get the stored data. parse it into an object

    var d = JSON.parse({dialog.object}.treeData);
 

    //reopulate the tree
    t.populate(d);

}

 

 

UX Component - Map Control - List Control - Add Markers to Map Using Data From List - Assume you have a List control with multiple records. Each record has a lat/lng value. You would like to add a marker to the map for each row in the List. You can certainly do this by using a built-in action in Action Javascript to 'Add multiple markers to a map'. However, the Action Javascript action involves making an Ajax callback.

Since the List already has lat/lng data for all of the markers you want to add to the map, it would be nice to be able to add the markers to the map without having to do an Ajax callback.

 

Here is a working example.

 

To do this, add a button to the List that calls the addMarkers() function.

Here is the definition of the addMarkers() function

 

function addMarkers()  { 

    //get a pointer to the list
    var lObj = {dialog.object}.getControl('list');

    //get the list data
    var _d = lObj._data;

 

    //get a pointer to the map control
    var m1Obj = {dialog.object}.getControl('map1');
    m1Obj.removeMarkerGroup('GROUP1');
    var _dr = '';

 

    //loop through all of the rows in the list

    //reading the 'name', 'city', 'state', 'latitude' and 'longitude'

    //columns in the list.


    for (var i = 0; i < _d.length; i++) { 
        _dr = _d[i];
        delete _s;
        _s = {};
        _s.group = 'GROUP1'
        _s.title = _dr.name ;
        _s.detail = {};
        _s.detail.has = true;
        _s.detail.data = _dr.city + ' - ' + _dr.state;
        m1Obj.addMarker('MARKER_' + i,[Number(_dr.latitude),Number(_dr.longitude)],_s);
    }
    m1Obj.viewMarkerGroups('GROUP1');;
}
 

 

 

UX Component - Tabular Lists - Showing and Hiding Lists - When a columnar List is shown after initially having been hidden, the List will not render correctly until is has been explicitly refreshed. Here is how you can refresh a columnar List so that it displays correctly after having been shown:

var lObj = {dialog.object}.getControl('mylist');

lObj.refresh();

 

 

NOTE: This comment does not apply to free-form Lists. Free-form Lists do not need to be explicitly refreshed.

PhoneGap Application - iOS StatusBar - In iOS, it is common to have the status bar at the top of the screen (with time, Wifi, and battery information) display as an overlay of the app. For many designs this can be a problem. You might rather have the "old" style of having a separate status bar above the active area of the screen. You might also want to specify the color of the background of that bar (for example, to match or complement the top of your app) and text. PhoneGap gives you an optional "Status Bar" 3rd Party plug-in to customize the status bar on iOS.

See example code in next topic.


 

Android Back Button - In Android, users often expect the device's "Back" button to control the app. By default, in PhoneGap, this will just exit the app and go back to the previous app. If you have popup windows, or detail views, the users will expect (and their fingers will be trained) to dismiss pop-ups or go back up the view list. See "Navigation with Back and Up" on the Android Developers web site: http://developer.android.com/design/patterns/navigation.html


Here is some code that can be placed in your app (such as in the Javascript functions or the onRenderComplete Client-Side Event:
 

// PhoneGap start up and initialization

document.addEventListener('deviceready', function() { // PhoneGap started
    var platform = device.platform;
    switch (platform) {
        case "Android":

            // back    button support
            document.addEventListener('backbutton', handleBackButton, false);
            break;
        case "iOS":
            if (typeof StatusBar === 'undefined') break;

            // configure statusbar in iOS 7+
            StatusBar.overlaysWebView(false);

            // Light statusbar text color. Use StatusBar.styleDefault() for dark text.
            StatusBar.styleLightContent();
            StatusBar.backgroundColorByHexString("#3355AA"); // Hex RGB value, similar to CSS
            break;
    }

    }

);


function handleBackButton(e) { // Android back button event handler
    // Go through UI items in priority order to do "back" operation
    var winobj = {dialog.Object}.getWindow('INTROWINDOW'); // Is this window popped up?
    if (!winobj.hidden) {
        winobj.hide(); // no - hide and finish
    return;
    }

    winobj = {dialog.Object}.getWindow('SETTINGSPOPUP'); // another potential window
    if (!winobj.hidden) {
        winobj.hide();
        return;
    }

. . .

    var panel = {dialog.object}.panelGet('OVERALLLAYOUT'); // is a docked panel being shown?
    if (panel.state.dockPanelShown) {
        panel.hideDock(); // yes - hide it and finish
        return;
    }

    if (canGoBack()) { // do normal user-initiated "back" operation in app (like a browser)
        doBackForward(+1);
        return;
    }

    // nothing left - exit app
    e.preventDefault();
    navigator.app.exitApp();

}

 


Note that the "back" handling seems to work in Android 4.3, but may not work in earlier versions.

 

 

Xbasic Classes - Property Getter and Setter Functions - You can create special .get() and .set() functions to read and write property values in a class. For example, in the class below the 'foo' property of the class has a .get() and .set() function. These functions are automatically invoked when you try to set or get the value of the classes' .foo property.

 

 

define class mynamespace::mySampleClass
 

    dim _foo as c = "hello"
    function sampleMethod1 as v()
        ui_msg_box("sampleVar1",sampleVar1)
    end function

    function foo.get as c ()
        foo.get = _foo
    end function

    function foo.set as v (value as c )
        _foo = upper(value)
    end function
end class

 

 

Using this class:

 

dim x as mynamespace::mySampleClass

?x.foo

= "hello"

x.foo = "Goodbye"

?x.foo

= "GOODBYE"

 

 

Calling SOAP Web Services From Xbasic - This topic shows 'real world' examples of Xbasic code that call SOAP web services.


Examples are provided here for WorldPay (a credit card processing company), Kareo (a medical billing software company) and Norman G Jensen, Inc (a provider of freight brokerage services).


The source code is extensively commented and is intended as a learning vehicle to help you write code to call these and other similar SOAP web services.

 

WorldPay


WorldPay provides credit card processing as a web service. For more information go to http://www.worldpay.com/us.

The function below encapsulates the process of charging a credit card using the world pay service.

This example was provided by Max Hammond, who has extensive experience using Alpha Anywhere with SOAP web services.


FUNCTION WorldPay_ProcessCC AS CallResult (acctid AS C, ccname AS C, ccnum AS N, amount AS N, expmon AS N, expyear AS N )

dim Result as CallResult

on error goto errorWp_ProcessCC

dim webLink as c = "https://trans.worldpay.us/Web/services/TransactionService?wsdl"
dim assemblyFile as C = "C:\Program Files (x86)\a5V12\WorldPayService.DLL"
dim webEndpoint as c = "https://trans.worldpay.us/Web/services/TransactionService"

dim sv as DOTNET::Services
dim ay as DOTNET::AssemblyReference
ay.FileName = assemblyFile


' This extra call does the heavy lifting and registers the assembly DLL.
' If the assembly does not exist, create one.
if .not. File.Exists(ay.FileName)
    if .not. sv.GenerateWCFWebServiceClientFromURL(webLink, ay.FileName)
        Result = sv.CallResult
    end if
end if

' Load the assembly into the Alpha Anywhere type system.
if Result.Success
    if .not. sv.RegisterAssembly("WorldPay", ay)
        Result = sv.CallResult
    end if
end if

if Result.Error
    goto doneWp_ProcessCC
end if

' Set up HTTP Binding
' The binding object determines how we will communicate with the web service.
' This includes the underlying network transport, credentials
dim b as System::ServiceModel::BasicHttpBinding
b.MessageEncoding = System::ServiceModel::WSMessageEncoding::Text

' The settings below will depend on the service.
' We want sufficient capacity to retrieve very large nested structures.
' If you get an error that you have exceeded a size, make the adjustment here.
b.MaxReceivedMessageSize = 10485760
b.maxBufferSize = 10485760
b.MaxBufferPoolSize = 10485760
b.ReaderQuotas.maxDepth = 32
b.ReaderQuotas.MaxStringContentLength = 10485760
b.ReaderQuotas.MaxArrayLength = 16384
b.ReaderQuotas.MaxBytesPerRead = 4096
b.ReaderQuotas.maxNameTableCharCount = 16384

' Set up the security.
' In this case, we are using transport level security a UserName credential over SSL and will provide a user name credential.
b.Security.Mode = System::ServiceModel::SecurityMode::Transport
b.Security.transport.ClientCredentialType = System::ServiceModel::HttpClientCredentialType::None
b.Security.Transport.ProxyCredentialType = System::ServiceModel::HttpProxyCredentialType::None
b.Security.Transport.Realm = ""
b.Security.Message.ClientCredentialType = System::ServiceModel::BasicHttpMessageCredentialType::UserName
b.Security.Message.AlgorithmSuite = System::ServiceModel::Security::SecurityAlgorithmSuite::Default

' Create an endpoint. This is the address information needed to find the service on the web.
dim endpoint as system::ServiceModel::EndPointAddress = new System::ServiceModel::EndPointAddress(webEndpoint)

' Create Client for WorldPay Service using endpoint and bindings
dim Client as WorldPay::TransactionSOAPBindingImplClient = new WorldPay::TransactionSoapBindingImplClient(b, endpoint)

' Create Web Request using WorldPay Client
dim WebRequest as WorldPay::processCCSaleRequest
WebRequest.ccinfo = new WorldPay::CreditCardInfo()
WebRequest.ccinfo.acctid = acctid
WebRequest.ccinfo.ccname = ccname
WebRequest.ccinfo.ccnum = ccnum
WebRequest.ccinfo.amount = amount
WebRequest.ccinfo.expmon = expmon
WebRequest.ccinfo.expyear = expyear

' Make Web Service Call to WorldPay
dim WPResponse as p
WPResponse = Client.ProcessCCSale(WebRequest)


' End process in error or success
goto doneWp_ProcessCC

errorWp_ProcessCC:
on error goto 0
Result.Code = error_code_get()

doneWp_ProcessCC:
WorldPay_ProcessCC = Result

END FUNCTION

 

Kareo
Kareo Medical Billing Software provides a comprehensive web service to manage practices. For more information go to http://www.kareo.com.

The sample code below was provided by Max Hammond, who has implemented a product using Alpha Anywhere and Kareo.

The following functions are included:

 

 


FUNCTION GetAppointments as CallResult (WSDLWebLink as C, ServiceWebLink as C, AssemblyFile as C, CustomerKey as C, User as C, Password as C, ConnectionString as C, PracticeName as C)

on error goto errorGetAppointments ' To catch the dim of service objects
dim Result as CallResult

' This extra call does the heavy lifting and registers the assembly DLL
CreateService(WSDLWebLink, ServicePointWebLink, AssemblyFile)

dim RequestHeader as Kareo::www::Kareo::com::api::Schemas::RequestHeader

RequestHeader.CustomerKey = CustomerKey
RequestHeader.User = User
RequestHeader.Password = Password

dim AppointmentsRequest as kareo::www::kareo::com::api::schemas::GetAppointmentsReq
dim GetAppointmentsRequest as Kareo::GetAppointmentsRequest

AppointmentsRequest.RequestHeader = RequestHeader
GetAppointmentsRequest.request = AppointmentsRequest

dim Service as Kareo::KareoServicesClient = CreateService(WebLink, EndPointWebLink, AssemblyFile)

' Create the filter for the GetAppointments call
dim filter as Kareo::www::kareo::com::api::schemas::AppointmentFilter
filter.FromLastModifiedDate = date()-30
filter.ToLastModifiedDate = date() + 10
filter.PracticeName = PracticeName
AppointmentsRequest.Filter = filter

' Set the fields you want populated in the return by marking them as true
dim fields as Kareo::www::kareo::com::api::schemas::AppointmentFieldsToReturn
fields.AllDay = .t.
fields.AppointmentReason1 = .t.
fields.AppointmentReason10 = .t.
fields.AppointmentReason2 = .t.
fields.AppointmentReason3 = .t.
fields.AppointmentReason4 = .t.
fields.AppointmentReason5 = .t.
fields.AppointmentReason6 = .t.
fields.AppointmentReason7 = .t.
fields.AppointmentReason8 = .t.
fields.AppointmentReason9 = .t.
fields.AuthorizationEndDate = .t.
fields.AuthorizationID = .t.
fields.AuthorizationInsurancePlan = .t.
fields.AuthorizationNumber = .t.
fields.AuthorizationStartDate = .t.
fields.ConfirmationStatus = .t.
fields.CreatedDate = .t.
fields.EndDate = .t.
fields.ID = .t.
fields.LastModifiedDate = .t.
fields.Notes = .t.
fields.PatientCaseID = .t.
fields.PatientCaseName = .t.
fields.PatientCasePayerScenario = .t.
fields.PatientFullName = .t.
fields.PatientID = .t.
fields.PracticeID = .t.
fields.PracticeName = .t.
fields.Recurring = .t.
fields.ResourceName1 = .t.
fields.ResourceName10 = .t.
fields.ResourceName2 = .t.
fields.ResourceName3 = .t.
fields.ResourceName4 = .t.
fields.ResourceName5 = .t.
fields.ResourceName6 = .t.
fields.ResourceName7 = .t.
fields.ResourceName8 = .t.
fields.ResourceName9 = .t.
fields.ServiceLocationName = .t.
fields.StartDate = .t.
fields.Type = .t.

' Create the GetAppointmentsRequest object with the request information
dim Response as p

' Make the service call
Response = Service.GetAppointments(GetAppointmentsRequest)

' Get the appointment information out of the response.
AppointmentsResponse = Response.GetAppointmentsResult

if AppointmentsResponse.ErrorResponse.IsError
    Result.Code = -1
    Result.Text = AppointmentsResponse.ErrorResponse.ErrorMessage
elseif .not. AppointmentsResponse.SecurityResponse.SecurityResultSuccess
    Result.Code = -2
    Result.Text = AppointmentsResponse.SecurityResponse.SecurityResult.ToString()
else
    Result = LoadAppointments(AppointmentsResponse.Appointments, ConnectionString)
end if

Result.Code = error_code_get()
goto doneGetAppointments

errorGetAppointments:
on error goto 0

doneGetAppointments:
on error goto 0

GetAppointments = Result

END FUNCTION
 



The functions below make it easier to populate service requests.

 

 

FUNCTION CreateService as Kareo::KareoServicesClient(DefinitionWebLink as C, EndPointWebLink as C, AssemblyFile as C)
' Make sure the client proxy DLL is created and loaded and create a client proxy (an object we can make service calls on).

dim Result as CallResult = RegisterServiceDLL(DefinitionWebLink, AssemblyFile)

if .not. Result.Success
    error_generate(Result.Code)
end if

' Set up HTTP Binding
' The binding object determines how we will communicate with the web service.
' This includes the underlying network transport, credentials
dim b as system::ServiceModel::BasicHttpBinding

b.MessageEncoding = System::ServiceModel::WSMessageEncoding::Text

' The settings below will depend on the service.
' We want sufficient capacity to retrieve very large nested structures.
' If you get an error that you have exceeded a size, make the adjustment here.
b.MaxReceivedMessageSize = 20485760
b.maxBufferSize = 20485760
b.MaxBufferPoolSize = 10485760
b.ReaderQuotas.maxDepth = 32
b.ReaderQuotas.MaxStringContentLength = 10485760
b.ReaderQuotas.MaxArrayLength = 16384
b.ReaderQuotas.MaxBytesPerRead = 4096
b.ReaderQuotas.maxNameTableCharCount = 16384

' Set up the security.
' In this case, we are using transport level security a UserName credential over SSL and will provide a user name credential.
b.Security.Mode = System::ServiceModel::SecurityMode::Transport
b.Security.transport.ClientCredentialType = System::ServiceModel::HttpClientCredentialType::None
b.Security.Transport.proxyCredentialType = System::ServiceModel::HttpProxyCredentialType::None
b.Security.Transport.Realm = ""
b.Security.Message.ClientCredentialType = System::ServiceModel::BasicHttpMessageCredentialType::UserName
b.Security.Message.AlgorithmSuite = System::ServiceModel::Security::SecurityAlgorithmSuite::Default

' Create an end point object to represent the address of the server.
dim e as system::ServiceModel::EndPointAddress = new System::ServiceModel::EndPointAddress(EndPointWebLink)

' Create the service object using the binding and the endpoint
dim MyService as Kareo::KareoServicesClient = new Kareo::KareoServicesClient(b, e)

' There are some quotas that are harder to set.
' This utility function will take care of this in one place.
SetSvcGraphObjectQuota(MyService)

CreateService = MyService
END FUNCTION


FUNCTION RegisterServiceDLL as CallResult (WebLink as C, AssemblyFile as C)
' This function retrieves the Web Service Definition Language (WSDL) XML file and generates a local .NET proxy.
' The proxy assembly is registered in Alpha Anywhere as a namespace (set of types) and can be used
' as any other .NET type to make web service calls.

on error goto errorRegisterServiceDLL
dim Result as CallResult
dim sv as dotnet::Services
dim Assembly as dotnet::AssemblyReference

'Create Web Service Client and Register
Assembly.FileName = AssemblyFile

if .not. File.Exists(AssemblyFile)
    if .not. sv.GenerateWCFWebServiceClientFromURL(WebLink, AssemblyFile)
        Result = sv.CallResult
    end if
end if

if Result.Success
    if .not. sv.RegisterAssembly("Kareo", Assembly)
        Result = sv.CallResult
    end if
end if

goto doneRegisterServiceDLL

errorRegisterServiceDLL:
on error goto 0
Result.Code = error_code_get()

doneRegisterServiceDLL:
on error goto 0

RegisterServiceDLL = Result

END FUNCTION



FUNCTION SetSvcGraphObjectQuota as CallResult (Service as P)
' This utility function sets the maximum number of objects in the serializer.
' The serializer packages and unpackages the request as it is send over the Web.
' You should only need to do this for services that return large amounts of data.

dim Result as CallResult

on error goto errorQuota
Operations = Service.Endpoint.Contract.Operations

for i = 1 to Operations.Count
    Operation = Operations[i]
    Behaviors = Operation.Behaviors
    Enumerator = Behaviors.GetEnumerator()
    while Enumerator.MoveNext()
        Current = Enumerator.Current
        if Current.gettype().FullName = "System.ServiceModel.Description.DataContractSerializerOperationBehavior"
            Current.MaxItemsInObjectGraph = 2147483647
        end if
    end while
next

goto doneQuota

errorQuota:
Result.Code = error_code_get()

doneQuota:

SetSvcGraphObjectQuota = Result

END FUNCTION
 

 

Norman G. Jensen

Norman G. Jensen, Inc (JGJ) provides US and Canadian customers brokerage, freight forwarding, warehousing,
distribution and consulting services to North American importers and exporters. For more information about the
company see http://www.ngjensen.com.

This script example downloads the service definition, generates and loads a client proxy assembly and then calls a service
function that accepts raw XML requests.


dim WebLink as C = "https://forms.ngjensen.com/library/aes_jt_service.php?wsdl"
dim DLLName as C = "c:\temp\aesV12.dll"
dim EndPointWebLink as C = "https://forms.ngjensen.com/library/aes_jt_service.php"

dim Result as CallResult

' Test Values - See Jensen documentation for actual values.
Authorization = 12345
IPAddress = "127.0.0.1"
XML = "<?xml version='1.0'?><NGJDocument><DocInfo ... >"

Result = CreateDLL(WebLink, DLLName)
if Result.Sucess
    Result = RegisterNamespace(DLLName, "submit_xml")
end if

if Result.Success
    Result = SubmitXML(EndPointWebLink, Authorization, IPAddress, XML)
end if



FUNCTION CreateDLL as P (WebLink as C, AssyFile as C)

CreateDLL = new CallResult()

if File.Exists(AssyFile)
    end function
end if

dim Service as DotNet::Services
if .not. Service.GenerateWebServiceClientFromURL(WebLink, AssyFile)
    CreateDLL = Service.CallResult
end if

end function



FUNCTION RegisterNameSpace as P (AssyFile as C, NameSpace as C)
' Load the assembly and register the types in Alpha Anywhere

RegisterNameSpace = new CallResult()

dim Service as DotNet::Services
dim AssyRef as DotNet::AssemblyReference
AssyRef.FileName = AssyFile
Dim Result as CallResult

if .not. Service.RegisterAssembly(NameSpace, AssyRef)
    RegisterNameSpace = Service.CallResult
end if

end function


function SubmitXML as C (EndPointWebLink as C, Authorization as C, IPAddress as C, XML as C)
dim AES as submit_xml::AES_Methods
dim cc as c
cc = AES.js_submit_xml(Authorization, IPAddress, XML)
SubmitXML = cc
end function

 

 

 

 

UX Component - List of Switches - A common design pattern in mobile applications is to have a series of switch controls to set logical values. The screenshot below shows how this might look.

Download component

 

 

 

 

 

Here are some of the important settings for each switch control:

 

 

 

Notice that the 'Control Container Classname' property property has been set to a custom class name. The definition is shown below.

In the CSS, we first set the control container to have a relative position - which means all absolutely positioned child elements will be positioned relative to the parent - allowing parent width and position to be honored be the child.

We then set the first level of child DIVs (of which there is only one - the switch itself - the label is a LABEL element) to have an absolute position, a specific width, and a right location of 0px - which means it will stick to the right of the parent.


.switchCtrlGroup {
    position: relative;
}
.switchCtrlGroup > div {
    position: absolute;
    right: 0px;
    width: .75in;
}

 


 

 

Build 2128-4292 29-Apr-2014 - Alpha Anywhere Version 2

Features

Web Application - PhoneGap - If you have a lot of applications in PhoneGap build, retrieving the app icon for each app can be slow because the PhoneGap build API does not have a call to retrieve all icons at once. You have to call the API once for each app. Therefore, a new property has been added to the Get Icon Timeout Threshold property. If you set this property to <disable>, a default icon will be used.

 

Features

Grid Component - <RowNumber> and <LogicalRecNo> Columns - Using these virtual columns in a tabular Grid caused an error.

AlphaDAO - MySQL - Numeric Fields with 7 or More Decimals - Fixed an issue with MySQL where you could not enter numbers with more than 6 decimal places.

Grid Component - Setting State Variables - Fixed an issue where setting state variables using the e._state pattern was not working in the AfterInsert, AfterUpdate and AfterDelete server-side events.

Build 2118-4290 24-Apr-2014 - Alpha Anywhere Version 2

Videos

 

UX Component Multi-select List Control - Icon to Indicate Selected Rows The Button List control (and the Checkbox control - configured to render as a Button List) can show an icon on selected items. The List control can also be configured to allow multiple selections (like a Button List or Checkbox), but it does not show an icon on the selected rows to indicate the row has been selected (it shows selected rows using a different row color).

In this video we show how you can easily display an icon on the selected rows. The technique uses a custom CSS class.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Making a TextArea Fill a PanelCard Controls such as Lists and Maps have a 'Fill container' property that allow you to automatically cause the List or Map to fill the Panel Card in which the control is contained. Other controls, such as Text Areas, do not have this property.

In this video we show how you can configure the UX so that the Text Area control automatically fills the Panel Card in which it is contained.

Watch Video
Download Component

 

 

Bugs

UX and Grid Component - Image Upload Action - Image Scaling - Fixed issue with scaling image after it was uploaded.

 

Calendar Component - Editing Events  - Fixed an issue editing an event the second and subsequent time. This issue was introduced in build 2089.

UX Component - Phone Gap - Fixed an issue with PhoneGap where Ajax callbacks were failing and images that were loaded from the server were failing.

Features

AlphaDAO - SQL::TableInfo - ParseTableName() Method - A new static method has been added to the SQL::TableInfo object. The .ParseTableName() method takes a fully qualified tablename and returns the base table name, owner, schema and catalog for the table.

For example

 

dim CatalogName as C
dim SchemaName as C
dim OwnerName as C
dim BaseTableName as C
dim FullName as C = "dbo.[hello.world]"
dim ti as sql::tableinfo
?ti.ParseTableName(CatalogName, SchemaName, OwnerName, BaseTableName, FullName)
= .T.

?CatalogName
= ""

?SchemaName
= ""

?OwnerName
= "dbo"

?BaseTableName
= "dAgency.06"

?fullname
= "[dAgency.06]"

 

 

UX Component - Action Javascript - Panel Actions - Navigate Action - History - The 'Navigate' action now has new options. The options with the 'History' prefix allow you to navigate through the Panel Navigator's history (much list the way a browser's history button works).

Code Editors - Xbasic and Javascript - Bookmarks - You can now get quick access to any bookmarks you insert into the script or function you are editing by clicking the 'Bookmark' icon on the status bar.

A bookmark is any comment that starts with //.

For example:

'//bookmark1  (Xbasic)

//''Bookmark1 (Javascript)

 

 

AlphaDAO - Listing Tables in a Database - When you use the <connection>.listTables() or <connection>.listTablesWithTypes() methods to list the tables in a database, by default, only the first 1,000 objects are listed.

As a result of this, many of the builders you use in AlphaAnywhere that require you to select a table only present a list showing the first 1000 tables in the database. Now, a new setting in the Settings dialog box allows you to set the maximum number of tables returned in a table listing.

To open the Settings dialog box, select the top-level View menu, then select Settings.

 

 

 

If you are using AlphaDAO to get your own listing of tables in an object, the SQL::TableFilter object which is passed into the .listTables() and .listTablesWithTypes() method now allows you to set the .MaximumTablesInList property on the SQL::TableFilter object. Set this property to -1 for no limit.

For example:

 

 

 

dim sqlFilter as sql::TableFilter

sqlFilter.IncludeAliases= .t.

sqlFilter.IncludeAllCatalogs= .F.

sqlFilter.IncludeAllOwners= .F.

sqlFilter.IncludeAllSchemas= .T.

sqlFilter.IncludeLinkedTables= .f.

sqlFilter.IncludeSynonyms= .t.

sqlFilter.IncludeSystemTables= .f.

sqlFilter.IncludeTables= .t.

sqlFilter.IncludeViews= .t.

sqlfilter.MaximumTablesInList = 2000

dim cn as sql::connection

cn.open("::name::myconnection")

dim list as c

list = cn.listTables(sqlFilter)

 

Tip: You can use the Xbasic helper function to list tables and automatically honor the setting you have defined in the Settings dialog. The helper functions are a5_list_tables() and a5_list_tables_with_types(). The functions take the connection object as the first parameter and the sql::tableFilter object as the second parameter.

 

 

Tips

AlphaDAO - Connection Strings - Postgres - Specifying the Default Schema - When working with a Postgres database that contains multiple schemas, you can specify the default schema in the connection string. Unfortunately, at this point, the connection string dialog does not let you specify the default schema, but you can easily edit the generated schema to add the necessary directive to set the schema.

For example:

{A5API='PostgreSQL',A5Syntax='PostgreSQL',A5UseServerSidePrepare=Y,A5InitialCommand='SET SCHEMA ''TestSchema''', Database='Alphasports', Password='alpha',Port='5432',Server='localhost',UserName='postgres'}

 

In this example, the following directive has been added to the connection string:

A5InitialCommand='SET SCHEMA ''TestSchema'''

 

Notice that the entire argument to the A5SetInitialCommand is enclosed in single quotes. Therefore the schema name, which must also be enclosed in single quotes uses escaped single quotes (a double single quote).

 


 

 

Build 2091-4284 11-Apr-2014 - Alpha Anywhere Version 2

Bugs

UX Component - List Control - Multi-Select - If the List control was configured to allow multiple rows to be selected, when the UX was submitted, the selections in the List were not being returned as an array, as they should have been. Instead, they were being returned as a '\n' delimited string. This bug was introduced in the last update.

 

Videos

Grid Component Opening a UX from a Button on a Grid and Passing Information Into the UX You can open a UX component from a button on a Grid using several different actions in Action Javascript. For example, there are built-in actions to edit the data in the current row of a Grid using a UX.

But sometimes you want to simply open a UX and pass information from the current row in the Grid to the UX.

In this video we show how this is easily done by defining arguments in the UX component and then automatically setting the value of these arguments when the UX is opened.

Watch Video - Part 1
Watch Video - Part 2
Download Component

Build 2089-4283 10-Apr-2014 - Alpha Anywhere Version 2

 

Security

 

Application Server - OpenSSL - 'HeartBeat' Bug - The Application server now uses Version 1.0.1g of the 3rd party OpenSSL library which Alpha Anywhere uses. This updated library patches the so called 'HeartBeat' vulnerability in the OpenSSL library.

 

 

Breaking Changes

UX Component - List Control - Group Summaries - If you are using the {dialog.object}.groupSummary() method in a Group header or footer, you will need to edit the component and change the method to

this.groupSmmary()

The .groupSummary() function is now a method of the List object. Previously is was a method of the UX object.

Application Server - Warning. A change has been made to the web security system to load the security much faster. This change alters one of the published security files. If a project is published from the latest pre-release to an older application server, the older application server will report a 500 internal server error as it won't be able to read the new file. The application server should be the same build as the development program.
 

 

Videos

UX and Grid Component E-mailing a Report A common pattern in both the UX and Grid component is to place a button on the component to print a Report and display the Report in a window, div or TabbedUI pane. However, instead of displaying the Report, you might want to send it as an email.

The Action Javascript action to Print a Report has an option to call an Xbasic function when the Report has printed.

In this video we show how you can use this option to e-mail the report using the Mandrill e-mail service.

(Note: The sample function prototype shown in the video is only available in build 4241 or above.)

Watch Video - Part 1
Watch Video - Part 2
UX Component Cross-domain Ajax Callback A cross-domain Ajax callback is a callback that takes places to a server that is in a different domain than the domain from which the component was loaded.

In this video we show how a callback is made to the Apple iTunes store and we contrast the difference between making the callback directly to the Apple site versus making a callback to the Alpha server first and then having the Alpha server make the call to the Apple site.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

Download component
 
UX and Grid Component Using CSS Icons from the Font-Awesome Icon Font Library The Font-Awesome CSS Icon library (http://fontawesome.io) is bundled with Alpha Anywhere and can be used in the UX, Grid and TabbedUI components.

In this video we show how to use the Font-Awesome font library and CSS icons in general.

Watch Videos - Part 1
Watch Videos - Part 2
Watch Videos - Part 3

 

UX and Grid Component Using 3rd Party Icon Font Libraries (CSS Icons) There are many 3rd party Icon Font (CSS Icons) libraries that can be used with Alpha Anywhere. In this video we show how you can go to a source of icon fonts  (http://www.fontello.com/)and download a font library that can then be installed into Alpha Anywhere.

Watch Video
UX Component Using CSS Icons in a List - List Menus A common pattern in mobile applications is to use a List control as the menu. This list control is then displayed in a Panel Window that animates in from the left side of the screen. Icons are typically displayed for each menu choice. CSS Icons are ideal for these types of icons. In this video we show how a List can be easily configured to display a menu. Each item in the List has a CSS Icon in it.

Watch Video
UX Component - Mobile Applications Creating a 'Split-View' using the Pre-Defined 'Split-View' Template A common pattern in mobile application is the 'split-view' which shows a menu on the left and a work area on the right. On a phone, were space is limited, the menu is hidden and only shown on demand, but on a tablet, the menu is always shown. In this video we show how you can quickly create a UX component that implements a split-view by selecting one of the pre-defined 'split-view' templates. We then explain some of the concepts behind the component.
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

 
UX Component Split Buttons A split button is displayed as a regular button and a smaller button with a dropdown icon. You can have different event handlers for the dropdown button portion of the button and the regular portion of the button. When space is constrained, you can use a single split button to perform many tasks, while still giving the user single click access to the last selected task.

In this video we show how you can use split buttons in your applications.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download components
UX Component List Control - Lookup Columns The List control allows you to define 'lookup columns' where the data in the column is 'looked up' either by calling a Javascript function (that you define), or by looking up the value in some other List.

A typical use case for this is a List that shows Order Details. Each row in the list has a 'productId' field. You would like to display the product name for each product id.

In this video we show how to define Lookup Columns in a List.

Watch Video
Download Component (You will need to change the connection string for both lists to point to the sample Northwind database).
UX Component List Control - Client-side Grouping and List Navigator Group breaks can be inserted into the List control. The group breaks can be 'server-side' group breaks, or 'client-side' group breaks. The advantage of 'client-side' group breaks is that they can be dynamically applied to the data in the List. That means you can easily switch from grouping the data by 'Lastname' to grouping by 'City', etc. You can also display summary values in the group headers and footer.

For lists that have group breaks (regardless of whether the group breaks were computed server-side or client-side), you can also display a List Navigator, which allows the user to easily scroll a long List.

In this video we give an overview of client-side group breaks and the List Navigator. Then, we go into depth on setting up client-side grouping using Action Javascript (to apply the group breaks after the List is initially rendered) and in the List definition itself (so that when the List is initially rendered, the group breaks are shown).

We also show how summary data can be inserted into a List header or footer.

Watch Video - Overview
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Download components
UX Component List Control - Using Native SQL For List Data When you create a List control that is based on SQL data, you must use Alpha Anywhere 'portable' SQL. If you want to base you List on 'native' SQL (which includes stored procedures), you must define a 'custom' data source for the List and then in the Xbasic function that returns the data, you can use your native SQL.

In this video we show how this can be done.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Drag and Drop - Dragging Rows from a Source List to a Target List A common design pattern in applications is to allows users to drag items from one List to another.

The Alpha Anywhere Javascript library contains powerful drag and drop functions that allow you to easily enable this type of functionality. In this video we show how you can create a UX with two List controls and drag rows from one List to the other.

Watch Video

In this video we explain the Javascript code that enables this functionality:

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4

Download component

Addendum. The previous videos show drag/drop on a List using a mouse. However, the previous examples do not work on some mobile devices because on iOS (for example), the 'up' event fires on the element that initiated the 'down' event (and not on the element on which the up event took place, as you might have expected). The next video explains how the component shown in the previous videos can be slightly rewritten so that it works on a mobile device (and as a bonus, also allows re-ordering of the rows within a List).

Watch Video
Download component
 
UX Component List Control - Range Searches The List control has a built-in action in Action Javascript to filter the List. An Ajax callback to the server is made and the query that populates the List is executed with a filter that is computed based on values in the search control on the UX. Now, you can easily perform 'range' searches, as shown in this video.

NOTE: Another way to perform a 'range' search is to use a single search control, turn on the 'Allow QBF' option and then enter the search value as a range using the .. (two dots) synax. For example, to search for quantity between 10 and 20, you would enter 10..20 in the search control.

Watch Video
UX Component Absolute Layout Container - Save as PDF The Absolute Layout container in a UX allows you to place controls at absolute locations, typically using a bitmap image of a form as a background. You can use an action in Action Javascript to save the contents of the Absolute Layout container as PDF file and then download the PDF to the client, or call some Xbasic function to process the PDF file.

This video shows how this is done using Action Javascript.

Watch Video
UX Component Internationalization - Language and Text Dictionary Tags Language or Text Dictionary tags are typically used to internationalize the strings in a UX component. However, adding the tags to a large component can be tedious. This video shows how the Internationalization Helper can be used to automate this task.

Watch Video
UX Component Client-side Formatting for Numeric Data and Templates You can use format directives in the Templates that the UX component List control uses to display data. This allows you to easily format numbers (for example show thousands separated by commas with 2 decimal places) and apply templates to strings (for example, show '5551234567' as (555) 123-4567)

The video shows how you can insert a format directive into a List template using the Number Format Genie.

Watch Video
UX Component Using a List Control to Display Detail Information (in Field/Value Pairs) for a Record A common pattern in mobile applications is to display a List of records and then when the user clicks on a row in the List to display a list of fields and corresponding values for the row the user clicked on, with one field/value pair per line.

In this video we show how a second List can be used to display the field/value pairs and how this List can be dynamically populated when the user clicks on a row in the main List of records

Watch Video - Part 1
Watch Video - Part 2
Download component

Addendum: In this video we show how you can enhance the UX by showing a message in the Detail List when no record is active in the primary List.
Watch Video
 
UX Component Dynamically Populating a List with Data from a SQL Database Populating a List dynamically with data from a SQL database is a very common pattern in application development. In this video we show how this is easily done.

In the video we show how a List control on a UX can be populated with customers in a country. The country is selected from a dropdown control.

Watch Video - Part 1
Watch Video - Part 2
Download component
UX Component Transform Data Type of List Data By default, the data type for each field in a List is a Javascript string. In some cases you might want the data type for a column to be a Javascript date or number object.

A benefit of transforming dates into true Javascript date objects is that you can then use date formatting in the template for the List. For example, when displaying a field called OrderDate in the the List, instead of specifying {OrderDate} in the template, you might specify {OrderDate:date('yyyy-MM-dd')}

Watch Video
Download component
 
UX Component List Virtualization - Optimizing the List for Large Number of Rows When you are working with List controls that contain a large number of rows (say several thousand rows), it is advisable to turn on the List's 'virtualization' feature. With virtualization turned on, the List will only render a small number of rows at a time (the visible rows and some additional rows above and below the visible rows).

Turning on List Virtualization will dramatically reduce both the time taken to load the List and the amount of memory consumed by the List.

Watch Video
Download component
UX Component List Control - Modeless Preview Window in List Builder When you are designing a List control in a UX component, the List Builder is a modal dialog. This means that you need to first close the List Builder before you can preview the UX component to see how your List control looks.

However, while you have the List Builder open, you can click the Preview button to open a modeless preview window which you can keep open whiel you are working in the List Builder. Simply clicking on the Preview button will quickly refresh the preview shown in the window.

Watch Video
UX Component Action Javascript - Merge Data into Template Alpha Anywhere has a very powerful client-side template engine that allows you to merge Javascript data into templates to produce HTML output that can then be displayed on your component.

This functionality is exposed in the 'Merge data into client-side template' action in Action Javascript.

NOTE: Other videos explain the template syntax in more detail.

Watch Video
Download Component
UX Component Using the Template Tester to Help Design Templates - Tutorial on Template Syntax The client-side template engine in the UX component is very powerful, but to be able to take full advantage of its power it is necessary to understand the syntax used in the templates.

In this video we demonstrate how to use the Template Tester and we walk through the various examples that are built into the Template Tester.
The video gives an extensive overview of the template syntax.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
UX Component List Control - Column Resizing The List control allows you to specify that columns in the list are resizable.

This video shows how you can set the resizable property at the individual column level.

Watch Video
Download Component
UX Component Destroy Child UX Component A common pattern when building large mobile applications is to break the app into multiple sub-component which are called from a master component.

Once the child component is no longer needed, it is useful to be able to delete the component from memory in order to conserve the limited memory available in the browser.

The {dialog.object}.destroyChildComponent() method can be used to delete child UX components from memory, as shown in this video.

Watch Video
Download Components
UX Component Generate a component at run-time using Xbasic In most cases, the UX components that your application uses will be built at design-time. However, there may be use cases for UX components that are generated dynamically at run-time using Xbasic.

The a5wcb_createDialogUsingXbasic() allows you to generate a UX component using Xbasic.

In this video we show how a button on a UX makes an Ajax callback to generate a UX on the fly. Another button then opens this dynamically generated UX component.

Watch Video
Download Component
Code Editor Highlighting Opening and Closing 'Pair' Delimiters When editing Xbasic or Javascript code, html, JSON etc. it is often helpful to be able to see the start and end of different 'pairs'. For example in an Xbasic function call, highlighting the opening an closing parentheses. Or in a Javascript function, highlighting the opening and closing curly braces. In some HTML text, the opening and closing tags (e.g. <div>, <body>, <p> , etc.)

In addition, once a 'pair' has been identified, keyboard shortcuts (Control  ] and Control-Shift ] )  allow you to quickly move focus from the start of the 'pair' to the end of the 'pair' or to select all of the text inside the 'pair'.

Watch Video
UX Component Using the List Scroller to Move Through the Rows in a List When working with virtualized Lists, it is possible to have Lists that have a very large number of rows. Navigating a very large List by drag scrolling on the List body could be cumbersome. To facilitate navigating large Lists, a 'List scroller' can be added to the List. The scroller shows a message while you are dragging on it showing which row in the List will be shown if you were to stop dragging on the scroller.

Using the scroller, you can very quickly navigate to any row in the List.

The List Scroller is not limited to virtualized Lists. It can also be used with non-virtualized Lists.

In this video we show how to add a List Scroller to a List and we show how you can quickly navigate to the last row in a virtualized List that contains 100,000 row of data.

Watch Video
Download component

 

 

 

 

 

 

Notice

Application Server - OpenSSL - 'HeartBeat' Bug - The Application server now uses Version 1.0.1g of the 3rd party OpenSSL library which Alpha Anywhere uses. This updated library patches the so called 'HeartBeat' vulnerability in the OpenSSL library.

 

 

Postgres ODBC Driver - Version 9.03.01.00 - Bugs - Postgres has introduced a bug in the latest version of their ODBC driver that affects the Grid component. The only solution is to roll back to a previous version of the ODBC driver, or turn off write conflict checking for all updateable fields in the Grid.

Specifically, the driver fails when an expression is included in the WHERE clause that tests a bound variable for NULL-ness.
Here is a summary of the bug:

Consider the following sample Interactive window session:


dim args as sql::arguments
args.add("tags", "rain, snow")
?cn.execute("select * from test_table where :tags is null", args)

 

This will fail and the error reported is:

The PostgreSQL ANSI ODBC driver reports 42P18 - ERROR: could not determine data type of parameter $<n>; when preparing SQL with an expression of the form:

<bound parameter> IS NULL.
 

Update: A work around has been added in the SQL generated by the Grid Component so that Grids will work with the 9.03.01.00 ODBC driver.

 

 

AlphaDAO - Postgres - Connection String - Changes In Default Values Set By the Alpha Anywhere PostgreSQL Extension Driver

The Alpha Anywhere PostgreSQL extension driver now defaults the following connection string attributes:

Protocol=7.4-1
UseServerSidePrepare=1

Previously only the following were set:

B8=1 // B8 = UnknownsAsLongVarchar (rather than varchar)
B9=0 // B9 = Bools as Char
ByteaAsLongVarBinary=1

If these defaults do not work for your installation for some reason, you will need to create and ODBC DSN and use the Alpha Anywhere ODBC driver.

Setting Protocol=7.4-1 has been demonstrated by one customer to dramatically improve performance with PostgreSQL 9.3 on large batches of inserts (about 25%).
 

Change in Behavior

Bugs

Reports - HTML Reports - Export to PDF, Excel, Word - International Dates - If your date format was set to dd/mm/yyyy then if you printed an HTML report that used dates in its filter expression and then you clicked a toolbar icon to export the report to PDF, Excel, or Word, the date filter was not applied correctly.

Reports - Quick Report Genie - Summary Fields - Fixed a bug where the Genie would crash if you edited a field that had summary values.

UX Component - Responsive Design Genie - Absolute Layout Containers - Textbox Controls with In-Place Buttons - Fixed an issue that caused the textboxes to not display.

TabbedUI Component - HTML Reports - Reports with Parameters that are Set to Prompt at Runtime - If you had an HTML report that was set to prompt for parameters at runtime, the first time you ran the report, the report would render correctly. But if you tried to run the report a second time (by entering new parameter values, but NOT first closing the Tab Pane), the report did not render.

UX Component - AbsoluteLayout Container - Text Control - Fixed a bug with text controls in an AbsoluteLayout container which caused controls that followed the text control to render in the wrong position.

Reports - Export to Word - In some cases, numeric fields in a report would not export correctly to Word.

UX Component - Absolute Layout Container - PanelOverlay Container - Content in an AbsoluteLayout container that was inside a PanelOverlay container did not render correctly.

Web Applications - Security Framework - MySQL - Under certain circumstances using MySQL tables for web security, deleting a user could fail.  This has now been fixed.

Web Security Framework - CSS Icon Fonts - The new iOS7 and Android style sheets use icon fonts. The images were not displaying if the security framework was enabled because the font files did not have the appropriate security settings.

The web security framework will now recognize the the new font files for CSS icon fonts. The page security must be opened from the web security menu to add the new types to the page security.  Then publish any page to add the new settings to security.  If the Security cache lifetime is set to 0, the application server must be stopped and restarted to apply the changes.
 

UX and Grid Component - Edit-Compo - Populate using Ajax Callback - If an edit-combo is dynamically populated using an Ajax callback, previously, the Order By property was ignored and the list was automatically ordered by the columns in the display list. Now, the order by clause is honored. Many SQL databases do not allow an order by clause on columns that are not in the select list. Therefore, you may need to ensure that the columns in your order by clause are also in the list of fields to display.

Grid Component - Font-Awesome - Live Preview - When you did a Live Preview from a Grid component that used Font-Awesome CSS Icons, the Font-Awesome files were not getting published to the Live Preview folder.

 

Layout Table Reports - Absolute Position Cell - Calculated Fields - If you created a cell in a Layout Table report that used Absolute Positioning and placed calculated fields in the absolute layout, the calculated fields were not shown in the Absolute Layout editor when you opened the editor a second time to make edits to the cell.

Web Applications - Report Server - SQL Reports - Under some circumstances, a report based on a SQL database would fail to print when using the Report Server. The error message was reporting that the connection string could not be resolved.

UX Component - Signature Capture Control - Tab Control - If a signature capture control was placed in a tab pane that was not initially visible, when the tab pane was made visible the control did not work.

Desktop Applications - Security - If you set permission on a .dbf table to disallow edits, changes or deletes, the permissions were not being honored.

 

UX Component - Server-side Save Records to Table(s) Action - User Defined Events - Aborting the Action - The help in the function prototype for the various events (such as beforeRecordInsert, beforeRecordUpdate, etc.) describe that you can abort the action by setting

 

rtc.abort = .t.

 

The help is wrong. It should have read:

e.rtc.abort = .t.

e.rtc.abortReason = "Reason"

 

 

Desktop Applications - Forms - Embedded Browses - Entering New Records - There was a cosmetic issue during data entry into a one-to-one child table in an embedded browser. Consider the following set:

TableMaster===>TableChild1---->TableChild2

If you were entering a new record into the embedded browse and you entered a value in the field in TableChild1 that links TableChild1 to TableChild2 and there was no matching record in TableChild2 (in other words, you were creating a new record in both TableChild1 and TableChild2, rather than the more common case of a new record in TableChild1 that links to an existing record in TableChild2), then as soon as you tabbed out of a field in TableChild2, the data you entered would disappear. When you saved the record, the data you entered would then show up. This is fixed.

 

UX and Grid Component - Edit-Combo - Static Choices - The 'Filter method for required selection' property was not shown if the choices were set to 'Static'. (This property was shown for 'Dynamic' choices).

On Firefox, if you do not set this property to 'Progressive' and you have set the 'User must select from list' property to true, then you will not be able to hit the tab key to tab out of the control to the next control in the form.

 

 

Xbasic - Passing Function Arguments By Referencing - Array Indexers - If a numeric value was passed into a function and then that value was as an array indexer, it failed. For example:

 

function myFunc as c (arr as p, byRef myIndex as n)

    dim result as c

    result = arr[myIndex].name

    myFunc = result

end function

 

However, if you did this, it would have worked:

function myFunc as c (arr as p, byRef myIndex as n)

    dim result as c

    result = arr[myIndex.value].name

    myFunc = result

end function

 

Desktop Applications - Forms and Browse - Lookup Field Rules - Display a Dropdown - Fixed an issue when you could not edit entries in a control that was defined as a lookup.

Calendar Component - TabbedUI - If you had a TabbedUI component that opened multiple calendar components, then buttons in the popup UX component would only render in the last calendar component that was opened.

UX Component - Signature Capture Control - Data Binding to .DBF Tables - Fixed an issue in the signature control if the UX was bound to .dbf tables.

Grid Component - Tree Control Navigator - Session Variables in Custom SQL Statement - If you specified a custom SQL statement for any level of the tree and used session variables in the WHERE clause, the query would fail.

Grid Component - Search Part - Cascading Dropdown Boxes - 'Explicit' Option - If the 'Explicit' option was used for defining the filter for the child Dropdown box, the child Dropdown was not populated correctly when its parent's value was changed. This bug only happened for controls in the Search part.

Grid Component - Radiobutton and Checkbox Controls - 'Not in List' Rule - Numeric Fields - The 'Not in List' property was not exposed for Numeric fields.

 

UX Component - Map Control - Bulk Add Marker - If the latitude sub-series name in the Data Series was not called 'latitude' and the longitude sub-series name was not called 'longitude' the action would throw an error.

 

UX Component - RadioButton and CheckBox Controls - Render as ButtonList Option - Events - When you check the property to render a RadioButton or CheckBox control as a ButtonList, the standard Javascript events that can be defined for a RadioButton or CheckBox are meaningless. ButtonsLists expose two Javascript properties:

Therefore, when you check the 'Render as ButtonList' property all of the standard Javascript properties in the Property Sheet are hidden and the onClick and onSelect events, which are standard for ButtonLists are now exposed.

 

UX Component - Panels - Internet Explorer V11 - Fixed some issues with Panels not working correctly under IE11.

 

Security Framework - Security Log in - The security log in process no longer checks user id and password values to see if they meet validation rules. The process will now attempt to log in with any non-blank value. This check is now only performed when user credentials are created or edited.
 

Features

Xdialog - UpperCase Only Input Control - A new directive, ^, allows you to specify that an input control will only accept uppercase characters. If the user types in a lowercase character, it will convert to uppercase. Previously you could have created a template to only accept uppercase, but that would have prevented the user from entering non-alphabetic characters.

 

For example:

ui_dlg_box("Convert to Upper","[%^%.10name]")

 

Using a template:

ui_dlg_box("Convert to Upper","[%X=LLLLLLLLLL%.10name]")

 

 

UX Component - Additional Resource Files Property - A new property has been added to the UX builder that allows you to specify the names of any additional resource files. These are files in the Web Project folder that you want to ensure get published every time you publish the UX component.

This property is in the 'Other' section of the UX Properties pane in the UX builder.

Additionally, if this component has been specified as the 'initial' component in a PhoneGap project then these files are automatically copied into the PhoneGap project that is submitted to PhoneGap build.

The files entered into this list must be in the form of a cr-lf list of relative filenames (relative to the Web Project folder).

 

UX Component - List Control - Scrollers - List scrollers allow you to quickly navigate to a particular record in a List. You can drag on the scroller in much the same way that you drag on the 'thumb' portion of a scrollbar in a desktop application. When you stop dragging on the scroller, the corresponding row in the List is brought into view.

Watch Video
Download component

 

While you are dragging on the scroller, a message is displayed showing what record would be shown if you were to stop dragging. The contents of the message is completely customizable. It is actually a standard HTML List template and it supports all of the template features for List controls. The message can display fields from the data in the List.

The List scroller is particularly useful for virtualized Lists because a virtualized List can contain a very large number of rows. Using the scroller you can quickly navigate to any row in the List without having to drag scroll one screen at a time.

However, List scrollers are not limited to virtualized Lists. They can also be used with non-virtualized Lists.

(See below for information on Virtualized Lists).

 

 

To turn on the List scroller, check the 'Has scroller' property on the List Properties pane in the List builder.

You can use placeholders for any field in the List in the template.

 

 

UX Component  - Customizing the Scroll Indicator - When you are drag scrolling on a List (or any container that supports drag scrolling), scroll indicators are displayed. You can now customize the appearance of these scroll indicators (or even turn them off).

To customize the scroll indicator settings, click the smart field for the 'Custom scroll indicator settings' property.

 

 

 

UX Component - List Control - Fixed Headers and Footers - List controls have always supported 'data' headers and footers. Data headers appear before the first row of data (below the List titles) and after the last row of data. When the List is scrolled, the data header and footer can scroll out of view.

Fixed headers and footers, on the other hand, appear above and below the List and are always visible regardless of how the List has been scrolled.

To turn on fixed headers and footers, check the appropriate property in the List Properties pane in the List builder.

TIP: To insert controls in the header or footer (e.g. input controls, buttons, etc), add the control to the UX and wrap then in an 'Injectible' container. The inject the contents into the header or footer as shown in the image below. When you open the header or footer editor you will see a hyperlink that generates the required code.

 

 

 

Code Editor - Highlighting - The code editor now highlights opening and closing parentheses, curly braces html tags (when editing HTML text) and long string delimiter (e.g. <<%txt% .... %txt%).

 

Watch Video

 

 

In the image below, the long string has curly braces (it is a JSON object). Because the long string uses the special

%html% delimiter, the curly braces are highlighted.

 

 

When the braces are highlighted, the right click menu has a new option - Select Pair... - which selects all of the text between the opening and closing brace.

 

 

The following keyboard shortcuts can be use when a 'pair' has been identified (i.e. the editor is highlighting the start and end of a pair.

 

 

Grid Component - Action Scripting - Send e-mail Action - Mandrill - Now supports the Mandrill service as a method for sending the e-mail. 

Grid Component - Action Scripting - Send e-mail Action - Dynamically Computing Message Body -

The message body can now be dynamically generated using an Xbasic function.

UX Component - Action Scripting - Send e-mail Action - A new action is now available in Action Scripting to send an e-mail. This is the same action that is exposed in server-side Action Scripting in the After Dialog Validate server-side event handler.

 

CSS Editor - Source View - Quick Navigator - When you are editing CSS in the Source tab of the CSS editor, the toolbar now has a quick selector that allows you to quickly jump to any rule. For example in the screenshot below, clicking on the down arrow icon in the status bar has opened a menu showing all of the selectors in the code being edited.

 

JSON_standardize() function - Takes non-standard JSON and standardizes it. Also corrects for trailing commas in the JSON (which are illegal)

 

For example:

 

?json_standardize("{name: 'Fred', age: 21}")

 {
"name": "Fred",
"age": 21
}

 

?json_standardize("{name: 'Fred', age: 21,}")

 {
"name": "Fred",
"age": 21
}
 


 

UX Component - {dialog.object}.destroyChildComponent() Method - A common pattern when building large mobile applications is to break the app into multiple sub-component which are called from a master component.

Once the child component is no longer needed, it is useful to be able to delete the component from memory in order to conserve the limited memory available in the browser.

The {dialog.object}.destroyChildComponent() method can be used to delete child UX components from memory.

Watch Video

 

 

UX Component - List Control - Column Resizing - You can now specify that individual columns in the List can be resized by the user at run-time. To specify that a column can be resized, check the 'Resizable column' property.

 

 

Watch Video

UX Component - Customize Scroll Indicator - List, Panel and Containers - You can now customer the scroll indicator for List controls, Panels and Containers. By default the scroll indicator for vertical scrolled content is on the right edge and the for horizontally scrolled content, it is on the top. However, you can set the position to left or bottom, and you can control the class and various offsets.

In the image below, the scroll indicator is shown on the left edge with a 20px offset.

 

 

 

To open the scroll indicator customization dialog, click the smart field button:

 

 

 

 

Client-side Templates - Allows you to merge complex Javascript data in richly formatted templates to produce HTML that can be displayed in a UX or Grid component.

 

NOTE: A powerful tool is available when you working with templates. See section below: 'Using the Template Tester'

 

NOTE: Templates use the A5.u.template.expand() Javascript function in the Alpha Anywhere Javascript library. See section below 'The A5.u.template.expand() Function'

 

The basic idea of client-side templates is that you have some Javascript data - typically a Javascript object, or an array of Javascript objects, and a template (with placeholders for data) and you merge the data into the template.

For example, take the following trivial example. Say you have a Javascript object defined as follows:

var data = {Firstname: 'Fred', Lastname: 'Jones'};

 

And a template defined as follows:

var template = 'Hello {Firstname} {Lastname}';

 

When you merge the data into the template, you will get a string that looks like this:

Hello Fred Jones

 

Technical Note: The syntax for the template is identical to the syntax for free-form templates in the List control and for individual columns in a columnar List control.

Of course, in a real application the template will likely also include HTML markup. For example:

var template = 'Hello {Firstname} <span class="class1">{Lastname}</span>';

 

Array Data

The data for the template can be an array of objects, in which case the template will be expanded for each object in the array.

For example:

var data = [

    {Firstname: 'Fred',  Lastname: 'Jones'},

    {Firstname: 'John',  Lastname: 'Smith'},

    {Firstname: 'Sally', Lastname: 'Rome'}

];

 

Using the same template as above, this will produce this output:

Hello Fred Jones

Hello John Smith

Hello Sally Rome

 

Object Data

The data object can include sub-objects. For example

var data = {Firstname: 'Fred', Lastname: 'Jones', Address: { Street: '123 Main St', City: 'Boston', State: 'Ma' }};

 

The template to consume this data could then be defined as follows:

var template = 'Hello {Firstname} from {Address.Street} in {Address.City}';

 

Alternatively, the template could be defined as follows:

var template = 'Hello {Firstname} from {Address} {Street} in {City} {/Address}';

 

Notice that the template includes {Address} and {/Address}. Inside the {Address} block, the placeholders do not need to be fully qualified. You can use {Street}, rather than {Address.Street}

The {Address} placeholder is referred to as a 'scope' placeholder.

Both of these templates will produce the same output:

Hello Fred from 123 Main St in Boston

 

Array Data and Object Data Combined

In the Array Data example above, the data was in the form of a Javascript array. In many cases it will be preferable have the data as an object. So, instead of specifying the data for the template as:

var data = [

    {Firstname: 'Fred',  Lastname: 'Jones'},

    {Firstname: 'John',  Lastname: 'Smith'},

    {Firstname: 'Sally', Lastname: 'Rome'}

]

 

You could specify it as:

var data = {

    Customers: [

        {Firstname: 'Fred',  Lastname: 'Jones'},

        {Firstname: 'John',  Lastname: 'Smith'},

        {Firstname: 'Sally', Lastname: 'Rome'}

    ]

}

 

The template to consume this data could then be defined as:

   

var arr = [];

arr.push('{Customers}');

arr.push('Hello {Firstname} {Lastname}');

arr.push('{/Customers}');

var template = arr.join('\n');

 

NOTE: The template is created by pushing individual lines into a Javascript array and then joining the array. This is simply a convenient technique for creating long strings in Javascript.

 

This template will produce this output:

Hello Fred Jones

Hello John Smith

Hello Sally Rome

 

Notice that since the {Firstname} and {Lastname} placeholders are nested inside the {Customer}...{/Customer} scope placeholders, it is not necessary to use fully qualified placecholders (e.g. {Customer.Firstname}).

 

The benefit of placing your array as a property of an object, rather than at the top level, is that you can then use the {*header} and {*footer} constructs, and you can compute summary information (such as the number of items in the array, an average value of a field in the array, etc).

 

Client-side Template Syntax

There are a rich set of template directives that make templates both extremely powerful and also easy to use.

 

 

{scope} Placeholders

If the data passed to the template expand function contains nested objects, or arrays, you can use special {scope} placeholders, where scope is the name of nested object or array.

For example, consider the following simple data object:

{name: 'John Smith', address: {street: '1 Main', city: 'Boston'}}

The template to print this could be:

{name}

{address.street}

{address.city}

 

or more conveniently, a {scope} variable could be used:

{name}

{address}

{street}

{city}

{/address}

The {scope} variable acts like an 'with' statement in Xbasic.

Within the {scope}, it is not necessary to fully qualify the placeholder names.

In the case where the data contains a nested array, the {scope} variable indicates that the template should loop over the rows in the array.

For example, consider this data object:

[

    {name: 'John Smith', children: [{name: 'Griffin'}, {name: 'Callie'}]},

    {name: 'Toby Mohan, children: [{name: 'Kyle'}, {name: 'Katy', name: 'Luke'}]}

]

And the following template:

{name}<br>
<ul>
    {children}
        <li>{name}</li>
    {/children}<br>
</ul>
 

  Which will produce this output:

 

John Smith
Toby Mohan

 

{[value]} Placeholder

The {[value]} Placeholder is a special placeholder to use when looping over arrays of values, rather than arrays of objects.

In the previous example, the data was specified as:

 

[

    {name: 'John Smith', children: [{name: 'Griffin'}, {name: 'Callie'}]},

    {name: 'Toby Mohan, children: [{name: 'Kyle'}, {name: 'Katy', name: 'Luke'}]}

]

 

The nested array is an array of objects.

However, the data could have been specified as:

 

[

    {name: 'John Smith', children: 'Griffin','Callie']  },

    {name: 'Toby Mohan, children: ['Kyle', 'Katy','Luke']}

]

In this case, the nested array is an array of values, not of objects.

To emit the data in the array, the template must use the special {[value]} placeholder. For example:

{name}<br>
<ul>
    {children}
        <li>{[value]}</li>
    {/children}<br>
</ul>
 

 

NOTE: The [value] field can be followed by formatting directives, just like any other field. For example:
{[value]:number('$#,###.00')}

 

Missing Data - Alternative Text - The || Directive

In some cases the data you pass in to the template expander will have missing data. For example, consider the following data object:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', city: 'Boston'},
        {firstname: 'Laura', lastname: 'Linneker'}
    ]
}

 

The 'city' property has been specified for the first object in the 'employees' array, but not the second.

 

{employees}
    Employee name: <b>{firstname} {lastname}</b> City: {city||Not available}<br>
{/employees}

 

The text to display for a missing value is specified in the placeholder after a || delimiter. In the template shown above, the missing text for the {City} property has been specified as 'Not available'.

The above template will render as follows

Employee name: Fred Smith City: Boston

Employee name: Laura Linneker City: Not available

 

NOTE: The missing data directive can be combined with formatting directives. For example:  {price:number('#.00')||N/A}

 


 

 

Headers and Footer - {*header} / {*footer}

Headers and Footer can be used if the data object you pass into to the template expander contains array data.

For example, assume the data object looks like this:

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith'},
        {firstname: 'Laura', lastname: 'Linneker'}
    ]
}

 

And the template looks like this:

 

{employees}
    {*header}
        This is the header - it prints before the first item in the array.<br>
    {/*header}
    Employee name: <b>{firstname} {lastname}</b><br>
    {*footer}
        This is the footer - it prints after the last item in the array
    {/*footer}
{/employees}
 

The merged data will look like this:

 

This is the header - it prints before the first item in the array.
Employee name: Fred Smith
Employee name: Laura Linneker
This is the footer - it prints after the last item in the array

 

Empty Arrays - Alternative Text - {*empty}

If an array does not contain any entries you can specify alternative text to display.

 

For example, consider the following sample data:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', skills: [ {name: 'Javascript'},{name: 'CSS'}]},
        {firstname: 'Laura', lastname: 'Linneker', skills: [{name: 'Xbasic'}]},
        {firstname: 'Junior', lastname: 'Programmer', skills: [] }
    ]
}

 

Notice that only the last array instances does not have any rows in the skills array.

The template might be defined as follows:

 

{employees}
    Employee name: <b>{firstname} {lastname}</b><br>
    <div style="border:solid 1px green; margin-left:50px;">
        {skills}
            {*empty}
                No skills yet
            {/*empty}
            Skill Name: {name}<br>
            {*footer}
                <i>Count of skills: {@countSkills}</i>
            {/*footer}
        {/skills}
    </div>
{/employees}
 

The Javascript function for the countSkills function (called by the {@countSkills} directive) is:

 

function countSkills(data,context) {
    return data[context].length;
}
 

 

The merged data looks like this:

 

Employee name: Fred Smith
Skill Name: Javascript
Skill Name: CSS
Count of skills: 2
Employee name: Laura Linneker
Skill Name: Xbasic
Count of skills: 1
Employee name: Junior Programmer
No skills yet

 

Conditional Sections - {*if logicalExpression}, (*endif}

Templates can include conditional sections. Conditional sections are defined using the following template commands:

where logicalExpression is any Javascript expression that evaluates to a true/false value.

The logicalExpression can refer to data in the current 'row' of data.

For example, consider the following data:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', state: 'MA'},
        {firstname: 'Laura', lastname: 'Linneker', state: 'CA'},
        {firstname: 'Junior', lastname: 'Programmer', state: 'MA'},
        {firstname: 'Bill', lastname: 'Lindsey', state: 'NY'}
    ]
}
 

And the following template:

 

{employees}
    Employee name: {[countOneBased]} <b>{firstname} {lastname}</b><br>
    <div style="border: solid 1px blue; margin-left:20px; margin-bottom: 10px;">
        {*if state=='MA'}
            Employee is based in MA
        {*elseif state=='CA'}
            Employee is based in CA
        {*else}
            Employee is not based in MA or CA
        {*endif}<br>
    </div>
{/employees}

 

The merged data looks like this:

 

Employee name: 1 Fred Smith
Employee is based in MA
Employee name: 2 Laura Linneker
Employee is based in CA
Employee name: 3 Junior Programmer
Employee is based in MA
Employee name: 4 Bill Lindsey
Employee is not based in MA or CA

 

Formatting Directives

You can include formatting directives in the template placeholder to format numeric values and strings, and to format date values.

To format a numeric value, use the :number(formattingDefinition) directive in your placeholder.

For example, assume you have a field called Price, which contains this value: 123456.345.

You might define the template to emit this field as follows:

{Price:number('$#,###.00')}

 

This will result in the following output:

$123,456.35

 

You can also use the :number() directive to merge strings into templates. For example,, assume that you have a field called Phone, which contains 6715551234.

The placeholder for this field in your template could be defined as:

{Phone:number('=(###) ###-####')}

 

This will result in the following output:

(617) 555-1234

 

 

To format a date value, use the :date(formattingDefinition) directive in your placeholder.

You can use the following symbols in the formattingDirective.

You can also use the :uppercase and :lowercase directives to force string values to upper or lower case.

For example:

{name:uppercase}

{name:lowercase}

 

 

NOTE: The missing data directive can be combined with formatting directives. For example:  {price:number('#.00')||N/A}

 

 

Expressions - {expression}

The placeholders in a template can be arbitrary Javascript expressions.

For example, assume that you have the following data and template:

{product: 'Book', qty: 4, price: 23}

 

Template:

Product: {product.toUpperCase()} - Price: {price}, Quantity: {qty} - Total: {price * total:number('$#,###.00')}

 

Result:

BOOK - Price 23, Quantity: 4 - Total $92.00

 

Functions - {@JavascriptFunctionName}

Your template can include calls to Javascript functions that compute values based on data in the current 'row'. To call a function you use the {@JavascriptFunctionName} placeholder in your template, where JavascriptFunctionName is the name of the Javascript function that you want to call.

The value returned by the function is emitted for the placeholder.

The Javascript function takes a single parameter, data, which allows you to reference data from the current row.

Consider the following simple data object:

{firstname: 'John', lastname: 'Smith'}

And the following template:

Hello {@fullname}

 

The fullname Javascript function might be defined as:

function fullname(data) {

    return data.firstname + ' ' + data.lastname.toUpperCase();

}

 

The template result for the above data, template and Javascript function will be:

Hello John SMITH

 

Functions can also be used to compute summary data. For example, assume that the data object you define includes an array of data. You might want to output summary data that includes (say) the count of the number of rows in the array and the total of one of the fields in the array.

Consider the following sample data object:

{

    customer: [

        {name: 'Smith', amountDue: 345.34},

        {name: 'Jones', amountDue: 35.43},

        {name: 'King', amountDue: 45.14}

    ]

}

 

And the following template:

{customer}

    {name} - {amountDue}<br>

    {*footer}

        Total amount due: {@amountDue} from {@count} customers.

    {/*footer}

{/customer}

 

And the following definition for the 'amountDue' and 'count'  javascript function:

 

function amountDue(data,scope) {
    var arr = data[scope]
    var tot = 0;
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amountDue;
    }
    return $u.n.round(tot,2);
}

 

function count(data,scope) {

    return data[scope].length;

}
 

 

 

The above will produce this output:

Smith - 345.34

Jones - 35.43

King - 45.14

Total amount due: 425.91 from 3 customers.

 

In the above example, notice that the 'amountDue' and 'count' functions are in the {*footer}..{/*footer} block inside the {customer}..{/customer} scope. When the Javascript functions are called from inside a {*header} or {*footer} block the scope ('customer') is passed into the function along with the data. ('data' is the first argument, and 'scope' is the second argument).

What's in the 'data' object passed into a Javascript function depends on where the Javascript function is called from.

If a Javascript function is called from within a {*header} or {*footer} placeholder the data in the data object will be the same as if the function had been called from outside the scope. In other words, if the template has {@myfunction} after the closing {/customer} placeholder, the data passed to the 'myfunction' Javascript function will be the same as the data that would be passed to the function had it been called from inside a {*header} or {*footer} block inside the scope (e.g. {customer}...{/customer}.

On the other had, if the {@myfunction} placeholder is used anywhere within the scope (e.g. inside the {customer} ..{/customer} block), but not inside a {*header} or {*footer} block, the data object only contains data for the current array instance and the 'scope' value is blank.

The following example will help make this clear:

 

Data:

{
    customer: [
        {name: 'Smith', amountDue: 345.34},
        {name: 'Jones', amountDue: 35.43},
        {name: 'King', amountDue: 45.14}
    ]
}
 

 

Template:

{customer}
    {name} - {amountDue} - {@data}<br>
    {*footer}
        In footer:<br>{@data}
    {/*footer}
{/customer}
<br>
Outside the 'Customer' scope: {@data}

 

 

Javascript function:


function data(data,scope) {
    if(scope == '') scope = 'BLANK';
    var json = JSON.stringify(data,'\t');
    var msg = '<div style="border: solid 1px red;"><b>scope</b>: ' + scope +       

                '<br><b>data</b>: ' + json + '</div>';
    return msg;
}

 

The above produces this output:

 

Smith - 345.34 -
scope: BLANK
data: {"name":"Smith","amountDue":345.34}

Jones - 35.43 -
scope: BLANK
data: {"name":"Jones","amountDue":35.43}

King - 45.14 -
scope: BLANK
data: {"name":"King","amountDue":45.14}

In footer:
scope: customer
data: {"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

Outside the 'Customer' scope:
scope: BLANK
data: {"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

 

Note that the 'data' Javascript function simply shows the data that is passed into the function (as a JSON string) and also shows the value of the 'scope' argument

 

The 'data' function is called in 3 different places:

As show, inside the {customer} scope, the data passed into the function is just the data for the current array instance and the 'scope' passed into the function is blank.

However, when the Javascript function is called from inside the {*footer} block, the data and scope passed into the function are the same as if the function had been called from outside the {customer} scope. In this case the data passed into the function includes all of the data in the scope.

 

With the above understanding of the what's passed into the Javascript function, let's re-examine the 'amountDue' and 'count' functions from the previous example. Here is the function definition again:

 

function amountDue(data,scope) {

    var arr = data[scope]
    var tot = 0;
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amountDue;
    }
    return $u.n.round(tot,2);
}

 

The amountDue function has been called from inside a {*footer} construct. Therefore the data passed into the function looks like this (in JSON format)

{"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

 

Therefore we can get the array of data shown in the {customer} scope by using this Javascript statement:

data['customer']

 

However, the 'scope' variable that was also passed into the function contains 'customer', so we can get the array of data as follows:

data[scope]

 

Once we have the array of data, it is a simple matter of writing a Javascript loop to sum up the value in the 'amountDue' property for each row in the array.

Note that before we return the number we use the $u.n.round() function from the Alpha Anywhere Javascript library to round the result to 2 decimal places.

The 'count' function is even simpler. We simply return the length of the array.

 

function count(data,scope) {

    return data[scope].length;

}
 

 

 

Here is a more complex example that shows an object with two arrays of data - 'charges' and 'payments'. Our template shows the total charges, total payments, and the net amount due (total charges - total payments)

 

Here is the data:

 

{
    charges: [
        {name: 'Smith', amount: 345.34},
        {name: 'Jones', amount: 35.43},
        {name: 'King', amount: 45.14}
      ],
    payments: [
        {name: 'Smith', amount: 123.34},
        {name: 'Jones', amount: 45.45}
        ]
}
 

 

Here is the template:

 

<b>Charges</b><br>
{charges}
    {name}<br>
    {*footer}
        Total charges: {@totaldue}
    {/*footer}
{/charges}<br>
 

<br>
<b>Payments</b><br>
{payments}
    {name}<br>
    {*footer}
        Total payments: {@totaldue}
    {/*footer}
{/payments}<br>
<br>
Net amount due: {@netdue}

 

Here is the Javascript:

function totaldue(data,context) {
    var tot = 0;
    var arr = data[context];
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amount;
    }
    return tot.toFormat('$#,###.00');
}

function netdue(data,context) {
    var arr = data['charges'];
    var totDue = 0;
    for(var i = 0; i < arr.length; i++) {
        totDue = totDue + arr[i].amount;
    }

    arr = data['payments'];
    var totPay = 0;
    for(var i = 0; i < arr.length; i++) {
        totPay = totPay + arr[i].amount;
    }

    var netDue = totDue - totPay;
    return netDue.toFormat('$#,###.00');

}

 

 

And here is output produced by this template:

 

Charges
Smith
Jones
King
Total charges: $425.91

Payments
Smith
Jones
Total charges: $168.79

Net amount due: $257.12

 

Notice in the above example that the same 'totalDue' function can be used to return both the total charges and the total payments (because in the first case the 'scope' passed into the function will be 'charges' and in the second case, the 'scope' passed into the function will be 'payments'.

The 'netDue' function that called from outside both the 'charges' and 'payments' scope gets called with the data for both arrays. This function gets the charges array using this syntax:

data['charges']

and then computes the total charges.

Then it gets the payments array, using this syntax:

data['payments']

and then computes the total payments.

Once the total charges and total payments are computed, the net amount due can be computed.

 

Using the [] directive to emit array instance data

 

When you are outside a scope that references array data, you can use a special syntax in the scope placeholder to display values from the scoped array.

For example, consider the following output from a template:

 

 

Showing employees from: 'Smith' to 'Programmer'
Employees

Employee name: 1 Fred Smith
skillName: 1 Javascript
skillName: 2 CSS
Count of skills: 2
Employee name: 2 Laura Linneker
skillName: 1 Xbasic
Count of skills: 1
Employee name: 3 Junior Programmer
No skills yet

 

Notice that before the Employees are shown, the template shows:

Showing employees from: 'Smith' to 'Programmer'
 

Where 'Smith' is a value from the first row in the array, and 'Programmer' is a value from the last row in the array.

In the above example, the following template was defined:

 

Showing employees from: '{employees[0].lastname}' to '{employees[-1].lastname}' <br>

{employees}

    {*header}
        <b>Employees</b><br>
    {/*header}
    Employee name: {[countOneBased]} <b>{firstname} {lastname}</b><br>
    <div style="border:solid 1px green; margin-left:50px;">
        {skills}
            {*empty}
                No skills yet
            {/*empty}
            skillName: {[countOneBased]} {name}<br>
            {*footer}
                <i>Count of skills: {@countSkills}</i>
            {/*footer}
        {/skills}
    </div>
{/employees}
 

 

Notice that outside the {employees} scope, the following template directives can be used to emit data from the employees array:

{employees[0].lastname} - 'lastname' property from the 1st array instance.

{employees[-1].lastname} - 'lastname' property from the last array instance.

 

Partial Templates - {*partial partialName}

Partial templates are named sub-templates. A template can reference these partial templates using the {*partial partialName} command. This is useful if a template has text that is repeated. For example, consider the following Javascript code:

 

//define the data

var _d = {firstname: 'Fred', lastname: 'Smith'}

 

//define the template

var arr = [];

arr.push('Welcome<br>');

arr.push('Hello {firstname} {lastname}<br>');

arr.push('{*partial partial1}');

 

var _t = arr.join('\n');

                        

 

//define the settings object (template and partials)

var settings = {
    template: _t,
    partials: {
        partial1: 'from partial1: {firstname} {lastname}<br>'
    }
}

 

//merge the data into the template

var html = A5.u.template.expand(_d,settings);

 

 

This will produce the following output:

Welcome

Hello Fred Smith

from partial1: Fred Smith

 

 

 

NOTE: Several powerful new features for templates have been added in Alpha Anywhere V3. Please consult the Release Notes for additional information.

 

 

Using the Template Tester - The Template Tester is a powerful tool to help you design and test templates.

To open the Template Tester select the Tools menu when the Web Control Panel has focus and then select the 'JSON Data Template tester' command.

This will open a modeless window where you can enter test JSON data, template definitions and Javascript functions and then see the results in real-time.

 

NOTE: The Template Tester can also be opened from within the List control builder when you are defining a template for a column in a columnar list or you are defining a free-form template.

 

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8

 

 

 

You can also click the 'Load Example' button to open a menu showing several different examples that illustrate different concepts.

 

 

 

 

Whenever you open the Template Tester, the text that you had last entered is automatically restored.

 

The A5.u.template.expand() Javascript Function - Templates are expanded using the A5.u.template.expand() Javascript function, which is part of the Alpha Anywhere Javascript library.

The syntax is

var html = A5.u.template.expand(data,settings);

 

Where data is a the data array or object to be merged into the template and settings defines the template (and any partial templates).

For example:

 

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var settings = {

    template: template,

    partials: ''

}

var html = A5.u.template.expand(data,settings)

 

 

NOTE: For an example that uses partials, see 'Partial Templates - {*partial partialName}' above.

 

A5.u.template.parse() Function - If a template is used multiple times in a component, you can pre-parse the template so that when the template needs to be expanded you can use the pre-parsed template for improved performance.

For example, take the following Javascript:

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var settings = {

    template: template,

    partials: ''

}

var html = A5.u.template.expand(data,settings)

 

The could be re-factored as follows:

 

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var parsedTemplate = A5.u.template.parse(template);

var settings = {

    template: parsedTemplate,

    partials: ''

}

 

var html = A5.u.template.expand(data,settings)

 

 

 

 

Action Javascript - Templates - Merge data into client-side template' Action - This action allows you to define a data and a template, merge the data into the template and then set the innerHTML of a div, placeholder control, or Panel with the resulting HTML.

 


Watch Video
Download Component

 

 

When you open the builder, the genie shows this screen:

 

 

You can either specify static data to merge into the template, or you can specify the name of a Javascript function that will return the data to merge into the template.

Similarly, you can specify a static template, or the name of a Javascript function that will dynamically create the template.

 

Using Client-side Templates on the Server-side - a5_merge_JSON_into_template() Function -  Because Alpha Anywhere has the ability to execute Javascript from an Xbasic script, you can actually use client-side templates in Xbasic using the a5_merge_JSON_into_template() function.

The syntax for the function is:

c Result = a5_merge_JSON_into_template(C jsonData ,C template [,C javascriptFunctions [,C partialTemplatesJSON [,C localCSS ]]])
 

For example:

 

dim data as c
data = <<%txt%
{firstname: 'Fred', lastname: 'Jones'}
%txt%

template = <<%html%
Name: {firstname} {lastname}
%html%

htmlOut = a5_merge_JSON_into_template(data,template)

showvar(htmlOut)
 

 

 

 

{grid.object}.getRowsInGrid() Method - Returns the number of rows in the current page of the grid. This is not the same as the number of rows in the Grid query.

Previously, users were using the internal ._rowsInGrid property to get the number of rows in the current page, but this value includes rows that have been deleted.

For example, say that the Grid is set to show 10 rows per page and that the refresh method is set to 'Auto' and that a minimal refresh is done after update, insert and delete operations.

If the user deletes a row from the Grid, the ._rowsInGrid property will still be 10, because the deleted row is not really deleted from the current page - it is just hidden and marked as deleted.

On the other hand, the {grid.object}.getRowsInGrid() method will return 9.

 

 

{grid.object}.getSelectedRow() Method - Returns the selected row number, or null if no row is selected.

Previously, users were using the internal ._selectedRow property to get the row number of the currently selected row. However, under some circumstances this property can return a confusing (but technically correct) value.

For example, if the refresh method on the Grid is set to 'Auto' and a minimal refresh is done after an update, insert or delete operation and the user deletes a row, the ._selectedRow property will return the row number of the row that was just deleted (which is actually correct internally, because the row that was deleted has simply been hidden in the page and it is still marked as selected).

On the other hand. the {grid.object}.getSelectedRow() method will return null, indicating that no row is currently selected.

 

 

 

UX Component - List Control - List Preview - Modeless - The List Builder has a 'Preview' button to do a quick preview of the List control while you are in the List builder. The Preview window is now modeless - which means you can keep it open while you are working in the List builder (and perhaps move it to a second screen if your computer has two monitors). This makes it very convenient to preview the List after every change you make.

Watch Video

 

UX Component - List Virtualization - Normally, when a List control is populated, the HTML for all of the rows in the List is rendered. If the list only has a few rows (say 200 rows), then there is no noticeable delay while the List is populated.

However, if the List has a lot of rows (say several thousand rows), then there will be a noticeable delay while the List is populated and also, a large amount of memory will be consumed by the List. On a mobile device where memory is more limited, the amount of memory consumed by the List could be a problem.

List virtualization allows you to only create HTML elements for a portion of the List - the portion that is currently visible and some additional rows above and below the currently visible portion. The number of rows that are rendered in the List is called the 'page' size.

When the user is scrolling the List and they hit a page boundary, the user can tap on a Next or Previous button (or optionally use a pull/release gesture) to populate the List with the next or previous page of data. It is important to recognize that tapping the Next or Previous button does not trigger an Ajax callback. It is simply rendering the next or previous page of data using the data that has already been loaded into the List and is in memory. Therefore, the time take to populate the next or previous page is practically instantaneous.

The advantage of virtualizing the List is that you can dramatically reduce the time taken to load large Lists and you can reduce the memory footprint of the List.

To turn on List Virtualization, set the Virtualization type property shown below to 'Dynamic'.

 

Watch Video
Download component

 

Once you do this, several additional properties will be shown

 

 

Virtualization type - Set to 'None' to turn virtualization off. Set to 'Dynamic' to turn virtualization on.

Size - The size property defines the 'page' size - the number of rows of data that should be rendered. This should typically be a multiple of the number of rows in the viewport. For example, say that your List can display 20 rows of data at a time, you might set the size to (say) 100 so that the user can scroll a fair amount before hitting the page boundary.

When you reach a page boundary (either on top or bottom of the page), there are 'Next' and 'Previous' buttons to get the next logical 'page' of data. The user can either tap on the Next/Previous button, or use a pull/release action to fetch the next page of data.

Max size - This is an advanced optional setting that can be used to specify a type of 'hybrid' virtualization. By default, this property is set to 0, which means that the number of rows that the List renders is always equal to the 'page' size. When you hit a page boundary, the current page is memory is replaced by the next page that is loaded.

However, if you set the Max size to -1 (which indicates that the max size is equal to the number of rows in the List), or some positive number that is greater than the size property, then when you are navigating forward and you hit a page boundary, the next page of data is automatically rendered (without requiring the user to tap the Next button). The number of rows in memory continues to grow as the user scrolls down in the List. In other words, the memory consumed by the List is initially very small (as only a single page of data are rendered) and the time taken to render the List is optimized (again, because only a single page of data are rendered), but as the user scrolls, the number of rendered rows in the List continue to grow and more memory is consumed. When the 'max size' is reached, then the user will then have to use the 'Next' button to continue to viewing additional records.

Offset - When you hit a page boundary, and click the Next/Previous button, the 'offset' indicates the number of rows from the page that is being discarded that should be included in the new view. If this number is less than the number of rows in the viewport, the List will appear to 'jump' when you navigate to a new page. It is recommended that this value be set to a minimum of the number or records that can be seen in the viewport at one time so that when the user taps the Next/Previous button, the scroll position of the List does not change. It is recommended that this number be no more than half of the 'page size'. The larger the number, the more rows the user can scroll backwards before hitting the Next/Previous buttons.


Navigate on pull - Allows the user to pull/release to navigate (in addition to tapping on the Next/Previous buttons).

Pull size - Number of pixels before the 'pull/release' gesture is recognized as a 'navigate' action.

 

 

UX Component - List Control - onBeforePopulate and onPopulate Client-side events - Two new client-side events have been added to the List control.

onBeforePopulate - fires before the List is populated. Allows you to transform the data that will be used to populate the List. The event handler gets passed in 'data' - an array with all of the data for the List.

onPopulate - fires after the List has been populated.

UX Component - List Control - Transform Data Type - Unless the List data source is a Javascript function (in which case you have complete control over the data types for each field in the List), all data in the List are string values.

 

Watch Video
Download component
 

The 'Transform data type' property allows you to transform the data type of the data in a List column to a Date, Numeric, or Logical data type.

To transform the data type, set the option in the 'Transform data type' property on the Fields pane in the List builder (as shown below).

 

 

The benefit of transforming dates into true date objects and numbers into true number objects is that you can then use the template formatting options to format date or numeric values.

For example, the template for a date field might be specfied as:

{DateOfBirth:date('MM-dd-yyyy')}

or a numeric field, the template might be specified as:

{Price:number('$# ###.00')}
 

NOTE: It is not strictly necessary to transform a string to a number in order to use the number format directive in the template. The sample template shown above ( {Price:number('$# ###.00')} would actually also work on a string value that contained a valid number.

 

 

Property Grids - Font Size - Property Grids are ubiquitous in the Alpha Anywhere builders. You can now change the default font size by selecting the View, Settings... menu item. Select the 'System Font's pane and then the 'Property Grid' category.

 

 

 

The image below shows a Property Grid with a 12 point font size:

 

 

 

word_i() function - A case-insensitive version of the word() function

Example

?word_i("alpha software corp",2,"SOFTWARE")

= "corp"

 

Web Applications - Session Object - .SaveSessionFileToFile() - A new method on the session object allows you to save a file that as previously stored as a session file to a permanent location.

The syntax is

session.saveSessionFileToFile(c Key, C DestinationFile)

 

Note: The session file might have been created in the first place using either of these methods:

 

session.saveFileToSessionFile( c fileName, c key)

 

session.saveDataAsFile( b data, c key)

 

 

Storage - Storage is an Alpha Anywhere abstraction for dealing with different types of storage using a standard interface. Currently, 3 type of storage are supported - Amazon S3, Azure and Disk storage.

Storage is used for storing files.

To work with Storage you will need a storage connection string to 'connect' to the storage object.

Named connection strings are typically used (in much the same way that named AlphaDAO connection strings are used when you connect to a SQL database).

To create a named storage connection string, select the Tools, Storage Connection strings menu item from the Tools menu when the Web Control Panel has focus.

 

 

This will open a dialog where you can create as many named storage connection strings as you want.

 

When you create or edit a named storage connection string, the Connection String dialog is shown:

 

 

Named storage connection strings are published in the a5_application.a5i file when you publish your application.

 

Summary of Helper Functions for Working with Storage - Several Xbasic helper functions make it easy to work with the storage. These helper functions are written on top of the low level storage objects that are documented here.

 

 

The helper functions are:

Examples for each of these functions is shown below.

 

 

a5Storage_saveFile() - Saves a file to storage

Syntax:

L a5Storage_saveFile(C connectionString ,C filename ,C itemName [,C mimeType [,* pResult ]] )
 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

filename - name of the local file to save in storage.

itemName - name of the object in storage. You can can specify a logical folder by using forward slashes in the name. For example: image/image1.jpg

mimeType - the mime type of the object. If you don't specify this property, the value can be inferred from the extension you assign to the itemName property.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

Example:


dim pr as p
flag = a5Storage_saveFile("::storage::Amazon_East","c:\images\4290.jpg","movies/4290.jpg","",pr)

?flag

= .T.
 

If you examine the pr dot variable that was passed into the function you will see the following properties:

hasError = .f.
timeTakenMilliseconds  = 239
AbsolutePath  = "https://<bucketName>.s3.amazonaws.com/movies/4290.jpg"
ContentType  = "image/jpeg"
ModifiedTime  = CTODT('03/15/2014 01:53:13 00 pm')
Name  = "movies/4290.jpg"
size  = 5880

 

The AbsolutePath property gives you a URL to the object. Note that in order for this URL to work you need to make sure that you have set the appropriate permissions on the storage container ('bucket' in S3 terminology).

 

 

a5Storage_saveData() - Saves data to storage

Syntax:

L a5Storage_saveData(C connectionString ,b blob ,C itemName [,C mimeType [,* pResult ]])

 

Same as a5Storage_saveFile(), except takes a blob as input rather than a filename.

 

A5Storage_getItemProperties() - Gets properties of an item in storage

Syntax:

P itemProperties = a5Storage_getItemProperties(C connectionString , C itemName)

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

 

 

Returns a dot variable with these properties

 

 

a5Storage_getItem_as_blob() - Retries data from an item in storage and put the data in a blob variable

Syntax:

b blob = a5Storage_getItem_as_blob(C connectionString ,C itemName [,* pResult ])

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 


 

Example:

dim p3 as p
b3 = a5Storage_getItem_as_blob("::storage::Amazon_East","movies/4290.jpg",p3)
?b3.size()
?p3
'= contentType = "image/jpeg"
timeTakenMilliseconds = 297
 

 

a5Storage_getItem_as_file() - Retries data from an item in storage and create a local file

Syntax

L flag = a5Storage_getItem_as_file(C connectionString ,C itemName,  C filename  [,* pResult ])

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 


 

a5Storage_listItems() - Lists items in storage

Syntax:

c List = a5Storage_listItems(C connectionString [, C searchPrefix [,* pResult ]])

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

a5Storage_deleteItem() - Delete an item from storage

Syntax:

L flag = a5Storage_deleteItem(C connectionString, C itemName [,* pResult ])

 

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

itemName - name of item to delete

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

Note: The flag value returned by this function is .f. if the connection failed, but is .t. if the item was not found in storage.

 

 

 

Web Applications - .A5W Pages - Debugging - You can now debug live running .A5w pages from within the HTML editor. The editor now has a new 'Live Preview' tab.

Simply insert a debug(1) statement in your Xbasic code and then switch to the 'Live Preview' tab pane.

 

 

UX Component - Pop-up Javascript Windows - Customize Title Direction - A new property has been added to set the default title direction for pop-up Javascript windows. By default, the direction is 'ltr' (left to right), but the direction can now also be set to 'rtl' (right to left - title on right and close button on left).

 

 

Grid Component and UX Component - Image and File Upload - Show Progress and Allow Cancel - The image and file upload features in the UX and Grid components have been enhanced.

The image below shows the File Upload window showing progress as a large file is uploaded.

 

You can now:

In order to enable this new functionality, edit your Image Upload, File Upload or File Upload - User Defined actions (defined using Action Javascript) and set the properties shown below.

 

 

 

In the case of the 'File Upload - User Defined' when the 'Allow multiple files' option is selected, the size check that takes place before the upload begins is the combined size of all selected files. You can set the maximum combined size property in the builder. The 'Maximum file size' property which applies to individual files will also be enforced after all of the files have been uploaded.

 

 

 

The Action Javascript builders allows you to specify the style for the progress bar. The 'A5' style blends in nicely with the component style, but for older styles, such as GrBlue, GrOlive, etc. the 'A5' style might be too subtle for your taste and you might prefer to use the 'Basic' style, wich uses a standard HTML progress element.

The image below shows how the slider is rendered using the 'A5' option (first slider - using the iOS style) and the 'Basic' option (second slider).

 

 

 

Grid and UX Component - HTML Editor - File and Image Upload - The File and Image upload features in the HTML editor have been enhanced.

You can now:

 

 

UX Componet - Slider Control - Displaying Progress - A new property on the slider control has been exposed that allows you to turn off the slider handle. This is useful for displaying 'progress'. In the image below the first Slider has its handle turned off.

When you want to use the slider to show progress, you should also disable it so that the user cannot change the value by clicking on the slider. For example, enter '1=2' as the client-side Enable expression for the slider.

 

 

UX Component - Tab Control - Genie Style - Genie Button Position - When defining  'Genie Style' tab controls (shows buttons to advance through the tabs), you can now specify the button position (Above or Below the Tab Panes). Previously, the buttons were always shown below the Tab Panes.

 

 

 

 

Xdialog - Edit Combo - Case-Insensitive - The edit combo in Xdialog is case-insensitive by default. You can now force it to be case sensitive using the new %CS% flag.

For example

 

dim selected as c = ""

dim colors as c

colors = a5.color_enum()

ui_dlg_box("Select Color",<<%dlg%

Color combo: [%CS%.50selected^+colors];

Color edit-combo: [%CS%.50selected^=colors];

 

%dlg%)

 

 


 

UX Component - Abstract Events - downHold Information - Click, Tab, Swipe, Etc. events now have additional information in the event's 'abstractData' object that tells you if a 'downHold' event occurred. The motivation for this additional information is to allow you to add code to Click, Tap and other abstract events to prevent them from executing their standard code when a downHold abstract event fires.

For example, if you examine the 'e' object that is available inside the event handler for a click abstract event, you will see the following information (screen shot taken from Visual Studio Javascript debugger). As the screen shows, the e.abstractData object has a property called 'downHold'. In this case the property is true, indicating that the click event has fired as a consequence of the downHold event firing.

 

 

You might then write your click event handler as follows

 

var flagRunCode = true;

if(typeof e.abstractData != 'undefined') {

    if(e.abstractData.downHold) flagRunCode = false;

}

if(flagRunCode) {

    //code you want to run in a pure click event

}

 

Code Editors - Search and Search and Replace - Regular Expressions - The Search and Search and Replace dialogs now support the ability to use regular expression. In addition, the history feature that shows previous search and replace values is now case-sensitive.

 

UX Component - Internationalization - List Controls - The UX component Internationalization genie (described later in this document), now allows you to add language and text dictionary tags to column headings for List controls.

 

 

Xbasic - Dot Variables - .data() Method - The .data() method can be used to read the value of a property in a dot variable. However, the .data() method trims trailing spaces. Now you can use an option to preserve trailing spaces by adding the '.raw' suffix to the property name.

 

delete p
dim p as p
p.name = " "

?"a" + p.name + "b"
= "a b"

?"a" + p.data("name") + "b"
= "ab"
?"a" + p.data("name.raw") + "b"
= "a b"


 

 

UX Component - List Control - Client-side Numeric Formats - You can now specify format directives in the template for the List control. For example, the image below the template for the 'longitude' column in the List.

Watch Video

 

Notice that the placeholder in the template shows:

 

{longitude:number('#.0'}

 

The numeric format is specified in the placeholder, separated from the field name by a colon.

The builder has a link labeled 'Insert format directive' that will open a genie to help you define formatting directives.

 

NOTE: In the screenshot shown below the List is a columnar List. Client-side format directives can also be inserted into the template for Freeform Layout Lists.

 

 

 

See 'UX and Grid Component - Client-side Calculated Fields - Builder' below for more information.

 

 

Xbasic - Image Metrics Class - The new Image Metrics class gets both the pixel size and the logical size of an image.
The logical size is expressed in twips, and reflects the DPI stored with the image.


Example usage:

dim isize as Helper::ImageMetrics

isize.LoadImage("jpg",file.to_blob("C:\imgage.jpg"))

? isize

..

pixel_height = 1200

pixel_width = 1920

twip_height = 18000

twip_width = 28800

 

? *unit_convert(isize.twip_width,"tw","in")

= 20

? *unit_convert(isize.twip_height,"tw","in")

= 12.5

 

 

UX and Grid Component - Action Javascript - Open Grid - The Action Javascript to "Open a grid component" now has an option to set Autorefresh on focus if the target is a TabbedUI Pane. When checked, the content in the tab pane will be refreshed automatically every time the pane gets focus.
 

UX and Grid Component - Masks - User Defined Formats - When you define a mask for an input control in either the UX or Grid you can select from a list of built-in masks, or you can define your own mask. Now, you can add your own entries to the list of built-in masks by creating a special text file in the executable folder. The text file must be called:

 

UserDefinedMasks.txt

 

The text in the file must be of this form:
 

{data=(000) 000-0000}US Phone number

{data=000-00-0000}Social Security Number

{data=00000}Zip code - 5 digit

{data=00000-0000}Zip code - 9 digit

{data=L0L 0L0}Postal Code - Canada

 

 

UX and Grid Builder - Live Preview - Caching - Previously if you made a change to CSS or linked Javascript files after previously having done a Live Preview in the builder, the changes were not always reflected because Internet Explorer was loading assets from its cache. Now, the builder is more aggressive about not caching assets during Live Preview.

UX Component - Internationalization - In order to design a UX component that adapts automatically to different languages, you typically wrap all labels in either language tags (e.g. <a5:r> ... </a5:r>) or Text Dictionary tags (<a5:t>..</a5:t>). Adding these tags to all of the text elements (such as labels, bubble help, frame labels, etc) in a large component can be quite tedious.

A new Internationalization Utility makes it easy to retrofit an existing UX component with language or text dictionary tags.

 

Watch Video

 

To access the utility, click the Menu button, shown below.

 

 

Then, select the Internationalization Helper Utilities... menu option.

 

 

This will open a dialog that allows you to select different options. Each option generates some Xbasic code that will set properties on your UX component.

 

 

 

 

TabbedUI - onTabbedUIInitialize Server-side Event - The TabbedUI Component now has a new server-side event that fires when the TabbedUI component is initialized.

TIP: You can use this event to simulate session variables when you are in Working Preview. For example:

 

if eval_valid("request.SERVER_PROTOCOL") then
    if request.SERVER_PROTOCOL = "A5RES" then
       session.var1 = "simulated value for var1"
    end if
end if

 

UX Component - Get Online Status -  {dialog.object}._getOnlineStatus() Method -  The

{dialog.object}._getOnlineStatus() method returns true if the device has an internet connection and false if there is no connection.

NOTE:   The onConnectionChange client-side event fires when the connection state changes.

NOTE: For testing how your application will behave when there is no connection, you can set your component to simulate a disconnected state by calling the {dialog.object}._setSimulatedOnlineStatus() method.

 

UX Component - Set {dialog.object}SimulatedOnlineStatus()  Method - Allows you to force the return value from the {dialog.object}._getOnlineStatus() method to be true or false, regardless of the true state of the connection. This is useful for testing purposes when you want to test how your component behaves when it is disconnected, even though you currently have a connection.

The syntax is

{dialog.Object}._setSimulatedOnlineStatus(mode);

 

Where the mode flag is


UX Component - Client-side Events - onAjaxCallbackNotAvailable Event - A new client-side event has been defined. The onAjaxCallbackNotAvailable event fires if the user tries to execute some Javascript that does an Ajax callback and the device is not currently connected to the internet.

 

UX Component - Client-side Events - onConnectionChange Event - The onConnectionChange event fires whenever the device's connection status changes. For example if the device was online and the connection was lost, the event will fire, and vice versa.

NOTE: If you set the simulated connection status using the {dialog.object}._setSimulatedOnlineStatus() method, the event will also fire (assuming that the _setSimulatedOnlineStatus() method changed the simulated online status.

 

 

UX Component - Ajax Callback Action - Offline Javascript - A new property can be set when defining an Ajax Callback. The 'Offline Javascript' property allows you to define Javascript to be called when the device is not connected. This differs from the 'Ajax failed Javascript' property in that if the device is not connected, the Ajax callback is not even attempted, and the Javascript specified in the 'Offline Javascript' property is executed immediately.

On the other hand, the 'Ajax failed Javascript' is only fired after the timeout period if a response is not obtained from an Ajax callback.

NOTE: You can also use the new client-side onAjaxCallbackNotAvailable event to specify Javascript to execute when a user tries to make an Ajax callback and there is no connection.

 

 

 

UX Component - List Control - Filter Records - Range Searches   - Using Action Javascript, you can create actions that filter the records shown in a List control. Now, you can easily make 'range' searches (similar to the Search Part in a Grid).

Watch Video

To define a 'range' search, select the control that has the 'range start' value first. Then, check the 'Range search' checkbox. A new prompt will be shown where you can specify the name of the control that has the 'range end' value.

Range searches can also be defined for actions that search embedded grids on a UX, retrieve primary keys for a data bound UK and print embedded reports.

 

 

UX Component - Absolute Layout Containers - Save as PDF - You can now create a button using Action Javascript to save the contents of the container to a PDF file.
Watch Video

To create a button to save an Absolute Layout container as a PDF, use the 'Absolute Layout Container - Create PDF' action in Action Javascript.

After the PDF is created you have the option of either:

 

 

 

 

UX Component - Control Containers - Class Name and Prevent Float - When a UX component is rendered, every control in the component is wrapped in a DIV control that has a class of 'A5CWLayout'.

NOTE: If you have set the UX 'Layout type' property to be 'ControlWidth', then the class is A5container.

The A5CWLayout (or A5container) class has two important functions:

Under some circumstances a developer might want more control over the styling of the container (a DIV) that is used to enclose each control. Two new properties have been added for most of the controls in a UX:

 

 

The 'Control container class name' property allows you to specify the CSS class name that will be used in the container DIV in addition to the standard 'A5CWLayout' (or 'A5container') class.

The 'Control container prevent float' property allows you to specify if the container DIV will use the 'A5CWLayout' (or 'A5Container') class at all.

With these two new properties you have complete control over the styling of all controls on the UX.

NOTE: For controls that are in a 'NoFloat' container, the 'Control container prevent float' property is implicitly true.

 

 

 

UX Component - Panels - .Refresh() Method - Panel Cards and Panel Navigators now have a .refresh() method. This means that if you change the contents in the header or footer of the Panel (which might change the height of a header or footer, for example), you can now call the .refresh() method to layout out the Panel again, showing the new footer or height.

 

For example:

 

var pObj = {dialog.object}.panelGet('PANELCARD_1');

//some code to change the HTML shown in the Panel header or footer

pObj.refresh();

 

 

Xbasic - CURL - Built-in Support For CURL - CURL is a popular library for calling URLs. A genie is available to convert a CURL command that you might read in some API documentation into Xbasic. To open the CURL command to Xbasic genie, right click on whitespace in the Xbasic code editor or Interactive window. The select the CURL command to Xbasic command.

 

 

 

The genie open up and you can paste in a CURL command, then click the Generate Xbasic button.

The generated Xbasic instantiates the Curl object in the extension namespace.

 

NOTE: When using the HTTPS protocol, you must have a certificate. In the sample shown below the certificate in the CARoot folder in the Alpha Anywhere executable folder is used.

 

Grid Component - SQL - Search Part - Grids Based on GROUP BY Statements - If you have defined a Grid that is based on a SQL statement that has a GROUP BY clause, interpreting what the user intends when they do a search using the the Grid's Search Part can be tricky. For example, does the user intend the submitted search criteria to be used in a WHERE clause, or a HAVING clause?

Previously, if the Grid based based on a GROUP BY statement, the SQL generated by the Search Part was added to the HAVING clause.

Now, a more flexible approach is implemented.

When you define the Search Part in a Grid, for each field you add to the Search Part, you can define the Search Expression. The Search Expression is used in the generated SQL when the user searches on this field. If the search expression uses a summary operator (for example Sum(AmountDue) ), then a search on this field will go into the HAVING clause. On the other hand, if the Search Expression does not use a summary operator (for example, AmountDue), then a search on this field will go into the WHERE clause.

As a result of this change, you can define a Search Part in the Grid that will generate SQL statements that have both WHERE and HAVING clauses.

 

Grid and UX Component - Image and File Upload - Window Position - You can now set an explicit position for the file select window in these actions:

 

Reports - HTML Content - Base64 Encoded Embedded Images - If you have HTML content in a report and the HTML content has base64 encoded embedded images, the images will now render correctly in the printed report.

UX Component - List Control - Action Javascript - List Control Actions - Client-Side Order Expression - The genie now allows you to perform multi column sorts.

Set the 'Client-side sort mode' to Advanced and then use the smart field to define the sort definition.

You can define ascending or descending sorts and you can specify whether you want to sort on the whole field, or a subset (for example, just the first character of the field).

 

This gene generates Javascript that uses the .setOrder() method of the List. For example, here is how a mult-level (Customer, Country) sort would be defined:

var listObj = {dialog.object}.getControl('LIST1');
var sortObj = {'Country' : 1 , 'City' : 1};
listObj.setOrder(sortObj);
 

UX Component - List Control - Group Breaks - Client-Side - The List control has always had a Group Break option, but this option is a server-side group break. This means that the data that is sent from the server to the browser has the group breaks physically embedded into the List data.

Now, you can define client-side group breaks. These group breaks are inserted into the List on the client-side (after the List has been populated). Client-side group breaks offer several advantages over server-side group breaks. Namely:

NOTE: One advantage of server-side group breaks over client-side group breaks is when the List data source is based on a SQL query and you have turned on the List pagination option. In this case, summary data shown in a List header will be for all of the data in that group, not just the records that are currently visible in the List.

 

In the image below, the List has two levels of grouping: Country and City. Notice that a custom style has been defined for the second level group headers (showing the city name in blue, with a left padding of 50px).

 

 

Here is the same List, but this time showing some summary data in the top level group header:

 

To turn on client-side grouping for a List, check the 'Has client-side group breaks' property for the List as shown in the image below:

 

 

You can then click the smart field to open the 'Client-side Grouping' genie.

The genie allows you to define multiple levels of grouping.

For each group you define:

 

When you define the HTML for the header or footer, you can click the smart field button to open a genie. This genie has an option that makes it easy to include summary data in the header or footer. For example, in the image below, which shows the editor for the header HTML expression, the user has clicked on the 'Insert summary field' hyperlink, and the Summary Field Genie is displayed.

 

 

When you use the Summary Field genie, the generated Javascript that is inserted into the expression calls a special helper method of the List object. For example, here is the code to compute the average of the Price column:

this.groupSummary(data,'Price:N','avg')

 

Note: The .groupSummary() method ignores NULL values in the data.

In the example below, the average is computed and then formatted using a format string

 

Number(this.groupSummary(data,'Price:N','avg')).toFormat('# ##0,00')

 

 

 

UX Component - List Navigator - When you have a lot of records in a List, scrolling the List to the bring a section of the List into view can be tedious - especially on mobile devices where there is no vertical scroll bar. The List Navigator makes it easy to scroll a List that has group breaks. In the image below a List is shown with group breaks on the first character of the Contactname field. A List Navigator is shown on the right side of the List.

NOTE: You can only display a Navigator if the List has group breaks.  It does not matter, however, if the group breaks are computed server-side or client-side.

 

 

The user can drag on the Navigator to quickly scroll the List.

The Navigator has an entry for each Group Heading.

The Navigator can be positioned on the left, right, top or bottom of the List. Positioning the Navigator on the top or bottom is generally done when the List is set to scroll horizontally.

You have complete control over the size of the Navigator (when it is not in use) and its position (relative to to the edge of the List). The size of the Navigator when it is in use (i.e. when the user is dragging on it), is automatically determined by its contents. If the size of the Navigator (when it is not in use) is not wide enough (for left/right position), or high enough (for top/bottom position) to show its full contents when the user starts to drag on it, it will dynamically resize while it is in use and then go back to the smaller size when the user stops dragging on it.

 

To define a Navigator for a List, check the 'Has List Navigator' property on the List Properties pane of the List Builder. Then click the smart field to open the genie.

 

 

 

The List Navigator builder (shown above) allows you to define a Javascript expression that determines what data are put into the Navigator. You expression can reference the special html field. The html field contains the HTML that is shown in the Group Header.

In the above screen show, the HTML expression is:

html

This means that if the Group Headers in the List contain:

A

B

C

D.....

 

The Navigator will also contain the exact same values.

But, if the HTML expression was:

html.toLowerCase()

The Navigator would contain:

a

b

c

d...

 

UX Component - List Control - Action Javascript - List Control Actions - Client-side Group Breaks - A new action has been added to the List Control Actions genie that allows you to apply client-side Group Breaks to a List. The user interface for the Genie is identical to the user interface for client-side group breaks in the List Builder. See the section 'UX Component - List Control - Group Breaks - Client-Side'  for more details.

 

UX Component - List Control - Action Javascript - List Control Actions - Show Navigator/Hide Navigator - New actions have been added to the List Control Actions genie that allow you to show a List Navigator for any list that has group breaks and to hide a previously shown List Navigator.

 

UX Component - List Control - Client Side Filter and Order Expressions - You can now define a client-side filter and order for any List. The client-side filter is applied to the data when it is loaded into the List. If you have defined a server-side filter/order, the client-side filter will be applied in addition to the server side filter/order.

 

UX Component - Lookup Columns - You can display columns in a List where the data in the column is 'looked' up in another List, or by calling a Javascript function.

Watch Video
Download Component (You will need to change the connection string for both lists to point to the sample Northwind database).

 

Consider the following example. The image shows a List based on the Order Details table in the sample Northwind database. Notice that the List shows the ProductId, but not the ProductName.

 

 

It would be nice to show the Product Description in the List, as shown in the image below:

 

Obviously this could be done by specifying a SQL join for the List data source where the Order Detail table was joined with the Products table. However, this would mean that much more data would have to be sent over the network as every row of data in the List would include the Product Description field.

A much better approach would be to 'look up' the data on the client-side as the List was being rendered. You might create a second List based on the Products table that has the ProductId and ProductDescription fields in it.

To define a Lookup, click the smart field for the 'Lookup columns' property on the 'List Properties' pane in the List Builder.

 

 

This will open the Lookup Columns genie. You can define as many lookups as you want.

Each lookup must have a unique name. The lookup type is either 'List' or 'Function'.

A 'List' lookup will lookup the value in another List. You can Link the list to the Lookup List on one or more fields.

IMPORTANT: The List that is used as the data source must appear in the UX builder before the List that references it. For example, if the OrderDetails List lookups up values in the Products List, the Products List must appear before the OrderDetails List in the UX builder.

 

A 'Function' lookup will call a Javascript function that you define and return either a single value, or an object (with multiple values). Data from the current row in the List is passed into the Javascript function. You specify what data from the current row is passed into the Javascript function by setting the 'Lookup field(s)' property in the Lookup Columns builder.

If you specify more than one lookup field (for example, 'Firstname' and 'Lastname'), the lookup fields are passed into the Javascript function in an array. If there is only one lookup field, the value is passed into the Javascript function as a string. Here is an example of a very simple Javascript function that takes an array of input values:

 

function myLookupFunction(idValues) {

    if(idValues[0] == 'John' && idValues[1] == 'Smith') return 'value1';

    if(idValues[0] == 'John' && idValues[1] == 'Jones') return 'value12;

    return 'Value not found'

}

 

 

 

Once you have defined the Lookup, the fields from the Lookup are available in the 'Available Fields' list in the List Builder.

Notice in the image above, the 'Lookup Name' was set to 'products'.

Notice in the image below the available fields include:

The 'products' prefix is derived from the 'Lookup Name'. The list of available fields includes all of the fields in the Lookup List.

 

 

 

 

 

UX Component - Buttons - Split Buttons - A new option on the Button control allows you to easily create 'split' buttons. A 'split' button has a 'button' part and a 'down' part. You can define different event handlers depending on which part of the button the user clicked on.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download components

 

To define a split button, set the 'Display as split button' property

 

 

In your Javascript event handler you can reference

arguments[1]

If the user clicked on the button, arguments[1] is set to 'normal'

If the user clicked on the dropdown arrow, arguments[1] is set to 'split'.

IMPORTANT: You can only reference the arguments[1] parameter if your code is in the button's 'onClick' event. If you use the abstract 'click' event, then arguments[1] is not set to 'normal' or 'split'.

 

 

A typical use case for a split button is to display a menu when the user clicks on the down arrow. The user makes a selection from the menu, the action is performed AND the button is updated to show the action the user selected. The next time the user wants to perform the same action, a single click on the button will perform the action (rather than clicking on the down arrow and having to select from the menu).

The relevant methods that the menu can use to update the text in the button are:

For example:

var btn = {dialog.object}.getControl('button1');

btn.setContent( { html : 'New Button Text', tip: 'Help for button', icon: 'mynewicon.jpg'});

 

In some case, when the down arrow has been pressed, you might want to open a modal window and while the window is open you might want to show the button in a 'depressed' state, For example, notice the difference in the image below compared with the image above:

 

To set the state of a button to depressed or normal, you can use the <buttonObject>.setState() method.

The syntax is:

<buttonObj>.setState( pointerToButtonElement, true/false);

where true indicates the button is depressed and false returns the button to its normal state.

For example, assume the button Id is 'BUTTON_1';

 

var bEle = {dialog.object}.getPointer('BUTTON_1');

var bObj = {dialog.object}.getControl('BUTTON_1');

bObj.setState(bEle,true);

 

 

Application Server - Security Framework - Large Applications - The time to load security framework information for large applications has been significantly improved. In a test of a large application with 5,000 pages, each of which had security settings, the the time improvement is 2 orders of magnitude. To take advantage of this change, you must republish something in your application.

If a project is published from the latest pre-release to an older application server, the older application server will report a 500 internal server error as it won't be able to read the new file. The application server should be the same build as the development program.

 

 

SQL Query Builder - Column Alias Naming - When you build a SQL query that involves multiple tables and you select a column with the same name from multiple tables, Alpha Anywhere automatically assigns an alias to the column so that it has a unique name. The alias is a numeric suffix (e.g. CustomerID1). Now, you can specify if you prefer to use a table alias in the generated column alias. To set you preference, click the Preferences hyperlink in the image shown below.

 

PhoneGap - Support for the PhoneGap Build service is now tightly integrated into Alpha Anywhere.

PhoneGap is an open source product that allows you to build native applications for mobile devices. PhoneGap Build is a web service offered by Adobe that allows you to create native applications that use PhoneGap without having to install the device SDK on your machine, or in the case of iPhone/iPad apps, without even having to use a Mac.

PhoneGap creates a native application with an embedded browser control. Your Alpha Anywhere mobile app runs in the embedded browser, but has access to all of the native features of the phone that are exposed by PhoneGap.

To bring up the PhoneGap genie, click the PhoneGap button on the Web Control Panel toolbar.

You can download the documentation for the PhoneGap Build genie here.

For more information on PhoneGap, go to http://phonegap.com/

 

Web Applications - Security Framework - SQL Databases - The Web Application Security framework allows you to store the account information for the users and groups in your security framework in either .dbf tables or a SQL database. Previously, configuring the Web Security Framework to use SQL tables was a manual process, described in the following document:

http://wiki.alphasoftware.com/Using+SQL+tables+in+Web+Security

Now, a new genie makes it easy to configure the Security Framework to use SQL tables for your user and groups list. The genie also make it easy for you switch a previously configured Security Framework from .dbf tables to SQL tables without loosing any data.

When you edit your Security Properties (by clicking the Web Security button when the Web Control Panel has focus), the dialog now has a new property called 'Security Table Type', as shown in the image below.

If you select the 'SQL' option, then when you close the Security Settings dialog, a genie is launched (see screens below) to walk you through the process. The genie will prompt for a connection string and then will create the necessary security tables in your target SQL database.

If you are switching from .dbf security tables to SQL security tables, the genie will transfer your existing data to the SQL database.

NOTE: Remember, the genie will only be started once you close the Security Settings dialog and only if you have not previously configured security settings, or you are changing from .dbf to SQL tables. If you have previously configured your Security Settings to use SQL tables and you edit your security settings, the genie will not be started when you cloe the Security Settings dialog.

 

NOTE: The genie creates new tables in your SQL database. Mapping to existing tables is not supported.

 

TIP: If you want to change the SQL database in which your account information is stored you should first convert to use .dbf tables. That will import all of your existing account information into .dbf tables. The convert back to SQL. This will then export the data in the temporary .dbf tables to the new target SQL database.

 

 

After you click the OK button to close the Security Settings dialog, the Web Security Tables Upsize Genie is started.

 

 

 

 

 

 

 

 

AlphaDAO - <connection>.ListTables() Method - Limit Tables - The .ListTables() method is now limited to 1,000 table names. This change was made because a user had a database that has over 1,000,000 tables and returning the names of all tables in the database in this case is obviously impractical.

 

AlphaDAO - ODBC Connection String - DSN Less Connections - You can now create ODBC connections that do not use a DSN.

At the Data Source Name prompt in the Connection String builder, select <None> from the list.

 

 

When bypassing the DSN, you must provide the driver name by adding Driver='' as an additional parameter:

Example:

Driver='{Microsoft Paradox Driver (*.db )}'

 

For the generic ODBC API Alpha Anywhere populates the following parameters in the ODBC connection string if the we encounter corresponding values in the Alpha Anywhere connection string:

 


Prompt            SQL_DRIVER_NOPROMPT
NoPrompt        SQL_DRIVER_PROMPT
Complete        SQL_DRIVER_COMPLETE
Required        SQL_DRIVER_COMPLETE_REQUIRED
 
See the Microsoft documentation for ODBC for a complete explanation of these options.

 

Here is an example of an Access connection string and the equivalent DSN-less connection string that Alpha Anywhere automatically creates behind the scenes when the first connection string is used.

 

Connection String using the built-in Access option in the Connection String builder:

{A5API=Access,FileName='C:\temp\Northwind.mdb',A5TraceSQL=Y}

 

DSN-less ODBC connection string:
 

{A5API='ODBC',A5Syntax='Access',A5TraceSQL=Y,Driver='{Microsoft Access Driver (*.mdb, *.accdb)}',DBQ='c:\temp\Northwind.mdb',ExtendedAnsiSQL=1,ImplicitCommitSync=Yes,UserCommitSync=Yes}

 

a5_show_htmlChrome() Function - Desktop Applications -  Opens an Xdialog window and display HTML content using the embedded Chrome browser. Contrast with the existing a5_show_html() function that uses the IE activex control.

For example, consider the following script in a desktop application

 

dim html as c

html = <<%html%

<b>Hello World</b>

%html%

a5_show_htmlChrome(html)

 

 

UX and Grid Component - Styles - iOS7 and Android - New styles are included for iOS7 and Android. For Android, two styles are included - AndroidDark and AndroidLight.

 

IMPORTANT: If you are converting an existing component that previously used the iOS style to iOS7, AndroidDark or AndroidLight you will notice that the 'disclosure icons' on the right edge of your List controls do not render properly. Also, if your component was built using the Demo Mobile App that ships with Alpha Anywhere, the Menu List control might not render properly. Here is how to fix these two issues.

To fix the List template, edit the template and replace the disclosure icon in the template with {images.dialog.listNavSubtle} or {images.dialog.listNav}. The fixed HTML will then look like this:
<img src="{images.dialog.listNavSubtle}" />

To fix the Menu List, edit the Window container that contains the Menu List and check the HTML template in the Header HTML property. This property is in the Optional Window Parts section. Edit this template and make sure that the following HTML markup exists at the end of the template HTML:
<br style="clear:both;">

 

 

   

 

A particularly attractive feature of these new styles is the way that the icons in the style are rendered. Instead of using bitmaps for the icons, the styles use CSS Icons (also called Font Icons because the icons are all included in a special font file that is included as part of the style).

See below for more information on CSS Fonts in general and on Font-Awesome in particular. Font-Awesome is an open-source Font Icon that is now bundled with Alpha Anywhere.

 

 

UX, Grid and TabbedUI Components - CSS Icons (Icon Fonts) - Support has been added for CSS Icons (also know as Icon Fonts) - Icon fonts have become very popular, especially for mobile applications because they scale smoothly, and are smaller than bitmaps. Also, there are many libraries of icon fonts that can be used with Alpha Anywhere.

In the image below, the two icons in the buttons are both CSS Icons rendered using the Icon Fonts that come with the iOS7 style.

 

An icon font is just a regular font, excepting that instead of displaying characters, such as 'a', 'b', 'c', etc., the font has icons at each character position. So, assuming that the font defines a 'save' icon for character 'a', then in order to display the 'save' icon on your component, you would display the character 'a', and set its style to use the Icon Font.

Remembering that the 'save' icon corresponds to the character 'a', would be tedious, so a corresponding CSS file is defined. This CSS file has two main purposes:

For example, the CSS might define a rule called 'icon-save' that indicates what character the 'save' icon is mapped to.

When defining an image for a control (for example a button), you would indicate that the image name is:

cssIcon=icon-save

 

When the component is rendered the HTML markup, might look like this:

<img src="cssIcon=icon-save" />

 

This HTML markup is then automatically translated by Alpha Anywhere to:

<i class="icon-save"></i>

which correctly renders the icon using the appropriate character in the Icon Font.

 

You can also define an inline style for the CSS Icon. For example, if you define the image name as:

cssIcon=icon-save {color: blue;}

then, when this is translated automatically, the HTML becomes:

<i class="icon-save" style="color: blue;"></i>

 

UX, Grid and TabbedUI Components - Font-Awesome Icon Font Library - Font-Awesome is a popular open-source icon font library. Alpha Anywhere now comes with Font-Awesome pre-installed. The Font-Awesome library is installed in the CSSIcons folder in the folder where the Alpha Anywhere executable is installed.

For more information on Font-Awesome, please go to:

http://fontawesome.io

 

Watch Videos - Part 1

Watch Videos - Part 2

Watch Videos - Part 3

 

In order to use any icons in the Font-Awesome library, (or in any 3rd party CSS Icon Library) you must set a property in the UX, Grid or Tabbed UI builder to indicate that the library should be loaded. Click the smart field button for the CSS (Font) Icons property to open the dialog that allows you to select which CSS Icon library you want to load.

 

 

NOTE: When you close the 'Select CSS Icon Libraries to Load' dialog shown in the above image, the library files are copied from the CSSIcons folder in your executable folder to the CSS folder in your Web Project. Because the CSS Icon library files are then part of your Web Project, they will be automatically published when you publish your application.

 

Once you have indicated the libraries that you want to load, any time you are prompted for the name of an icon, you can select a regular bitmap, or a CSS Icon. For example, note the 'CSS Icon' option on the Image selector:

 

 

If you select the CSS Icon option you can select the icon source. If you are using a style that uses icon fonts (for example the iOS7, AndroidLight, or AndroidDark styles), the ImageSource list will show <Style> as an option.

The Image source list will always include 'Font-Awesome' since this library is bundled as part of Alpha Anywhere. But the list will also include any other libraries that you have installed. See section below on installing 3rd party CSS Icon font libraries.

To select an icon, click the Select button to open the genie:

 

 

The genie allows you to easily filter the list to quickly find a particular icon. You can specify the size of the icon using the dropdown 'Size' selector. If you select 'Custom' , then you can use the slider to select any size you want.

As you can see in the image below the icons scale smoothly, even when displayed at a large size - 127px in the image below.

 

 

You can also specify the color, CSS classes or in-line style to apply visual effects to the icon. For example:

(In the example below, the style for the Icon has been set to:

border: solid 3px; border-radius: 20px; padding: 4px;

)

 

 

 

CSS Icon Libraries - Installing 3rd Party Libraries - There are many sites on the web that supply Icon fonts and the accompanying CSS file to load and select icons from the font.

You can generally use any of these third party libraries as long as the accompanying CSS file for the library uses the convention of displaying the icon use the HTML <i> tag.

For example, to display the 'heart' image from the Font-Awesome library, the HTML markup is:


<i class="fa fa-heart"></i>

 

If the library you want to install uses the same conventions, then it can be used in Alpha Anywhere.

To install a 3rd party CSS Icon library, simply copy the folder that contains the CSS and font files for the library into the CSSIcons folder in the Alpha Anywhere executable folder (development version, not Application Server), and then 'install' the font (so that it can be used in Working Preview). See below for information on 'installing' fonts.

A popular source of icon fonts is http://www.fontello.com/

This site allows you to select icons from a menu of available icons and it then builds a custom icon font which you can download. After you download the files, just copy the folder into the CSSIcons folder in your executable folder.

Watch Video - Installing a 3rd Party CSS Icon Library


Registering the Font For Use in Working Preview

Icon fonts are loaded dynamically by the CSS file when you are in Live Preview or running your published application. However, when you are in Working Preview, in order to see the icons in the icon font, you must have previously 'installed' the font. Installing a font is easy. Just open the folder for the CSS Icon library. Look for a file with a .ttf (true-type font) extension (it will often be in a sub-folder called 'Fonts') and double-click on the .ttf file.   Windows will bring up a dialog that has an Install Font button. Click this button. It will install the font so that it can be used when you are in Working Preview.

 

UX Component - List Control - Menu Lists - A common pattern in mobile applications is to use a List control as the menu. This list control is then displayed in a Panel Window that animates in from the Left side of the screen. Icons are typically displayed for each menu choice. The CSS Icons are ideal for these types of icons.

Watch Video

A new pre-defined control is available in the Defined Controls section of the toolbox.

 

 

TIP: If you are building a mobile application, rather than using the pre-defined List Menu, you might find the pre-defined SplitView examples more helpful. These are available by selecting 'QuickPanels' from the 'Panels' category in the UX Toolbox on the left of the UX builder. See  'New SplitView Examples' below for more information.

 

 

Selecting this option will produce a List control like this:

 

If you edit the List properties for the above List, you will notice that the control type for the icon field has been set to CSSIcon. See topic UX Component - List Control - Using CSS Icons below for more information.

 

 

UX Component - List Control - Using CSS Icons - You can now easily use CSS Icons in a List. A new Control type property is available on the Fields tab of the List Builder.

In the image below, the control type for the Image column has been set to CSSIcon.

The data in this List's Data Source could be something like this (using CSS Icons from the Font-Awesome library in this case):

MenuName|Image|Action
Menu One|cssIcon=fa fa-heart fa-2x|action1
Menu Two|cssIcon=fa fa-music fa-2x|action2

 

Notice that in the 'Image' column, the name of the CSS Icon is specified (including the cssIcon= prefix).

You can also use in-line styles or your own classes to style icons. For example, here is how the data could be represented using an in-line style for the icon in the first row and a custom class for data in the second row:

 

MenuName|Image|Action
Menu One|cssIcon=fa fa-heart fa-2x {color: red;}|action1
Menu Two|cssIcon=fa fa-music fa-2x myiconclass|action2

 

 

 

If your list uses a Free-form template, you can put a CSS Icon directly in the template using this HTML markup:

<i class="fa fa-heart fa-2x"></i>

 

Tip: You could just as easily add the following HTML markup to your template:
<img src="cssIcon=fa fa-heart fa-2x" />
and at run-time Alpha Anywhere will translate the <img> tag to the correct <i> tag (because the src attribute of the <img> tag starts with 'cssIcon')

 

 

UX Component - Mobile Applications - SplitView - Pre-Defined Quick Start Templates - A typical mobile application often includes a 'menu' panel that allows the user to navigate to different parts of the application. A common pattern is to use a 'split-view' with the menu in the left Panel and the main work area of the application in the right Panel. The menu is hidden on a phone (where screen space is limited), but shown on a tablet (where more screen space is available). If the menu is hidden, tapping on button in the PanelHeader, or swiping to the right, will reveal the menu.

In the images below, the UX is shown as it appears on a phone and a tablet. Notice that on the tablet, the menu is always visible and the button in the PanelHeader (shown when the UX is on a phone) is automatically hidden.

 

Watch Video - Part 1

Watch Video - Part 2

Watch Video - Part 3

 

 

 

 

If you want to use the pattern described here, you can select add a pre-defined set of controls to your UX component by selecting 'Quick Panels' from the UX toolbox.

 

Then select '{Predefined:SplitViewWithIconsAndPanels}'

 

 

UX and Grid Component - Client-side Calculated Fields - Builder - When you open the Builder to define a client-side calculated field, a new hyperlink appears on the dialog - 'Format String'. This hyperlink opens a genie that can be used to define the format string for the new FormatNumber() function which can be used in your client-side calculated fields to format numeric values.

 

When you click the Format String hyperlink, a genie opens to help you define your format string:

 

 

UX and Grid Component - Client-side Calculated field - FormatNumer() function - Client side calculated fields can now use a new psuedo function, formatNumber() to format a numeric field.

For example:

formatNumber(num1,"#,###.00");

The format string is very similar to the syntax used by Excel. For information on the syntax for format strings, see the section 'Number Format Strings' below.

NOTE: When you use the formatNumber() pseudo function in a client-side expression, the function gets converted to the following Javascript:
            number.toFormat('formatString')

where 'number' is any Javascript numeric variable. The Alpha Anywhere Javascript library adds a .toFormat() method to the prototype for numeric objects.
 

 

UX and Grid Component - Number Format Strings

 

Number format strings are used in the .toFormat() method of numeric variables and in the formatNumber() function when defining a client-side expression in a Grid or UX component.


A number format string can have multiple formats in them by using a ";" to separate multiple formats. The way a given format in the format string is selected is based on either its location in the string, or by an optional condition.

If the format string doesn't contain any conditions then the first format will be used for a positive value, the second for a negative, and the third for a zero value.

Conditions can be put into the format by making the first part of the format string contain if(expression) where n equals the value of the number. For example:


if(n>999999999)=(###) ###-####;=###-####
 

is a multi-format string that the will return numbers greater than 999999999 as a 10 digit phone number mask and number less than 999999999 as a 7 digit phone number mask.

You can also optionally process a number before it is formatted by adding =(expression) onto the end of a format string where n equals the value of the number. For example:

##0.00 %=(n*100)
 

is a format string that will first multiply the number by 100 before outputting it with the format. A value of '.254' would be returned as '25.40 %'

A number format can be either of two types: a "number" or a "mask" format.

A mask format is indicated by the first character in the format being an = sign. The # character in the mask will be replaced with the first available digit from the number. An example of a number format for a 10 digit phone number is:


=(###) ###-####
 


Using the above mask, the number

8004511018

would be formatted as:

(800) 451-1018



While 'masks' are simple, 'number' formatting can be more complex. Below is a list of the special characters that can be used in a 'number' format string:

 

Character Description
# an optional digit
0 a required digit (will be output as "0" if no value in the number for the given location)
_     (an underscore character) an optional digit (will be output as  " "  if no value in the number for the given location)
* after the decimal character will cause there to be no rounding (number if output with its full precision)
] at end of a number format (before any suffix) means round to zero (there will be no decimal value)
[ with "]" means force "0" for integer places in the number (e.g. 123 formatted with #[00] would be 100)
< at end of a number format (before any suffix) means round decimal up, before "]" is the round up equivalent of "["
> at end of a number format (before any suffix) means round decimal down, before "]" is the round down equivalent of "["
-/- display decimals as fractions


After optional conditions and number processing expressions have been removed from the format string, any non-special characters at the beginning and end of the format string are placed into the prefix or suffix. If a format string does not contain multiple formats for positive and negative values, a '-' (minus sign) will be appended to the start of the result if the number is negative.

Examples

 

Number Format String Result Description
1256.2 # ##0,00 1 256.20 use a " " to separate thousands and a "," for the decimal, round to two decimal places and force "0" for those two decimal places
.257 0.00> 0.25 pad the integer part with a "0" and use a "." for the decimal, round down to two decimal places.
1256.2 #,#[00] 1,300 clip to two integer places and use a "," as thousands separator.
1256.2 #,#>00] 1,200 clip to two integer places, round down, and use a "," as thousands separator.
1256.2256 #,##0.* 1,256.2256 use a "." for the decimal and a "," for the thousands separator, don't round the decimal.
1.256 0.##> and -/- 1 and 1/4 round down to two decimal places and render the decimal as a fraction in the suffix
1256.2 $#,##0.00;$ (#,##0.00);------ $1,256.20 multiple format strings for positive, negative and zero value. The thousands separator is "," and the decimal character is ".". Number if rounded to 2 places. Negative value is enclosed in parentheses. Zero value is output as "------"
4
3
1
if(n>=4)# (Good);if(n>=2) # (Average);# (Bad) (Good)
(Average)
(Bad)
render the number with a custom suffix based on a condition. For example, if the number if 4, the output value is (Good). If the number if 1, the output value is (Bad)
 
1256.2 #[0] 1260 round to 10, integer only
1256.2 #[00] 1300 round to 100
1256.2 #[000] 1000 round to 1000


 

 

 

UX Component - Ajax Callback - Timeout Setting - You can now specify an explicit value for the Ajax callback timeout. This is the amount of time to wait (in milliseconds) for the response from the Ajax callback. If the response is not received within the specified the, the callback is considered to have failed and the 'onAjaxCallbackFailed' event is fired and any code defined in the optional 'Ajax failed Javascript' property is executed.

Previously, the timeout setting used the default value set by the browser.

If you set the property value in the dialog shown below to <Default>, then a default value for the component is used. This default can be defined by adding code like this to the UX component's 'onRenderComplete' client-side event:

{dialog.object}.ajaxCallbackTimeout = 1000;

 

If you set the property value to 0, the default value as defined by the browser is used.

 

 

 

 

 

UX Component - Action Javascript - Ajax Callbacks - Cross-Domain - Because of security issues, browsers typically enforce a policy that requires that the page that responds to an Ajax callback must be loaded from the same domain that the original page was loaded. This does not represent a problem for typical Ajax callbacks that are handled by Xbasic code on the server.

However in cases where you want to call a web service directly from the client (without first going to the Alpha server), it does represent a problem.

Consider for example the following scenario:

Say you have a button on the UX and you want to make a call to the Apple iTunes store to retrieve information about a book.

The URL for this web service (including the query string for the particular book you are interested in) is as follows:

http://itunes.apple.com/lookup?isbn=9780316069359

 

The domain for this URL is obviously not the same as the domain from which the UX component was loaded in the first place.

There are two ways in which you could call this web service:

Clearly, the second approach is more desirable as it avoids hitting the Alpha server at all.

However, in order to implement the second approach you need to perform a cross-domain Ajax callback.

The new 'Ajax Callback - Cross Domain' action in Action Javascript allows you to perform cross-domain Ajax callbacks.

TECHNICAL NOTE: The Ajax Callback - Cross Domain action is built on top of jQuery. You must load jQuery core for this method to work. See the Web Project Properties dialog to enable jQuery.

 

When you define this action you specify the URL of the callback page. Any parameters that you want to pass in to the web service are in the query string. When you specify the URL, you can specify an explicit value, or any Javascript expression that evaluates to the URL. This allows you to dynamically construct the URL for the callback.

You also specify the name of a Javascript function that will be called when the Ajax callback completes successfully. The function gets passed an argument that contains the data retuned by the callback.

NOTE: Unfortunately, if the callback fails, there is no way to specify an 'onFailure' function. This is a limitation of the technique used for making cross-domain callbacks.

A useful technique for seeing what data in passed to the success function is to define  the following success function for your action:

 

function mySuccessFunction(data){
    alert(JSON.stringify(data,'','\t'));
}

 

This function will convert the data returned by the callback into a JSON string and display it.

 

 

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

 

 

UX and Grid Component - Client-side Expressions - New Round() functions - In build 1788-4225 new options were added to the $u.n.round() function in the Alpha Anywhere Javascript library. These options allowed you to specify if the rounding was:

However, when using the client-side expression builder, there was no way to specify which option you wanted to use when you used the round() function.

Now, these new functions can be used in your client-size expressions:

 

 

HTML Reports - Export to Excel, Word or PDF - beforeHTMLReportExport event - A new client-side event has been added to the UX, Grid and Tabbed UI components. This event is fired when an HTML report is displayed and the user clicks one of the buttons on the report toolbar to export the HTML report to PDF, Word, Excel or Text mode. The main motivation for this event is to allow the developer to put up a custom wait dialog. The afterAjaxComplete event can be used to dismiss the custom wait dialog.

 

 

UX Component -  List Control - Buttons and Hyperlinks - Set Focus Property - Buttons and Hyperlink controls now have a new property called 'Set Focus'. By default, when you click on a button or hyperlink in a List row, the row that contains the button or hyperlink does not automatically get selected. Now, if you check the 'Set Focus' property, when you click the button or hyperlink, the corresponding row is also selected.

 

Grid Component - Edit-Combo and Auto-Suggest Controls - NotInList Event - Added support for the NotInList event for edit-combo and auto-suggest controls in Grids. This event fires when the user enters a value that is not in the list of choices. The typical use case for this event is to write code to add the value that the user entered to the table that contains the choices so that in future, the value that was entered can be presented in the pick list.

UX Component - Javascript Controls - 'Initialized' property - All Javascript controls on a UX (for example, List, SpinList, ButtonList, Switch, etc.) now have a new 'initialized' property. Consider the following example that explains why this property is useful:

Assume you have a List control and you have unchecked the 'Allow Null selection' property. This means that when the List is rendered, the first row in the List will be automatically selected and the onSelect event of the List will fire.

Assume that in the onSelect event you reference some property of the List that does not yet exists because the List has not yet been fully initialized. Your code will generate a Javascript error. Using the new 'initialized' property, you can write your onSelect event as:

 

if(this.initialized) {

        //your onSelect event code goes here

}

 

hmac_hash() Function - The hmac_hash() function is primarily for internal use in situations where OAuth authentication is used. The function is exposed to Xbasic as it might be useful to developers.

?hmac_hash("alpha anywhere","secret","HMACSHA1",.F.)

 

Grid and UX Component - .runAction() Method - Javascript Actions - Passing in an Object Reference - The .runAction() method now takes an optional second argument which is a pointer to an element on the page. The use case for the parameter is described below.

Assume you used Action Javascript for a button to open a window that was positioned relative to the button. If you examine the generated Javascript code, you will see that the Javascript in the button's onClick event passes in 'this' - a reference to the button. Therefore the windows can be positioned relative to the button.

However, if you define the exact same action as a Javascript Action, and then try to invoke the Javascript Action from a button (using the .runAction() method in the button's onClick event), you will get a Javascript error because the code that tries to position the window does not have any reference to the button.

Now, by passing in a reference to the button when the .runAction() method is called, the window can be positioned.

For example

{dialog.object}.runAction('myaction',this)

 

 

*property_filter() Function - Takes a .dot variable and filters out certain properties. The 'filter' specification is a cr-lf delimited string of directives that can include wildcard characters and a leading - sign to indicate that a property should be removed.

For example consider the following .dot variable:

 

 

dim prop.firstname as c
dim prop.lastname as c
dim prop.company as c
dim prop.age as n

 

'this filter selects the properties 'firstname' and 'age'

dim filter as c

filter = <<%str%
firstname
age
%str%

 


prop =  *property_filter(prop,filter)

?prop
= age = 0
firstname = ""

'this filter removes the 'firstname' property, selects all properties

'that end in 'name' and all properties that start with 'comp'

filter = <<%str%
-firstname
*name
comp*
%str%


prop = *property_filter(prop,filter

?prop
= company = ""
lastname = ""

 

 

 

property_from_url() Function - Parses a URL query string into an Xbasic .dot variable.

Syntax:


property_from_url(prop as p,url as c)

 

 

Example:

dim p2 as p
property_from_url(p2,"firstname=john&lastname=smith&company=ACME%20Industries")
? p2
= company = "ACME Industries"
firstname = "john"
lastname = "smith"