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 V4.12  -Build 3603-4668 13-May-2016

Features

UX Component - List Control - Export - Select Columns to Export - A new option has been added to the 'Export List data to Excel/Ascii' action to allow selection of the List columns to export.

To export only selected List columns you must first specify settings for the 'Customize field sizes and column headings in export file' property and then ton the 'Only export columns for which customize options are defined' property.

 

 

PhoneGap App Builder - Generate App Zip File - A new option has been added to the PhoneGap Builder to create a zip file that contains all of the files and assets required to build an iOS, Android or Windows Phone app on PhoneGap Build.

The use case for this option is that in some organizations, access to the API that Alpha Anywhere uses to communicate with the PhoneGap build service is blocked and therefore, in order to build a PhoneGap project it is necessary to visit the PhoneGap site in a browser and then upload a .zip file from the user interface presented by the browser.

When you select this option, you can specify the folder location to allow easy access to the file. The zip file is named with the app name specified in the PhoneGap Builder.
 

The zip file can be uploaded directly to https://build.phonegap.com to update an existing project or to create a new project on PhoneGap Build. The ability to easily upload the app zip file is helpful when the development machine is located behind a secure firewall that does not allow access through to PhoneGap Build through the PhoneGap Build API which is used by the Alpha Anywhere PhoneGap App Builder.

 

Bugs
 

UX Component Crash - An error was introduced in the previous build that, under certain circumstances, would cause a UX to crash. The pattern for the error message shown when the crash occurs was:

wfNew.<some variable name> = wfOrig.<some variable name>

 

Alpha Anywhere V4.11  - Build 3596-4665 10-May-2016

Features

SVG Icons - Slow Loading - If you defined a large number of SVG icons in a component, the component was slow to load.

 

Bugs

Security Framework - A recent change in a security function broke the security show /hide on legacy components built in early versions of Alpha Anywhere and previous Alpha versions.  A workaround was to use the bulk update process to Update component security settings and republishing.  It is now not necessary to use the workaround.
 

 

 

Alpha Anywhere V4.1  - Build 3583-4662 03-May-2016

UX Component - List Control Search Highlighting When you perform a server-side search to filter records in a List you can highlight the matching characters in each record. This makes it easy to see why the record was included in the search result.

Watch Video

Date added: 2016-04-24
UX Component - PhoneGap Sending Push Notifications using the Pushwoosh Service A common feature in mobile applications is push notifications. In a PhoneGap application, this can be be done, utilizing the Pushwoosh plugin, which integrates the Pushwoosh service.

This video shows an example application that uses push notifications.

Watch Video

PhoneGap Push Notifications

Date added: 2016-04-28
SVG Icons Introduction to SVG Icons SVG Icons have many benefits over bitmap images and font icons. In this video we introduce you to SVG icons and show how they can be used in your components.

Watch Video

Date added: 2016-05-01
SVG Icons Search the Web for SVG Icons and Importing into Components There are a large number of free SVG icons available for download on the web. In this video we show how you can download SVG files from a site that specializes in SVG images and then import the SVG files for use in your components.

Watch Video

Date added: 2016-05-01
SVG Icons Converting Locally Defined SVG Icons to Linked SVG Files SVG icons can either be defined within a component, or they can be stored in physical files that are linked by your components. The advantage of using linked files is that  many components can share the same SVG icon definitions. In this video we show how you can easily convert locally defined SVG into a file of SVG icons that can then by linked by many components.

Watch Video

Date added: 2016-05-01
SVG Icons Using SVG Icons in a List Control on a UX Component A common pattern in mobile applications is to use a List control as the menu for the application. It is common to use icons in the menu List. In this video we show how SVG icons can be used in these menu Lists.

Watch Video

Date added: 2016-05-01
UX Component - PhoneGap Sending Push Notifications using the Pushwoosh Service A common feature in mobile applications is push notifications. In a PhoneGap application, this can be be done, utilizing the Pushwoosh plugin, which integrates the Pushwoosh service.

This video shows an example application that uses push notifications.

Watch Video - Part 1
Watch Video - Part 2


Documentation - PhoneGap Push Notifications

Date added: 2016-04-28
     

 

Features

 

 

SVG Icons - The Grid, UX and TabbedUI components now support SVG icons.

 

Introduction to SVG Icons -  Video

 

SVG icons have several very important advantages over traditional bitmap icons. Namely:

While the same advantages are also true of font icons, which Alpha Anywhere has supported for some time now, SVG icons are easier to work with than font icons.

An additional benefit of SVG icons over font icons is the ability to support colored icons. With a font icon you can specify a color for the entire icon - but not for different aspects of the icon. In other words, a font icon is always green, red, yellow, or whatever color you specify. Whereas an SVG icon can be mostly green, red, yellow, or whatever color you specify for the 'fill' and 'stroke' color, but certain parts of the icon can be hard-coded as a particular color.

There are a large number of freely available SVG icons on the web. A particularly good source of free SVG icons is http://www.flaticon.com/

 

In the screen shot below, two different icon sets are shown in the SVG Image picker. These icons were imported from icon sets on www.flaticon.com. As the image shows, the second icon set is richly colored.

 

 

 

 

In this next screenshot the icons are shown at a much larger size. As you can see, the icons scale smoothly.

 

 

 

 

There are two ways to use SVG icons in a component:

To use locally defined SVG, you set the Local SVG definitions property in the CSS/SVG section in the component builder. To use linked SVG files you set the SVG Linked files property in the CSS/SVG section in the component builder.

 

 

Locally Defined SVG

When you open the builder for Local SCG definitions you get a screen where you can enter the SVG definitions. For example:

 

 

As you can see, the SVG definition looks quite formidable, but this is largely irrelevant because the SVG will, in almost all cases, be generated by importing SVG files that you have downloaded, or will have been created by an SVG authoring tool that you use.

 

 

How to Import SVG Files

 

Watch Video

 

Once you have found a source of SVG icons on the web that you want to use in your components, you will need to import the SVG. To import SVG files:

  1. Open the builder for  Local SVG definitions
  2. Click the Import folder of SVG files hyperlink
  3. Specify the name of folder where the SVG files that you downloaded are stored
  4. Specify an icon prefix name. This name will be used as the prefix for each SVG icon in the SVG Icon Selector.

After you import the SVG into the builder, you might want to manually edit the SVG. The most common type of edit you might want to perform on the imported SVG is to change the fill and stroke color on the SVG icons. Click the Understanding SVG Icon colors hyperlink for more information on this subject.

 

Converting Locally Defined SVG to Linked SVG

 

Watch Video

 

After you have imported SVG files into Local SVG definitions, you might want to convert the SVG that is locally defined, into a SVG file that is linked. The main reason for doing this is so that other components can use the same SVG icon definitions.

To do this, click the Convert to Linked SVG hyperlink on the dialog while you are editing the local SVG definitions..

 

Syntax for Specifying an SVG Icon

When you use a SVG icon in a component (for example as the image on a button, or in a List control, or as the image to display in a Dynamic Image control), you use a special syntax (generated automatically by the image picker). For example:

svgIcon=#svg3_safebox:52 {fill: red}

 

This syntax is very similar to the syntax used for CSS font icons. For example:

cssIcon=fa fa-heart fa-2x

 

In the case of the SVG icon, the prefix is 'svgIcon' and in the case of the CSS font icon, the prefix is 'cssIcon'

In the above example, the SVG icon is being displayed with a size of 52px and a fill color of red. The icon name being displayed is 'svg3_safebox'. Notice that the icon name is prefixed with a hash character.

 

 

Printing Ink Annotation over a Picture in a Report - a5_composite_picture_and_ink() Function -

If your database has picture fields and ink fields that were used to annotate pictures you might want to print a picture field with the ink annotation shown directly over the picture.

This is done by creating a calculated field that uses the special a5_composite_picture_and_ink() function.

This function takes the name of the field that contains the picture, the name of the field that contains the ink and (optionally) a base path. The base path is only needed if the picture field contains relative a relative filename. The base path is used to convert the relative image filename into an absolute filename.

a5_composite_picture_and_ink(c pictureFieldName, c inkFieldName [, c basePath])

For example, assume that your database has fields called picture1 and annotation1 and you want to print the ink in annotation1 over the picture in picture1. You could create a calculated field called compositeImage, defined as shown below, and then add this calculated field to your report.

compositeImage = a5_composite_picture_and_ink("picture1","annotation1")

 

 

 

 

PhoneGap - UX Component Template - Secure Login With Location Tracking And Pushwoosh Notifications -  This new UX component template is a mini-app that is designed to introduce developers to the power of using native push notifications with Alpha Anywhere and the Pushwoosh service.



The app offers user login and location check in and check out for a mobile worker. When the user logs in or out, an admin user is sent a push notification that includes the user name and the date and time the user logged in or out of the app. When the user checks in or out of a location, a marker is placed on a map, the lat/lon is reverse geocoded with the Google Geo-location API to determine the exact address and a push notification is sent to the admin user. The admin user is identified in a Pushwoosh filter called Admin. This allows the admin user to receive push notifications to track all activity within the app.

For a video overview of this component template, click the link below.
Video overview of the Secure Login With Location Tacking And Pushwoosh Notifications

To view the help documentation click the link below.
PhoneGap Push Notifications

 

 

UX Component - List Control - Search Highlighting - When you perform a server-side search on the records in a List control (using the 'Filter records in a List' action in Action Javascript), or you apply a filter from a List's Search Part (either server-side or client-side) you can now highlight the characters in each record that were matched by the search. This makes it easy to see why a particular record was included in the search result.

Watch Video

 

For example, in the image shown below, the table were searched for all records that contain the string 'manager' in the 'Contacttitle' field.



To turn on search highlighting, edit the List and check the Search highlight property, as shown in the image below. You will then be able to set the class name and in-line style to apply to the highlight characters.

 

 

 

UX Component - AudioPlayer and AudioRecordAndPlayer Controls - Events - Added event hooks to these controls.

 

 

 

Action Javascript - PhoneGap - File System Actions - A new action is now available in Action Javascript. The PhoneGap - File System Actions (Fire URI Based) is similar to the  PhoneGap - File System Actions action in that they both allow actions such as read file, write file, create directory, delete directory, read directory, etc.. The key difference is the the File URI Based actions give you explicit control over which part of the device's file system the operations are performed in.

The PhoneGap - File System Actions  actions operate on files in a default location, whereas the PhoneGap - File System Actions (Fire URI Based) actions allow to specify an explicit file location.

 

 

 

SQLite Database  - Indexes - PhoneGap - When you use Action Javascript to construct a SQLite database you can now specify that indexes should be build for each table in your SQLite database. You can add as many indexes as you want. For each index you can define the columns used in the index.

Sending E-mail Using the SparkPost Service - email_send_SparkPost() Function - You can now use an Xbasic helper function to send e-mail using the SparkPost service. This service is similar to the Mandrill service. You must first go to sparkpost.com to get an API key. You will also be required to verify your ownership of you sending domain.

Once you have your API key and you have verified your domain ownership you can send e-mail in much the same way that you may have used the email_send_mandrill() function.

NOTE: Currently the email_send_sparkPost() function does not expose the ability to use merge variables in the HTML message. If you need this functionality, you must compose the message JSON manually. Refer to the SparkPost documentation.

 

Syntax

p Result = email_send_sparkpost( c key, A message)

 

Where

 

Example:

 

dim ms as p
ms.send_to = "john@acme.com:Optional friendly name for John Smith,sally@acme.com"
ms.from_email = "sendername@acme.com"
ms.from_name = "Sales at Acme" 'friendly name - optional
ms.subject = "Information You Requested"
ms.message_html = "Here is the <b>information</b> you requested."
ms.message_text = "Plain text version of the message"
ms.attachments = "c:\alphasports\invoice.pdf,c:\alphasports\vendorlist.pdf"
dim key as c = "your sparkpostkey"
pp = email_send_SparkPost(key,ms)

 

 

You can optionally define attachments using an array syntax. Instead of defining a property called ms.attachments which has a comma delimited list of files to attach, you can define an array as shown in the example below::

 

dim ms.attachmentsArray[1] as p
ms.attachmentsArray[1].name="report.pdf"
ms.attachmentsArray[1].type=resolve_mime_type("pdf")

ms.attachmentsArray[1].content=base64encode(file.to_blob("c:\myfiles\invoice.pdf"))
 

 

In the body of your HTML message you can optionally include in-line images. To define in-line images you can either use a property that specifies a comma-delimited list of image filenames, or you can use an array syntax:

 

Array syntax:

dim ms.inlineImagesArray[1] as p
ms.inlineImagesArray[1].name = "myimage1.jpeg"
ms.inlineImagesArray[1].type = resolve_mime_type("jpg")
ms.inlineImagesArray[1].content = base64encode(file.to_blob("C:\Images\4296.JPG"))
 

Comma delimited filenames syntax:

 

ms.inlineImages = "c:\movieImages\4296.jpg|myimage1.jpeg"

 

Notice that the comma delimited names syntax specifies the image name (the name by which you will refer to the image in the HTML body) with a | delimiter. In the above example, the image name is 'myimage1.jpeg'

 

To use the in-line images in the HTML message body, you use this syntax:


Here is your inline image!<br><img src="cid:myimage1.jpeg">

 

Signature Control - Reports - PDF - If you print a report that contains a signature control bitmap image using the Amyuni PDF printer driver, the bitmap previously showed up with a black background. This is due to a bug in the Amyuni Printer Driver which does not properly render transparent image backgrounds.

Now, Alpha Anywhere will automatically convert the transparent background on the image to white. If you want an explicit background color, then set the image fill style to 'solid' and pick the background color you want to use. The transparent background on the image will be converted to the specified color.

 

PhoneGap - Custom Window onerror Event Handlers - By default, the Alpha Anywhere Javascript libraries add window.onerror handlers to certain functions in the Alpha Anywhere libraries. This can interfere with any window.onerror event handlers that you might want to add to your code.

You can now prevent Alpha Anywhere from adding system window.onerror event handlers by adding the following code to the client-side onRenderComplete event.

{dialog.object}.customWindowErrorEvents = true;

Bugs

Grid Component - Search - 'Is blank' and 'Is not blank' - Were generating SQL statements that used the Length() function rather than the StringLength() function (which is the portable SQL function for string length).

Application Server - Xbasic Error Log - A change was made in how thread usage is calculated in the Application Server to reduce false thread error messages which could occur under rare conditions.

 

 

 

Alpha Anywhere V4.01  - Build 3550-4650 18-Apr-2016

Videos

UX Component - Map Control Adding Multiple Markers to a Map - Customizing the Marker Icon for Each Marker Using Action Javascript, it is easy to add multiple marker to a map control on the UX. However, in some cases you might want to use a different icon for each marker. In many cases the decision as to what icon to use for a particular marker should be based on some data about the marker.

In this video we show how the marker icons used for markers on a map can be dynamically specified.

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

Date added: 2016-04-15

Features

UX Component - Map Control - Action Javascript - Adding multiple markers to a map - Customizing the marker icons - When you add multiple markers to a map you can now dynamically set the icon used for each marker based on data in the Data Series for each marker. You can also use image sequences.

 

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

 

To customize the marker icons, click the smart field for the Marker icon property, shown below.

 

 

This will bring up a dialog that offers three different methods for specifying the marker icons:

 

 

 

UX Component - Calendar Control and Date Picker - Disabled Days - When configuring the Calendar control or the Date Picker you can now explicitly disable certain dates.

 

 

 

You can either explicitly specify certain dates to disable (or call a Javascript function that returns an array of explicit date values), or you can specify more general Javascript code that gets called before each date value is drawn to determine if the date is disabled or not. For example to disable every December 25th date (regardless of year), you could specify the following Javascript:

 

Note: The Javascript is referencing a variable called 'd' -- the date value of the entry being rendered.

if(d.getMonth() == 11 && d.getDate() == 25) return true; //month is 0 based

return false;

 

You can also set the disabled dates programmatically (using Javascript) after the calendar has been rendered. For example:

 

 

//create an array of disabled dates

var disabledDates = [];

disabledDates.push('12/25/2016');

disabledDates.push('12/26/2016');

 

//get a pointer to the calendar control

var obj = {dialog.object}.getControl('MYCALENDAR1');

 

//set the calendar's disabledDates.dates property
obj.datePicker.disabledDates.dates = disabledDates;

 

//refresh the control
obj.refresh();

 

Bugs

AlphaDAO - MySQL - Commands out of sync Error - If you executed code that returned a resultset from MySQL, but did not read all of the rows in the resultset before executing a new SQL command you would get a 'Commands out of sync' error from MySQL. This is now fixed.
 

AlphaDAO - SQL::Resultset - .NextResult() Method -- Under some circumstances, when there was no next result set, would return an Xbasic error, rather than .f..

 

AlphaDAO - Oracle - CLOB Fields - Fixed an issue with Oracle CLOB fields if the data in the field contained high order characters.

UX Component - List Control - Search Part - Keyword Searches - Keyword searches now honor the search type setting for individual character fields. This means that if you had set the search type for a field to (say) '12' -- a case in-sensitive 'contains' search -- and you preformed a keyword search that included this field, the field search would be performed using search type of '12'.

Grid Component - Row Expander and Linked Content Section - Fixed an issue if the child component was a UX or Custom Component.

Grid Component - Excel Import - Under some circumstances empty data in the Excel file did not import correctly.

Forms - Desktop Applications - Button Labels - A bug was introduced in the previous build the caused button labels on forms to not display correctly if the button text included the & character.

Application Server - Session Variables - Null Values -- A bug was introduced in the previous build that prevented a session variable from being set to a null value if it had previously been set to a non-null value.

UX Component - Default Value - Page Variables - If you set the default value of a variable to an expression that used the PageVariable prefix, the expression did not evaluate. For example:

 

=PageVariable.var1

This bug was introduced in build 3522-4647. However, an easy work around is to change the default value expression to:

=request.variables.var1

 

 

 

Alpha Anywhere V4.0  - Build 3522-4647 05-Apr-2016

 

Videos

UX Component PhoneGap - Storing Large Amounts of Data for Off-line Use in Files on a Device When you build an application for disconnected usage, the data you want to have available while you are disconnected is stored in List controls in the UX which are persisted to Local Storage on the device. Local Storage is, however, limited in size. In some cases your application will need to have a large amount of read-only data available (such as price lists, etc.) and instead of storing this information in Local Storage you would like to store the data in files in the file system of the device.

If your application is a PhoneGap application, then you can store large amounts of data in files on the device as shown in this video tutorial.

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

Download Component

Date added: 2015-08-01
UX Component PhoneGap Shell Building and testing PhoneGap applications can be tedious because every time you want to test a change to your application you have to submit the application to the PhoneGap build service and then load the app onto your device for testing.

This process can be dramatically shortened by building a PhoneGap shell application and then testing your application inside the shell. Every time you make a change to the component you are working on, you no longer have to submit it to PhoneGap build - you simply click the refresh button inside the shell, where the component is running.

In this video we show how you can easily build a PhoneGap shell component.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-08-01
UX Component PhoneGap - Using the Image Picker Plugin To Select Multiple Images from the Photo Library The List control allows you to use the camera on a mobile device to take a picture and then when the List data are synchronized, upload the picture to a server (such as Amazon S3 or the AlphaAnywhere server) and store the picture filename in the database. However, there are situations where you want to capture multiple pictures and adding one record at a time to a List and then using the camera to get the image for each record would be tedious. It would be preferable to be able to open the Image Library (i.e. the Photo Roll) on the device and select as many images as you want. Each selected image would add a new row to a List control.

This video shows how the PhoneGap Image Picker plugin can be used to do this.

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

Date added: 2015-08-09
UX Component Setting the Height of an Object to 100% Setting the height of to 100% might seem like a natural thing to want to do, but in reality it is complicated because while it is clear what you MEAN by this, the HTML layout engine may not know what the height of the containing element is. or put more accurately, when the the element you want to size at 100% height is initially rendered, its container may not have been properly sized yet.

This is especially true with Panels which need to be resized after initial render so that they fit the device.

Fortunately, Panels have an onSize event that exposes a height property, which you can use to set the absolute height of an element so that it fills a Panel, as shown in this video.

Watch Video
Download Component

Date added: 2015-08-25
UX Component Building 'Real-time' Applications Using Web-Sockets In a typical web-application the client makes a request to the server and the server responds. The server cannot send information to any client unless the client first requests it. However, in 'real-time' applications the server maintains a connection to the client and there is a two way channel for sending and receiving messages. When the server, or any of the connected clients, sends a message, the message is broadcast to all of the connected clients and an event will be triggered on each client when a message is received. The event handler can choose to handle the message, or to ignore it.

A common pattern (which is discouraged because it does not scale) is to user timer events on a Grid or UX to make periodic callbacks to the server to see if there is any 'new information' that is of interest to the client. Real-time applications built on web-sockets are much more efficient than the pattern of executing Ajax callbacks on a timer.

This video demonstrates how a real-time application can be built. The video demonstrates a chat application where any client can post a message that is instantly seen by all of the other clients.


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

Download Component

Date added: 2015-09-03

(Requires build 4540 or above)
UX Component Client-side Data Cache The client-side data cache allows you to retrieve data from the server. Once the data has been loaded into the data cache, you can use the data  in your UX component. The data in the client-side data cache can be persisted (either to Local Storage or to the file system in a PhoneGap application) so that the data is available even when you no longer have a connection.

The client-side data cache is particularly useful in PhoneGap applications that are designed for disconnected usage because you can store a large amount of data on the device and have this data available to your application.

In this video we show how the client-side data cache is set up and we demonstrate how it persists data to Local Storage and to the file system in a PhoneGap application.


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


Download Component

Date added: 2015-09-05

(Requires build 4541 or above)
UX Component Map Control - Adding Multiple Markers to a Map using Client-side Data Action Javascript has a method (in Map Control Actions) to add multiple markers to a map. However, this action assumes that you will be making an Ajax callback to the server to do a query to get the list of latitude/longitude values for each marker you want to add to the map. But what if you already have a list of data on the client-side with latitude/longitude values? Making an Ajax callback to the server under these circumstances is unnecessary.

In this video we show how a List control, which has latitude/longitude values for each row, can be used as the data source for the markers and how a marker for each row in the List can be added to the map without having to make an Ajax callback.

Watch Video
Download Component

Date added: 2015-09-10
Xbasic Calling into Node.JS from Xbasic - Node Services Defined at the Project Level You can define global Node services (i.e. services that can be called from any application on your server), or you can define Node services at the individual project level. Node services defined at the project level get 'published' like any other components, or pages in your application when you publish your applications.

In this video we show how you can define and consume Node services in a web project.

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

Date added: 2015-09-12
UX and Grid Component Using OData Data Sources OData is a standard method of access data using a REST api. Alpha Anyhwere allows you to easily consume data from OData services.

In this video we show how a connection string is defined to connect to an OData service and then how a Grid component is built to go against the OData service.


Watch Video - Part 1
Watch Video - Part 2

In the next video we show how a UX component with a List can be built using the OData data source:
Watch Video - Part 3


Date added: 2015-09-12
UX Component Finding Controls in a Large UX Component When editing a UX component with a large number of controls, finding the control that you want to edit can be difficult. The Quick Find genie makes it very easy to locate the control that you want to edit.


Watch Video

Date added: 2015-10-07
Xbasic Validating and Reformatting JSON Data Xbasic has many functions that make working with JSON data easy. Two particularly useful functions are json_validate() and json_reformat(). These functions are described in this video.

Watch Video

Date added: 2015-10-22
UX Component - List Control Converting a List that uses a Static Data Source to a SQL Data Source and Vice-Versa It is common when building a UX component that uses List controls to start off with Lists that are based on static data (because setting up a List to use static data is so easy). Once you have your UX working, you might then want to convert the List to be based on a SQL database. A genie allows you to easily export the data from your static data source to a new table in a SQL database, or to link your List to an existing table in a SQL database.

You can also easily convert a List that uses a SQL data source to a static data source by importing the data from the SQL table.

Watch Video

Date added: 2015-11-04
UX Component - List Control Opening a Pop-up Window with a Button in a List Row - Positioning the Window Relative to the Button When you create pop-up windows in a UX control, a common pattern is to open the window positioned relatively to the button that displays the window. If the button is in a row of a List control, then it is a little trickier to position the window relative to the the button that was clicked.

This video shows how you can position a dropdown window relative to a button in a List row.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-11-09
UX Component - List Control Dynamically Changing Page Size of a Paginated List at Run-time In this video we show how you can dynamically change the page size of a paginated List that is based on SQL data.

Watch Video
Download Component


Date added: 2015-12-29
UX Component Executing Client-side Validation Rules Programmatically When you define validation rules for controls on a UX, the rules are evaluated when the UX is submitted. However, there may be cases where you want to explicitly (programmatically) evaluate the validation rules for a set of controls.

For example, you might not want to allow the user to go to a different Panel Card if there are validation errors on the current Panel Card.

In this video we show how you can programmatically execute the client-side validation rules for a series of controls.

Watch Video
Download Component

Date added: 2015-12-30
UX Component - List Control Displaying Hierarchical Data in a List A common requirement in many mobile applications is to display cascading data in a List control (such as a list of menu choices). Some of the items in the List will have sub-choices. When an item in the List that has sub-choices is selected, the List is repopulated with the sub-choices and a 'back' button is enabled to go back to the previous level.
There is no limit as to how deep this hierarchy of nested Lists can be. Typically, when an item in the List that has no sub-choices is selected, an action associated with that List item is executed.

In this video we show how you can build a UX component that uses a List to display an hierarchical menu system. We show how a genie can help you generate the JSON data for the hierarchical menu system and how the List's 'Quick Setup Genie' can be used to configure the List to display the nested Lists defined by the List's JSON data.


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

Watch Video - Showing Animation for List Transitions


Date added: 2016-01-04
UX Component - List Control Displaying Hierarchical Data From a SQL Table in a List In the 'Displaying Hierarchical Data in a List' video we show how hierarchical data can be displayed in a List. In that example the data shown in the List is defined statically. In this video we show how the data hierarchical data for the List can be retrieved from a SQL table.

The video shows a List with Country names. When the user selects a Country, the List is repopulated showing the Cities in the selected Country and a 'back' button is enabled. When the user selects a City, the Contacts in that City are shown.

Watch Video
Download Component

Addendum:
In this next sample component the Xbasic commands that are executed to get the JSON data are replaced with a built-in helper function. When the user clicks on a List 'endpoint', the selected record is shown and can be edited.

Download Component

Date added: 2016-01-05
UX Component Structure Explorer When you are working with a complex UX component that has many different Panel Layouts, Navigators and Cards as well as many Window containers and Panel Overlays, it can be difficult to get a sense of the component's underlying 'structure'.

In this video we show how the Structure Explorer can help in getting an overview of how a UX component is structured.
 
Watch Video

Date added: 2016-01-05
UX Component Client-side Data Cache - Populating Dropdown Boxes From the Client-side Data Cache - PhoneGap In a PhoneGap application, if your UX contains Dropdownbox controls, the choices shown in the Dropdownbox controls will be defined at design time (when the PhoneGap application is built).

However, in your application you might want the choices in the Dropdownbox controls to be defined at run-time. Your app should make a callback to the server to get current data for the Dropdownbox controls and then persist that data locally so that the next time the app is loaded it already has the data for the Dropdownbox controls. The client-side data cache is ideal for this scenario.

In this video we show how you can define client-side data cache items for the data to populate Dropdownbox controls.

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

Download Component

Date added: 2016-01-12
UX Component - PanelOverlay PanelOverlay Windows The UX component allows you to display PanelOverlays that 'float' on top of a Panel. By showing and hiding the PanelOverlay you can make the PanelOverlay behave much like a 'window'.

In this video we show how the 'PanelOverlay is window' property is used to turn a PanelOverlay into a window that is initially hidden and shown on demand by executing the 'PanelOverlay window show' action in Action Javascript.

Watch Video
Download Component

Date added: 2016-01-13
UX Component - Custom Controls Understanding CustomControls The UX Component allows you to define two types of CustomControls - data bound and non-data bound. In both cases the HTML and Javascript for the custom control can either be specified at design-time, or (much more powerfully) generated by Xbasic at run-time.

In this video we introduce the CustomControl found in the 'Other Controls' category of the UX Builder (as opposed to the 'CustomControl' found in the 'Data Controls' category).

After introducing the basic concepts of the CustomControl, the video shows how a UX form can be dynamically generated at runtime from a definition that could be read from a database.


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

Download Component

Date added: 2016-01-19
TabbedUI Component Keyboard Shortcuts The TabbedUI component is a great way for navigating to the different components that make up an application. You can assign keyboard shortcuts to the different buttons in the TabbedUI that launch components.

Launching a component using a keyboard shortcut can be more efficient than having to visually locate the button in the TabbedUI and then click on it.

In this video we show how to assign a keyboard shortcut to a button in the TabbedUI.

Watch Video

Date added: 2016-01-21
Xbasic Calling SOAP Web Services from Xbasic You can register SOAP web services at the Web Projects Control Panel and then call methods of these services from your Xbasic code.

In this video we show how to register a SOAP service and then call methods of the service.


Watch Video

Date added: 2016-01-21
Grid Component Using IN clause in SQL Statement and Argument Arrays Argument arrays, in combination with the SQL IN clause are a powerful way to define what records the Grid should show.

In this video we show how you can use argument arrays to define a button on a UX that opens a Grid showing a selected list of records.

Watch Video
Download Component

Date added: 2016-02-10
Xbasic Working with MongoDB using AlphaDAO Alpha Anywhere allows you to connect to a vast array of SQL databases and then build Grid and UX components against the SQL data. You can also use Xbasic (specifically the AlphaDAO object) to write code that executes SQL commands.

You can work with a Mongo database in the same way.

In this video we show how you can create an AlphaDAO connection string that points to a Mongo instance - how you can export data from a SQL database to a Mongo database - and how you can build a Grid component against a Mongo database.

NOTE: These videos show how the Mongo database is accesses using standard AlphaDAO objects. Alpha Anywhere also provides an API to access Mongo directly.


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

Required build: 4612

Date added: 2016-02-10
UX Component Understanding Custom Settings The UX allows you to define Custom Settings - a list of named setting values. These custom settings can be referenced in Javascript code and also when the component is initially rendered.

Custom Settings are a powerful tool for dynamically configuring certain aspects of a UX component.

In this video we introduce the concept of Custom Settings and show some of they ways they can be used.

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

Required build: 4614
Date added: 2016-02-14
UX Component - List Control Pull-past-end to Refresh List Data A common pattern in mobile applications is to allow a user to refresh the data in a List by pulling down on the List past the top of the List and if the user pulls down past some threshold value, to trigger a List refresh once the user releases the List, and it bounces back to its initial position.

In this video we show how you can implement the 'pull-past-end-to-refresh' pattern in a List control.


Watch Video

Required build: 4620

Date added: 2016-02-20
PhoneGap Including Pre-populated SQLite Database Files in a PhoneGap Project The UX component has extensive support for working with SQLite databases in PhoneGap applications. A common requirement when building PhoneGap applications is to include pre-populated SQLite database files as part of your PhoneGap project. These pre-populated database files can contain large amounts of data. Since they are part of the PhoneGap project, the data in these database files will be immediately available to your application when it is loaded, even if there is no connection.

In this video we show how the PhoneGap Builder allows you to define the pre-populated SQLite database files to include in your PhoneGap project.


Watch Video 1
Watch Video 2

Required build: 4625

Date added: 2016-02-27
UX Component Using SQLite in a UX Component in a PhoneGap Project Action Javascript has actions that make it easy to work with a SQLite database on a mobile device.

In this video we demonstrate various actions that can be performed with the Action Javascript SQLite action.

Watch Video 1
Watch Video 2
Watch Video 3
Watch Video 4

Required build: 4626

Date added: 2016-02-28
Publishing Web Applications Using the HTTP Method for Publishing Web Applications When you publish a web application to a remote server, you can choose whether to use FTP or HTTP to do the actually work of transferring the files. The HTTP option has more options than the FTP option, but has some additional setup that is required.

In this video we show how to configure a server to allow HTTP publishing and how to create a Publishing Profile in the Alpha Anywhere IDE that uses HTTP Publishing.

Watch Video - Configuring the Server
Watch Video - Defining a Publishing Profile

Date added: 2016-03-02
UX Component Vertically Centering Content in a Panel Card A common pattern in mobile applications built using Panels it to vertically center some content in a Panel Card. The content should be vertically centered regardless of the device orientation or size.

In this video we show how this is easily done with some Javascript in the Panel Card's onSize event.

Watch Video
Download Component

Date added: 2016-03-04
UX Component Using SQLite to Store a Large Database of Records with Images for Use in an Off-line Application In a PhoneGap application, being able to use SQLite on the device allows you to store a large amount of information on the device that will be available when the device is offline. A common requirement is for the data that is stored in the SQLite database to contain images.

In this video we should how you can build a UX component that makes a callback to the Alpha Anywhere server to create a SQLite database of 500 records, with each record having an associated image. The SQLite database is then download to the device and stored on the device. The a SQL query is executed against the on-device SQLite database and a List control is populated showing all of the records and their associated image.

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

Date added: 2016-03-08
UX Component PhoneGap - iOS Background Geolocation This video shows how to use the 3rd party iOS Background Geolocation PhoneGap plugin.

Watch Video

Date added: 2016-03-11
UX Component PhoneGap - Local Authentication for iOS with the Fingerprint Scanner This video shows how to use the 3rd party Local Authentication for iOS with the Fingerprint Scanner PhoneGap plugin.

Watch Video

Date added: 2016-03-11
UX Component - ViewBox Control Introduction to Basic Concepts This video demonstrates basic concepts of the ViewBox control such as the a5-item attribute and the a5-value attribute and shows how events are attached to the ViewBox and how parts of the ViewBox can be made 'selectable'.

Watch Video
Download Component

Date added: 2016-03-13
UX Component - ViewBox Control ViewBox HTML Rendered by Merging Data into a Template The HTML that the ViewBox displays can be generated dynamically by merging data into an HTML template.

Watch Video
Download Component


Date added: 2016-03-13
UX Component - ViewBox Control ViewBox HTML Rendered by Merging Data Array into a Template The data that is merged into the ViewBox Template can be an array of objects. In this video we show how the template is expanded by iterating over all of the objects in the data array and how the resulting HTML can be formatted to look and behave like a simple List control.

Watch Video
Download Component

Date added: 2016-03-15
UX Component - ViewBox Control Making a ViewBox Behave Like a Simple List Control A common use case for a ViewBox control is to implement a simple List control. In cases where you don't need the full richness of a List control, but you only want to create a scrollable list of items, the ViewBox represents a simpler option.

In this video we show how the special ListRowContainer control can be used to make a simple List using the ViewBox.

Watch Video
Download Component

Date added: 2016-03-15
UX Component - ViewBox Control Sample ViewBox Walkthrough - Star Rating Example In this video we do a behind-the-scenes walkthrough on the sample 'star rating' ViewBox Control.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2016-03-15
UX Component - ViewBox Control Sample ViewBox Walkthrough - iOS Login Example In this video we do a behind-the-scenes walkthrough on the sample 'iOS Login' ViewBox Control.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2016-03-15
UX Component - ViewBox Control Understanding the Concept of 'Selectable' Elements in a ViewBox One of the key concepts of the ViewBox control is that elements in the HTML rendered by the ViewBox control can be 'selectable'.

In this video we explain this concept by taking a complex ViewBox layout that does not have any selectable elements and making portions of the ViewBox HTML selectable.

Watch Video
Download Component

Date added: 2016-03-15
UX Component - ViewBox Control Understanding the ViewBox State Object The ViewBox has a 'state' object and the values in the state object can be used in the ViewBox template.

In this video we show how the template can reference values in the ViewBox state and how the ViewBox's .setState() method allows you to set properties in the ViewBox state object.


Watch Video
Download Component

Date added: 2016-03-16
UX Component Add-in Controls The UX Builder allows you to define add-in data bound controls. These are control that are defined externally and are available in the uX Builder just like any of the built-in controls.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2016-03-15
UX Component - List Control Dynamically Populating a List Columns and Data - Generic SQL Table Viewer The List control on a UX is one of the most versatile controls in Alpha Anywhere. To demonstrate its versatility this video shows a sample UX component that can be used to view the data in any table in a SQL database. The UX has a dropdownbox where the user can select the table in a SQL database and then a callback is made to the server to dynamically populate the List with the data from the table.

In addition the UX contains a search part where the user can specify filter criteria to filter the data in the table.

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

Download Component

Date added: 2016-03-18
Xbasic Using Output Arguments when Calling a Stored Procedure When you call a stored procedure from Xbasic, the stored procedure might return values (in addition to resultsets). The calling Xbasic code can read these return values by using 'output' arguments.

In this video we show how input/output and output arguments are defined and used when calling a stored procedure.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2016-03-18
UX Component - List Control Audio Recording/Playback in a UX Component It is quite common to build mobile applications that work in disconnected mode and allow the user to capture images using the phone's camera. You can also build mobile applications that allow users to record and playback audio files.

NOTE: To record audio, you must be using PhoneGap.

In this video we show how a List with a Detail View can be used in a UX component that is running as a PhoneGap application to capture audio files for each new record that is added to the List. The application that we show can work in disconnected mode and allows the user to record many audio files while disconnected. When a connection is obtained and the data that was captured while disconnected is synchronized, the audio files can first be uploaded to a server (such as Amazon S3).

The component relies on the AudioRecorderAndPlayer control in the UX component.


Watch Video - Part 1
Watch Video - Part 2

Date added: 2016-03-26
Style Builder Style Builder In Alpha Anywhere V4 the Style Builder has been rewritten. You can now easily adjust the entire appearance of a style by simply adjusting the SASS variables that control the style colors and you can also easily add new sub-themes for different control types.

In this video we show how you create a new style for buttons and we also show how the entire style can be c hanged from a 'blue' color to a 'green' color.

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

Date added: 2016-03-26
UX Component - Ink Control Introduction to the Ink Control The Ink control allows you to create and edit 'ink' data.

In this video we give a very brief introduction to the Ink control.

Watch Video - Part 1
Watch Video - Part 2

Date added: 2015-08-13
UX Component - Ink Control Setting the Background Image for the Ink Control You can set the background image shown in the ink control to anything you want - either by specifying the URL of an image, or the base 64 encoded data for an image.

In this video we show how you can set the background to an image and also to a map this is generated by Google Maps.

Watch Video

Date added: 2016-01-21
UX Component - ViewBox Control ViewBox Control - In Depth Tutorial This video is an in-depth tutorial on how the ViewBox control can be used to build a 'star rating' control.

A common pattern in many applications is to allow a user to rate something by clicking on the number of stars. For example, the control might display 5 stars, all of which are grey. The user will then click on the 4th star to rate something as '4 stars'. The first four stars will then change color and the 5th star will remain greyed out.

This type of control can easily be built using the ViewBox control, as shown in this video.

NOTE: A 'star rating' control is actually a built-in control type (select the [More...] tool in the UX toolbox) so it is not necessary to go through the steps shown in this tutorial every time you want to add a star rating control to a component. The video is mean simply as in introduction to key concepts of the ViewBox control.


Watch Video - Part 1
Watch Video - Part 2

In depth discussion of how the control is built.
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8

Download Component
Date added: 2015-09-04
UX Component - FormView Control Using the MobileForms_StarterExample Quick Start Template When you create a new UX component that will use the FormView control to create a mobile optimized form, the sample 'MobileForms_StarterExample' template is a convenient starting point.

In this video we give a quick overview of the features of this sample template.

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

Date added: 2016-04-02

Features

 

FormView Control - Starter Example - When you create a new UX component  you can use the MobileForms_StarterExample as a quick start to create a basic UX component with a List control (the form's data source), a FormView control and a set of Editors (for editing values in the form).

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

 

To use the template select 'MobileForms_StarterExample' from the dialog shown below.

 

 

FormView Control - The FormView control (together with Editor Sets and Editors and the List View control) are the fundamental building blocks for building touch optimized mobile forms.

For more information on the FornView control click here.

 

Ink Control - A new type of data bound control can be added to a UX Component. The ink control allows users to 'draw' (using a finger or stylus on a device that supports touch events) or with a mouse (on a desktop browser). The ink is captures using a special text format.

Watch Video - Part 1
Watch Video - Part 2

 

Overview

The ink control, shown in the image below, is made up of two main parts, the editor and the view.

 

 

The editor (bottom part -- this is where the user draws) allows the user to edit the ink while the view (top part) provides the ability to navigate to the part of the page where the ink is being drawn. For example, the 'page' that contains the ink might be a standard 8.5 x 11 inch page.  In ink editor (bottom part) only shows a small part of the page. The view (top part) contains a dragable zoom-box (see the dotted red rectangle) showing the portion of the ink visible in the editor. The editor and view can be laid out in three ways.

The first is a split layout. In this layout the editor and the view share the ink controls layout area in either a horizontal or vertical layout. It should be noted that a split layout can still optionally show only the view or editor. This is useful if you are targeting multiple screen sizes, as you can use responsive layout Javascript to change the split layout on smaller screens to toggle between the editor and view if there isn't space for both. You can also use this to allow the user to toggle the editor to take up the entire ink control on larger screens as well.

The second layout is a detached view layout. In this layout the editor takes up the entire ink control area, while the view part is injected into an element specified by an ID. This allows for extremely customized layouts.

The last layout is an editor layout. This will display only the editor. This is useful for ink editing that doesn't need navigation, such as signature capture.

Ink data is stored in a string format, with the strokes stored as vectors. Below is an example of some ink data.

 

#A5Ink
version 1.0
settings %json%
{"page":{"width":5,"height":3,"unit":"in","dpu":300,"lines":false,"background":{"image":false,"color":""}},"meta":{"bounds":{"l":57,"t":35,"r":1393,"b":571},"created":"2015-09-12 05:12:15 pm","modified":"2015-09-12 05:29:42 pm"}}
%json%
A pen 3 #000
S 120,228,CAC+D+E+F+G+I+J+M+M+TaTaR+UaQcRdQcTeOePcMfJcGcFcEdDcEdAdBcAcAdBd+e+c+e+caebcbebedddekhfcfbgbgbfahahajal+m+-29+p+lBiBkAhBfAfBdAdCcAcC+CCAFCHCKCMBUDQBOBPBN+NAJ+MAI+J+H+H+IaIcHbIbGbEcDbCbCc+d+cAc+cAdDdCdCcBcBcBcBcE+D+D+DADCEAEBDBCBBCCEACDEAECFAF+FAFAG+E+F+EbHbDaDbEaC.........

 

This keeps the file size down and allows for the ink to be rendered at any resolution. The boundaries of the ink page are defined by the ink page settings. The page settings include width and height in a specified unit (in, px, etc.). This data is combined with the dots-per-unit (dpu) to create the ink page. The width and height are multiplied by the dpu to get the base page size in "ink units". The dpu can be thought of like "dpi" in printing. The higher the dpu, the higher the ink resolution.

The goal is to get the dpu relative to the units so that when the editor is at a scale of '1 ink unit equals 1px', the user is encouraged to enter ink at a larger scale than if they where writing on a sheet of paper. This works around the inherent lack of accuracy in capacitive touch screens (ink can only be captured at screen pixel accuracy), and allows for readable written input.

If the ink page unit is 'inches' then the dpu should be at least be 300. All measurements inside of the ink (pen width, margins, etc.) are in 'ink units' derived from the dpu.

The page can also store background (color and image) settings, and have automatically generated lines to create graph and ruled paper look.

The editor and view parts of the ink control can each have an overlay. The overlay is arbitrary HTML that will be laid out over each part. Elements in the HTML can make use of the "a5-item" attribute in order to easily add buttons to the ink control. There are a number of predefined "items" that allow the user to access the eraser tool, pan tool, undo and redo actions, and navigate the ink. Custom "items" allow you to add unique behaviors to elements in the overlay. The events on the "items" have direct access to the ink control.

The ink editor uses tools to edit the ink. The default tool in the pen tool. Other tools can be selected using the ink control's .setTool() method. This method can specify whether the tool is "sticky" or not. If a tool is not "sticky" then after a single user interaction with the tool, the tool will be deselected, and the ink editor will go back to the pen tool. Each tool has an optional "active class name" that will be applied to the ink control when that tool is active. This allows you, though CSS, to automatically highlight the elements in the overlay, and possibly change visibility of elements as well.

 

 

 

AudioPlayer Control - The AudioPlayer control allows you to add a control to the UX to play audio files.

To add a new AudioPlayer control to the UX component, select the [More...] entry in the controls toolbox (in the 'Data Controls' section) and then select the 'AudioPlayer' control.

NOTE: A separate Audio Recorder/Player control is also available. This control can only record in a PhoneGap application.

 

 

This will insert a control into the UX that looks like this:

To customize the AudioPlayer control, click the smart field for the Control properties.

 

 

 

 

Since the AudioPlayer is a data bound control, it has a {dialog.object}.setValue() and a {dialog.object}.getValue() method.

To set the audio file that you want to play back you use the {dialog.object}.setValue() method

For example:

{dialog.object}.setValue('MYAUDIOCONTROL','stream:http://audio.wgbh.org:8004');

 

In this case the AudioPlayer value is being set to a 'stream' - (a continuous audio stream) rather than a file.

After the stream is ready to play, the AudioPlayer appearance will change to this;

While the stream is loading (i.e. before it is ready to play), the text 'Stream', shown in the above image, will say 'Loading...'.

All of the text messages shown in the control are customizable in the AudioPlayer Control properties. 

 

In this next example, the AudioPlayer value is set to a file URL:

{dialog.object}.setValue('MYAUDIOCONTROL','http://s3.amazonaws.com/alphaVideos/theway.mp3');

 

In the case where the AudioPlayer value is set to an audio file (not a stream), its appearance will change as follows once the audio file is ready to play:

 

 

When the user taps the Play button, the audio starts to play back. The number on the right side indicates the duration of the audio file. Before playback starts, or when playback is paused, the fast forward and fast reverse buttons (on either side of the Play button) will skip to the beginning or end of the audio clip (if you tap on them). However, if you press and hold, they will rewind or fast forward in 2 second steps.

 

The top bar shows the progress as the audio file is being played. The number on the right hand side shows the duration of the audio file. The number on the left hand side shows how much of the audio file has been played. The buttons on each side of the Play button allows you to skip forward and back in the file.

 

 

NOTE: The AudioPlayer control cannot play audio files that are hosted on the Alpha Anywhere server. It can play files that are hosted on Amazon S3, or, in the case of a PhoneGap application, files that are stored in the file system on the device.

 

 

AudioRecorderAndPlayer Control - The AudioRecorderAndPlayer control allows you to add a control to the UX component to play audio files and to record audio files.

NOTE: A separate AudioPlayer control is also available. This control is for playback only and is not limited to PhoneGap applications.

To add a new AudioRecorderAndPlayer control to the UX, select the [More...] entry in the controls toolbox (in the 'Data Controls' section) and then select the 'AudioRecorderAndPlayer' control.

 

The AudioRecorderAndPlayer controls is a dual purpose control. It can be used to play audio files (or streams) and it can also be used to record audio files.

You can only record audio files if you are using PhoneGap.

When you build your PhoneGap application you must must ensure that the Media plugin has not been selected:

and that the Media With Compression plugin has been selected.

In addition, you are likely to need to upload the captured audio files to a server so the following PhoneGap plugins should also be loaded: Device, File, File transfer.

 

When you add an AudioRecorderAndPlayer control to your UX you customize the control properties by clickin the smart field for the Control properties.

The customization genie allows you to set customize text and also set the maximum recording duration (in seconds).

 

When the component is run, the AudioRecorderAndPlayer control will look like this (if not audio file has been loaded for playback):

 

The red circle button will put the control into record mode. When the control is in record mode, it will appear as follows:

 

The Done button (text on this button is customizable -- you can use language, or text dictionary tags for International applications- <a5:r> or <a5:t>) becomes enabled. This button indicates that you want to end the recording. The record button changes to a Pause button. You can use this button to pause the recording.

The horizontal line at the top of the control indicates the recording level. The color of the line will be orange, green or red to indicate if the recording level is too low, ok or too high.

The number on the right indicates the duration of the recording.

If you set the value of the control to an audio stream or an audio file ( using the {dialog.object}.setValue() method ),  the control's appearance will change as shown below.

The control is now in 'Player' mode. The play button in the center of the control will start playback. The small record button at the left of the control will allow you to switch the control from 'Player' mode to 'Record' mode.

 

Audio Files - List Control - Detail View - The List control now supports the 'Audio' control type in the 'Fields' pane of the List Builder, as shown in the image below. The purpose of setting a field type to 'Audio' is to designate the field as a 'media' field for synchronization purposes (as explained below).

 

Watch Video - Part 1
Watch Video - Part 2

 

 

 

The 'Audio' control type is intended to address a very specific use case. Consider the following scenario:

  1. You have built a mobile application that runs in PhoneGap
  2. You have used the AudioRecorderAndPlayer control to record audio files in your application. When an audio file is recorded, the audio file is stored in the file system on the mobile device and the filename of the audio file is stored in the List control
  3. When you sync the List control to save any edits that were made, you want to upload the audio files from the device to a server (either Amazon S3, or the Alpha Anywhere server) and then store the edits that made in the List data to the SQL database that backs the List.

When you sync the List, Alpha Anywhere looks in all of the 'media' fields in the List looking for local filenames. These files are then uploaded to the target server and the data in the List are then changed to reflect the filename of the file on the remote server before the data are submitted to the server to update the SQL database. The following example will help make this point clearer.

Assume that you have a List with these fields:

name, audioFile

 

The user adds a new row to the List and records an audio. The data in the List will look something like this:

name: John Smith

audioFile: file://folderNameOnTheMobileDevice/filenameOfAudiofile.m4a

 

When the user hits the sync button to push the edits made to the List back to server so that the data can be added to the SQL database that backs the List, Alpha Anywhere first scans the data in all 'media' files to find any references to local file system filenames.

If the control type of the audioFile fieldname was set to Audio in the List builder, the audioFile field is considered a 'media' field. Alpha Anywhere will detect that the data in the audioFile field is a local file and it will first upload this file to the target server. Assuming that the target server is Amazon S3, the URL of the file once it has been uploaded to S3 might be something like: https://your_bucket_name.s3.amazonaws.com/audiofile1.m4a

Next, before sending the data in the List back to the Alpha Anywhere server (where the data will be written to the SQL database), the data in the List is changed so that the media fields are set to the URL of the files on the remote server. So, in our example, the data in the List is changed to this:

name: John Smith

audioFile: https://your_bucket_name.s3.amazonaws.com/audiofile1.m4a

 

The data are then sent to the Alpha Anywhere server and the value that is stored in the SQL database for the audioFile field is https://your_bucket_name.s3.amazonaws.com/audiofile1.m4a and not file://folderNameOnTheMobileDevice/filenameOfAudiofile.m4a (which of course would be a meaningless value to store in the database!) 

 

NOTE: It is recommended that you set Amazon S3 as the target for media file uploads as the AudioPlayer cannot play audio files that are hosted on an Alpha Anywhere server. To set the upload target go to the 'Media and Other Linked Files (PhoneGap Applications Only) property on the 'Detail View' tab in the List Builder.

 

 

 

 

PhoneGap - FileTransfer - Upload and Download - SSL Server - If you are testing a PhoneGap application with a server that is using SSL with a self-signed certificate, all PhoneGap file transfer functions will fail.

You can set a global flag to tell the PhoneGap file transfer function to trust all host. When you set this flag to true, you will be able to test PhoneGap file transfer functions even though your server might be using a self-signed certificate.

To set the flag, you could add this code to the client-side onRenderComplete event:

{dialog.Object}._phoneGapTrustAllHosts = true;

 

PhoneGap App Builder - Config.xml File Format - Updated - PhoneGap Build has deprecated the 'gap:' prefix previously used within the project's config.xml file. While the 'gap:" prefix is still officially supported, the recent PhoneGap Build documentation suggests that the prefix should be dropped. This change affects the splash, icon, platform and qualifier tags. All new PhoneGap project config.xml files will no longer include the 'gap:' tag. All previously defined config.xml files will be automatically updated and the 'gap:' prefix will be removed once the PhoneGap project is saved.

PhoneGap App Builder - Launch Images / Splash Screens - Android Only - PhoneGap Build now requires a default launch image /splash screen called 'splash.png' for Android apps. You must include the core SplashScreen plugin as well. The SplashScreen plugin is now automatically enabled if you choose to build an Android app. The config.xml file now includes the required splash tag as well.

PhoneGap App Builder - App Icons / Splash Screens - Windows 8.1 -  PhoneGap Build now supports Windows 8.1. The appropriately sized icons and launch images / splash screens have been added to the config.xml file and will be automatically generated, should you choose to generate the images files for icons and splash screens when building a Windows 8 mobile app. Please keep in mind that you should always check the sizing on each launch image / splash screen prior to publishing your app to any of the app stores. While the PhoneGap Builder does its best to size the images in the X axis, the Y axis may be larger than the expected size because of the numerous varying aspect ratios that the properly sized images require.

UX Component - Control Flow Direction - Right-to-Left Languages - A new property in the UX builder allows you to set the control flow direction.

 

The default is left-to-right (ltr). You can also select right-to-left, as shown in the image below.

 

 

 

Web-sockets Server - Redis - A new option has been added to the Web-sockets server to use Redis to store the messages that are sent and to handle the distribution of messages to the connected Node.js server(s)

To turn on this option, go to the Web Project Properties dialog (accessible from the Web Control Panel) and select the option as shown in the image below.

A copy of Redis is automatically installed with Alpha Anywhere. You need to ensure that the Redis server has been started before you run a component that uses the web-sockets server.

You can start a local copy of the Redis server, or you can point to a remote copy by specifying the Redis host property in the dialog.

To start a local copy of Redis you can either start Redis manually, or install Redis as a service.

To start Redis manually, navigate to the Alpha Anywhere executable folder from the command window and then type:

Redis-server

 

For information on how to install Redis as a service, see:

http://stackoverflow.com/questions/26213403/install-redis-as-windows-service

 

If you are using a load balancer to distribute load to multiple Alpha Anywhere servers, then you should turn on the Redis option.

 

 

The benefit of using Reds in your web-sockets configuration is that the solution is more robust. If the Node.js server is restarted for any reason, the message queue is not lost. In addition, Redis enables web-sockets applications if you are running multiple instances of the Alpha Anywhere server that are managed by a load balancer.

 

 

 

 

registry.sys_get() Method - 64 Bit Registry Entries - A new option has been added to the registry.sys_get() method to specify where you search for a registry value.

The second parameter passed to the method can be '32', '64' or 'Any'. 'Any' is the default option. With the 'Any' option, the method will first search the 32 bit registry and then if no match was found, it will search the 64 bit registry.

 

Examples:


? registry.sys_get("HKEY_LOCAL_MACHINE\SOFTWARE\MongoDB\Server\3.0\Edition")
= "MongoDB 3.0 2008R2Plus SSL (64 bit)"
 

? registry.sys_get("HKEY_LOCAL_MACHINE\SOFTWARE\MongoDB\Server\3.0\Edition","32")
= ""
 

? registry.sys_get("HKEY_LOCAL_MACHINE\SOFTWARE\MongoDB\Server\3.0\Edition","64")
= "MongoDB 3.0 2008R2Plus SSL (64 bit)"

? registry.sys_get("HKEY_LOCAL_MACHINE\SOFTWARE\MongoDB\Server\3.0\Edition","Any")
= "MongoDB 3.0 2008R2Plus SSL (64 bit)"

 

 

UX Component - Add-in Controls -- The UX Component now supports  'add-in' controls. Addin controls are defined by entries in the 'uxCustomControls' folder in the executable folder.

Watch Video

 

To add an add-in control to your UX component, click the [More...] item in the UX toolbox.

 

 

This will bring up a dialog showing the existing Add-in controls:

 

 

To define a new Add-in control add a new folder to the uxCustomControls folder in the executable folder.

The name of the folder defines the name of the add-in control. Inside the sub-folder there should be three files

 

For examples of how to define the contents of these three files, please refer to any of the sample controls that are shipped with Alpha Anywhere.

 

Here is an example of how the IntegerValue control looks:

This control is used for a field that only allow integer values and the value can be set by clicking buttons to increment/decrement the integer value.

 

UX Component - Data Controls - Custom Control - Data Bound Custom Controls are a powerful new technique for creating custom controls on a UX component.

NOTE: Contrast  'Custom Controls' in the 'Data Controls' section of the UX toolbox (discussed here) with 'Custom Controls' defined in the 'Other Controls' section of the the UX toolbar - search for 'UX Component - CustomControl - 'Other Controls' for more information.

NOTE: 'Data controls' are controls that have the concept of a control 'value'. These controls have a {dialog.object}.setValue() and {dialog.object}.getValue() method and when the UX is 'submitted' the value in these controls are submitted and are available in the e.datasubmitted object in your Xbasic event handlers.

 

Custom data controls are built using the ViewBox control. An understanding of how the ViewBox control works is essential before you can create a custom data bound control. For more information on the ViewBox control, click here.

 

 

To add a data bound Custom Control to a UX cpmponent, select the [CustomControl] item in the UX toolbox.

To define the properties of the Custom Control click the smart field for the control properties. This will bring up the builder as shown below:

 

When you define a custom control you can specify the properties for the control 'now' (i.e. at design time), or you can generate the property settings at run-time using Xbasic.

The 'Specify Now' option is rarely used because a Custom Control that uses the 'Specify Now' option is really no different than a ViewBox control and so there is little reason to use the Custom Control rather than the ViewBox.

However, the option to generate the custom control definition at run-time using an Xbasic function is extremely powerful. and allows you to generate highly customized controls on your UX component.

 

Creating a Custom Control - Starting with a ViewBox Control

The easiest way to create a new Custom Control is to start by creating a ViewBox control and then once you are satisfied with the ViewBox control copy the generated Javascript from the ViewBox builder to the Custom control.

From the ViewBox builder, click the Show button at the bottom left corner of the dialog. Then select the 'Javascript code to render ViewBox' menu command. 

Copy the code for the 'Settings' object. This is the code you will paste into the Settings JSON property in the Custom Control builder.

 

 

UX Component - ViewBox Control - A powerful new control type is now available in the UX Builder.

See this link for details about the ViewBox control.

 

UX Component - List Control - International Numbers - If the system regional settings on your server are set to a country that uses a comma as the decimal point, when you create a List control numbers are now shown with the comma as the decimal character. Previously, numbers were displayed using a period as the decimal character.
 

As a result of this change client side calculations (e.g. client-side calculated fields), might no longer work correctly. To fix the problem add this code to the client-side onRenderComplete event:

$u.decimal = ',';

 

This code informs the Javascript functions that convert a string into a number what the decimal character is.

 

UX Component - File Save Format - JSON - In a previous pre-release build (4582) an option was introduced to allow the UX component to be saved as a text file (using a JSON format) rather than the default binary file format. However, the default format was left unchanged as binary. Now, the default format has been changed to JSON. The reason for this change is to make using source controls systems easier to work with.

 

UX Component - PhoneGap - Image Capture - File name Option - When you use the PhoneGap camera option to take a picture, the picture filename is stored in the file system in a temporary location. This means that if the application is terminated the file may be removed by the operating system. You now have the option of moving the file to a different part of the file system so that it is not in a temporary location.

This new option is exposed in the Action JavaScript builder as shown below.

 

 

UX Component - PhoneGap - File System Methods - Several new methods for working with the file system in a PhoneGap application have been added.

NOTE: The existing PhoneGap file system methods (accessed using the PhoneGap - File System Actions action in Action Javascript) are limited in that they do not allow you explicitly specify what file system you (i.e. 'temp', 'private', 'saved', 'public') you want to use and they assume that all actions are in the 'saved' file system.

These new methods are more generalized as they can work with fully qualified file and directory URLs.

 

{dialog.object}.phoneGapFilesAvailable() Returns true if there is a local file system and PhoneGap is running.
{dialog.object}.phoneGapGetLocalDirURL(type) Returns URL of base for the requested part of the file system.  'type' can be: "temp", "private", "saved", "public"

Note: On iOS, "saved" and "public" may be backed up to iCloud
{dialog.object}.phoneGapReadFileURL(filepath, onReadSuccess, onError, startAt, endAt) Read a file. Optionally specify a starting and ending position in the file.
{dialog.object}.phoneGapWriteFileURL(filepath, text, onWriteSuccess, onError, append) Write a file
{dialog.object}.phoneGapFileExistsURL(filepath, onResult, onError) Check if a file exists. onResult(properties) will be called with false if the file does not exist.
{dialog.object}.phoneGapDeleteFileURL(filepath, onDeleteSuccess, onError) Delete a file
{dialog.object}.phoneGapCopyFileURL(srcpath, destdirpath, destname, onCopySuccess, onError) Copy a file.
{dialog.object}.phoneGapMoveFileURL(srcpath, destdirpath, destname, onMoveSuccess, onError) Move a file.
{dialog.object}.phoneGapRemoveDirectoryRecurseURL(dirpath, onRemoveSuccess, onError) Deletes the specified directory and all of its contents, including other directories and their contents.
{dialog.object}.phoneGapEnsureDirPathURL(rootpath, subdirpath, onCompletion, onError) Ensures that a directory structure (specified by subdirpath) exists within the specified rootpath. If the directories do not exist, they are created.
{dialog.object}.phoneGapListFilesRecurseURL(rootpath, onCompletion, onError) List files in a directory (recursively)
{dialog.object}.phoneGapListFilesURL(dirpath, matchRegex, onCompletion, onError) List files in a directory. If matchRegex is specified only matching files are listed.
{dialog.object}.phoneGapDeleteFilesNotInListURL(dirpath, matchRegex, keepList, onCompletion, onError) Delete files. If matchRegex is specified, only matching files are listed. If keepList is specified files in the list are not deleted, even if they matched.

 

 

 

UX Component - HTML Editor - Toolbar - You can now customize which buttons are shown on the HTML editor toolbar.

To customize the toolbar, click the smart field for the HTML editor toolbar customization property.

 

 

This will open the Genie where you can select the buttons that you want and the order in which you want them to appear. Use *break to start a new row of icons and *space to insert a spacer between the icons.

 

 

 

 

UX Component - Sample Templates - PhoneGap - When you create a new UX component, the available sample templates now include 'PhoneGap - iOS Background Geolocation' and 'PhoneGap - iOS Device User Authentication'.

 

PhoneGap App Builder - Third Party Plugins (iOS) - Touch ID. Added support for the TouchID plugin. This plugin, allows a PhoneGap app to locally authenticate the user with the TouchID sensor (fingerprint scanner) on iPhone 5S and greater devices.

For a video overview of using this plugin with the new UX PhoneGap - iOS Device User Authentication template,
see Local Authentication for iOS with the Fingerprint Scanner Plugin

For the full cordova-plugin-touch-id plugin documentation,
see cordova-plugin-touch-id

PhoneGap App Builder - Third Party Plugins (iOS) - Background Geolocation. Added support for the Transistorsoft/cordova-background-geolocation-lt plugin. This sophisticated plugin, allows a PhoneGap app to continue acquiring device geolocation data when the app is in the background or the device is locked.

For a video overview of using this plugin with the new UX PhoneGap - iOS Background Geolocation template,
see iOS Background Geolocation with PhoneGap

For the full transistorsoft/cordova-background-geolocation-lt plugin documentation,
see cordova-background-geolocation-lt

 

Style Builder - A new Style Builder is available for Alpha Anywhere V3 Styles - Alpha Anywhere styles that were released in older versions of Alpha Five (e.g. MobBlue, MobGreen, GrBlue, etc) are tagged internally as 'version 2' styles. Newer styles (e.g. iOS, iOS7, AndroidLight, AndroidDark) are tagged internally as 'version 3' styles.

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

A new Style Builder is available for 'version 3' styles. Previously it was not possible to edit a 'version 3' style in the 'version 2' style builder.

Now, when you try to edit a style, Alpha Anywhere automatically selects the appropriate style builder.

 

There are several ways to get to the style builder. The easiest is to open the UX or Grid component and click the smart field button for 'Edit style in Style Builder'  property (which is just below the Style Name property).

You can also select the Edit, Open Web Style Builder command from the menu when the Web Control Panel has focus.

Alpha Anywhere web styles can be stored in one of three places:

When you select a style to edit, if you selected a 'system' style, you will get a dialog asking you to make a 'local' or 'global' copy of the style.

When you make a copy of the style you can keep the same name as the source ('system') style, or you can give the style a new name. Since the local or global style is stored in a different folder than the system style, it is perfectly OK to use the same name as the source ('system') style.

 

 

If you selected a version 3 style the new style builder will be displayed:

 

 

The Style Builder has two distinct modes.

Alpha Anywhere styles sheets are defined using SASS syntax. To learn more about SASS visit http://sass-lang.com/

One huge advantage of SASS syntax is the ability to define variables for many of the setting in the stylesheet, especially colors.

The Adjust mode allows you to easily adjust the SASS variables in your stylesheet. For example if you use the built-in iOS7 stylesheet you will see that the predominant color in the style is blue. By changing a single SASS variable in Adjust mode you can change the entire

The tabs at the bottom on the screen allow you to switch between Adjust mode and Code mode.

 

Code Mode

In Code mode the left side of the screen has a preview of the style in the top and the actually CSS in the bottom.

The property grid on the right shows all of the "object" types defined in the stylesheet. Examples of "objects" include Textbox, Button, Accordion.

For each object type one or more named sub-types can be defined. The sub-types are called 'sub-themes'. Generally every "object" has at least one 'sub-theme' called 'base'. For some object types only 'base' sub-theme is defined. You can add an arbitrary number of sub-themes for any object type.

A sub-theme defined all of the CSS classnames used to style the object.

At the top of the code window when you are in Code mode you will all of the SASS variables defined in the stylesheet.

You can adjust the variable values directly in the Code window or you can switch to Adjust mode to change the SASS variables.

 

 

 

 

UX and Grid Component - Open Style Builder - You can now open the Style Builder directly from the UX and Grid component. A new property 'Edit style in Style Builder' appears directly below the 'Style name' property.

 

 

Application Server - Open SSL - A new version of OpenSSL is now included with Alpha Anywhere.

OpenSSL 1.0.2g addresses the 'Drown attacks' vulnerability.

 

UX Component - Sub-theme Picker - Preview - When you pick the sub-theme for any control that supports sub-themes, the picker now shows a preview of all of the available sub-themes.

 

 

 

 

PhoneGap Builder - SQLite Databases - When you create a PhoneGap project, you can now include pre-populated SQLite database files as part of the PhoneGap project. A new genie allows you to create the SQLite databases that you include with your PhoneGap project.


Watch Video 1
Watch Video 2

 

If your PhoneGap project includes pre-populated SQLite databases, your UX component can work with the data in these SQLite databases using Action Javascript. See 'UX Component - PhoneGap - Using SQLite - Action Javascript' below for more information.

If you are including pre-populated SQLite databases in your project, be sure to specify the following PhoneGap plugins: Device, File, File Transfer, SQLitePluginExt.

To define the SQLite databases that should be part of your PhoneGap project, click the smart field for the SQLite Databases property in the PhoneGap Genie.

 

 

 

This will open a dialog where you can define your SQLite databases.

Your project can include multiple SQLite databases and each database can include multiple tables. Each SQLite database is contained in a single file and this file is automatically added to the Additional Files Required setting in the builder.

You can choose to put all of the tables you want in your SQLite databases in a single SQLite database, or you can use multiple SQLiite databases - the choice is yours.

 

 

 

Once you add a new SQLite database to the above dialog, you can click the Define SQLite Database Contents button to specify the tables that should be in the SQLite database. For each table that you specify you can define how the table should be populated. The options are to perform a SQL query to extract data from any SQL database supported by AlphaDAO, static data, or Xbasic. If you choose the Xbasic option, you can specify Xbasic code that will return data that are used to populate a table.

Once you have defined the SQLite databases, click the Create SQLite Database Files button to actually create the SQLite database files. These files will be created in the www folder in your PhoneGap project.

 

NOTE: Contrast creating pre-populated SQLite databases with making an Ajax callback to the server and dynamically creating the SQLite database. Dynamically creating SQLite databases is a built-in action in Action Javasascript and it is discussed below. See UX Component - PhoneGap - Using SQLite - Action Javascript.

 

 

UX Component - PhoneGap - Using SQLite - Action Javascript - The UX component now has extensive support for working with SQLite databases in a PhoneGap application.

SQLite is a SQL database that is available on your mobile device and is accessible through a PhoneGap plugin. When building disconnected applications, having an on-device SQL database can be extremely useful. It allows you to get rapid access to large amounts of data that are stored on the device (and is therefore available even when there is no connection). You can store significantly more data for offline access than would be possible using Local Storage.

The primary use case for an on-device SQLite database is to make large amounts of 'lookup' information available in a disconnected, mobile application.

 

Watch Video 1
Watch Video 2
Watch Video 3
Watch Video 4
 

NOTE: The UX Component Client-side Data Cache is also useful, in PhoneGap applications, for storing large amounts of data on the mobile device for use in offline applications. Your particular application requirements will dictate if the Client-side data cache, or SQLite, is the better solution.

 

IMPORTANT: To use the SQLite features in a PhoneGap application, your PhoneGap project must load the following plugins: Device, File, File Transfer, SQLitePluginExt. These plugins are all listed in the PhoneGap builder.

NOTE: While it is certainly possible to perform Insert, Update, and Delete actions on the SQLite database that is on a device, there is no built-in mechanism for persisting these changes to the source database on your server. You would be responsible for writing your own code to persist changes to the on-decice SQLite database to your server databases.

 

A SQLite database is a single file. The SQLite database file can be part of your PhoneGap project, or it can be downloaded to the device by making a callback to a server.

If the SQLite database is part of your PhoneGap project, you will need to list the name of the SQLite database file in the Additional Files Required property in the PhoneGap Builder.

 

 

NOTE: For more information on adding SQLite database to a PhoneGap project, see this section : PhoneGap Builder - SQLite Databases.

 

You can use Action Javascript to download a SQLite database to the mobile device at run-time (see below for more information). When you download the SQLite database to the device at run-time, you can either download an existing SQLite database, or your callback function can dynamically create the SQLite database file.

 

Action Javascript now has a new action called 'PhoneGap - SQLite Actions' that will allow you to select and configure the type of action you want to perform.

 

 

When you select this action, the builder shows the available SQLite actions:

 

 

 

The available action are:

 

Command Description
Download SQLite Database from the Server Downloads a SQLite database file from a server and stores the database file on the mobile device
Create SQLite Database on Server then Download to Device Similar to the 'Download SQLite Database from the Server' action excepting that the SQLite database file is dynamically created on the server before it is downloaded to the device
Execute SQL statement(s) Executes one or more SQL statements. If you execute multiple SQL statements, the statements are automatically wrapped in a transaction so that no changes are made to the database if any of the statements fail.
Get Tables in a Database Lists the tables in a SQLite database.

 

Each of these commands in discussed in more detail below.

 

 

Download SQLite Database from Server

Use this action to fetch a remote SQLite database file from a server (does not have to be the Alpha Anywhere server) and store the database on the mobile device. Once the database has been downloaded, you can then start executing SQL commands against the tables in the database.

There are two ways in which this action can be used:

  1. Specify the URL of the remote SQLite database file (using Javascript).
  2. Make an Ajax callback to the Alpha Anywhere server. The function that handles the callback will be responsible for returning the URL of the SQLite database file.

If you are using option 1, then you will need to specify Javascript code that returns the URL of the SQLite database file.

Examples:

Assume that the SQLite database files is in a folder in the webroot. The relative filename of the SQLite database file is (for example) sqlite/db1.db. Your Javascript code that returns the URL will therefore be:

return 'sqlite/db1.db';

 

There is no need to specify a protocol for the URL since the resource is relative to the webroot.

If, on the other hand, the SQLite database file was (for example) in an Amazon S3 bucket, your Javascript code might be:

return 'http://name_of_your_s3_bucket.s3.amazonaws.com/sqlitedbfilename.db';

 

Id you are using option 2, you must specify an Xbasic function that will handle the Ajax callback. The Xbasic function will return the URL of the SQLite database file (by setting the e.URL property in the Xbasic code).

 

Create SQLite Database on Server then Download to Device

This action is really just a variant of the Download SQLite Database from Server action. The main difference is that the SQLite database to download to the device is created on the fly by Alpha Anywhere and once the database file has been created, a message is sent to the client (i.e. the mobile device) telling it that the SQLite database file has been created and can now be downloaded to the server.

The SQLite database file is created by populating a SQLite database with data obtained from SQL queries (against your SQL Server, Oracle, MySQL etc. data sources), static data, or from Xbasic code (that returns data to be used to populate the SQLite database).

For example, you might define a SQLite database that contains several tables  (called say 'table1', 'table2', 'table3', etc.) where:

When you select this action, the builder shows this screen:

 

The SQLite Database definition property is where you define how the SQLite database will be created. When you click the smart field for this property you get this dialog.

 

 

 

This dialog allows you to define the tables that will added to the SQLite database.

You can add as many tables as you want. Once you have have added a table (by clicking on the Add table) button, you can then define the data source for that table (by clicking on the Edit table definition) button.

When you click the Edit table definition button you get a dialog as shown below where you can define how the SQLite table will be populated.

The choices are:

 

 

Format for Static Data and Data Returned by Xbasic Functions

If your Query Type is set to either Static or Xbasic, the required format for the data is as shown in the following example:

 

ID=INTEGER (Primary Key),FirstName=TEXT,LastName=TEXT,Salary=NUMERIC
1,Fred,"Smith",87234
2,Tom,Jones,45234

 

Note that the data is in CSV (comma separated value) value format. Values can be quoted if they contain commas.

The first row in the data is the field names. The format for the fieldnames is:

fieldname=fieldtype


There is no need to specify a field size for a SQLite table. The SQLite field types are TEXT, NUMERIC, INTEGER, REAL and BLOB. You can optionally indicate which column in the primary key by including the (Primary Key) keyword after the field type.

 

Execute SQL statement(s)

This action allows you to execute SQL statements against any SQLite database on the device. You can either execute a single SQL statement, or you can execute multiple statements.

If you execute multiple statements, the statements are wrapped in a transaction, which means that the state of the database is not changed if any of the SQL statements fails.

When you select this action you get the following dialog (shown twice - once for the 'Single' statement case and once for the 'Multiple' statement case).

 

 

Executing a Single SQL Statement

 

The properties in the Dialog are defined below:

Your SQL statement can optionally reference arguments (similar to SQL::arguments when using AlphaDAO in Xbasic).

For example, this statement does not use arguments:

select * from customers where id = 'ALFKI'

 

This statement does use arguments:

 

select * from customers where id = ?

 

The ? indicates an argument value.

If your SQL statement uses arguments you must defined the argument values in the Arguments property.

For example, if your SQL statement was select * from customers where id = ?

the Javascript that you define for the Arguments property might be:

return ['Alfki'];

 

 

Example:

Assume that your SQLite database has a table called customers and you want to populate a List control with the results of this query:

select * from customers where city = 'Boston'

 

You might set the onSuccess Javascript to:

 

if(resultArray.length > 0) {

    //populate list 'list1' with data
    {dialog.object}.setListColumnsAndPopulate('list1',resultArray);
} else {
    alert('No records in query.');
}
 

 


 

Executing Multiple SQL Statements

 

 

In the case where you are executing multiple SQL statements you must set the SQL definition Javascript property.

Your Javascript must return an object with these properties:

 

Alternatively, your Javascript can return an array of objects. Each object in the array should have these properties:

Example:

(This example uses the array of objects method. Notice that the parameters passed into the onSuccess functions are: tx, result, array and transObj.

where:

 

Notice how the arguments property for the last object in the array calls a function to set one of the argument values. This function can see the transObj variable.

)

 

 

var obj = [];
obj.push( { sql: 'drop table if exists cars', onSuccess: function(tx,result,array,transObj) { alert('table was dropped'); }} );
obj.push( { sql: 'CREATE TABLE Cars (Id INTEGER PRIMARY KEY, Name TEXT, Price INTEGER)'} );
obj.push( { sql: 'insert into cars (name,price) values (?,?)', arguments: ['Ford',1], onSuccess: function(tx,result,array,transObj) { transObj.foobar = 123;} });
obj.push( { sql: 'insert into cars (name,price) values (?,?)', arguments: ['GM',2] } );
obj.push( { sql: 'insert into cars (name,price) values (?,?)', arguments: ['Honda',3] } );
obj.push( { sql: 'insert into cars (name,price) values (?,?)', arguments: ['Toyota',function(transObj) { return transObj.foobar; } ] } )
return obj;

 

 

 

NOTE: When you edit the Javascript for the  SQL definition Javascript property, the Javascript editor shows extensive help for how to construct the object for the SQL definition object.  For example, the help shows how you can do the following task:

 

You can also define these properties:

 

How to Create a New SQLite Database on a Device

When you want to start working with a SQLite database on a mobile device there is no requirement that you either download an exiting SQLite database from the server or include a pre-populated SQLite database in your PhoneGap application. You can simply create a new SQLite database on the fly in your Javascript code.

When you use the 'Execute SQL statement(s)' action in the 'PhoneGap - SQLite Actions' action, you specify the name of the SQLite database name against which the SQL commands should be executed.

If you specify the name of SQLite database that does not exist, then a new SQLite database will automatically be created.

 

 

 

 

 

 

Xdialog - {treatasform} Directive - If a modeless Xdialog is displayed and then all Alpha Anywhere windows  (besides the modeless Xdialog) are closed or hidden, then once the last window is hidden, the Workspace itself will be closed.

For example, consider the following sample Xdialog code.

 

dim dlg_title as c 
dlg_title = "test"
dim dlg_body as c
dlg_body = <<%dlg%
<close><hide><show>
%dlg%
dim dlg_event as c 
dlg_event = <<%code%
if a_dlg_button = "close" then 
    ui_modeless_dlg_close(dlg_title)
else if a_dlg_button = "hide" then 
    controlpanel.hide()
else if a_dlg_button = "show" then 
    controlpanel.show()
end if 
%code%
ui_modeless_dlg_box(dlg_title,dlg_body,dlg_event)
 

 

Once you press the 'Hide' button to hide the Control Panel (assuming that there are no other Alpha windows open at the time), the Workspace will closed, and therefore the "Show" button, which is intended to show the Control Panel, will not work.

You can instruct Alpha Anywhere not to enforce this rule by adding the {treatasform} directive to the Xdialog. This will cause Alpha Anywhere to not close the workspace when the last window (not counting the Xdialog) is closed.

 

dim dlg_title as c 
dlg_title = "test"
dim dlg_body as c
dlg_body = <<%dlg%
{treatasform} 
<close><hide><show>
%dlg%
dim dlg_event as c 
dlg_event = <<%code%
if a_dlg_button = "close" then 
    ui_modeless_dlg_close(dlg_title)
else if a_dlg_button = "hide" then 
    controlpanel.hide()
else if a_dlg_button = "show" then 
    controlpanel.show()
end if 
%code%
ui_modeless_dlg_box(dlg_title,dlg_body,dlg_event)
 

 

UX Component Builder - Display Line Numbers in the Controls List - You can now turn on the display of line numbers in the control list in the UX builder. In large components, this will make it easier to find a control quickly.

 

Watch Video
 

 

 

To toggle the display of line numbers, click on the Menu button and select the Toggle line numbers in Controls display menu item.

You can also go to the Properties pane and check the Show line number in Controls list property.

 

 

 

TIP: You can easily navigate to a control by number by pressing the Ctrl-G shortcut key.

 

 

UX Component - List Control - Pull-past-End to Refresh List Data - You can now easily implement the common 'pull-past-end-to-refresh' List data pattern.

Watch Video

 

To turn on this behavior, open the List builder and check the Has 'pull-to-refresh' behavior property.

 

 

You can then configure the settings for the behavior.

 

 

The Convert to low level properties checkbox on the builder allows you to see all of the individual properties that get set to implement this behavior. If you want to customize the behavior beyond what this genie allows, check this box.

 

 

AlphaDAO - SQL - DateTime Fields - SQL::Resultset.toJSONObjectSyntax() - Datetime fields are now exported using an increased precision. Previously, the default format for date time fields was:

MM/dd/yyyy 0h:0m:0s   (or dd/MM/yyyy 0h:0m:0s if set by Windows regional settings).

Now, the default format is:

MM/dd/yyyy 0h:0m:0s 3

 

Technical Note: This change will solve the following problem: Assume that you had a SQL table with a field called (for example) 'ExaminationDate' and that the value in the field was 2/18/2016 3:24:10 123. Assume that you then built a UX component with a List control with a Detail View to allow users to edit this value and that you had write conflicting checking turned on for the ExaminationDate field.

When the user tried to synchronize the data after making a change to the ExaminationDate field they would get a write conflict error because the 'old' value for the ExaminationDate field was stored as 2/18/2016 3:24:10  and not 2/18/2016 3:24:10 123. With the above change, the 'old' value for the field stored in the List will be stored at the field's full precision, and the update will succeeed.

 

 

UX Component - Custom Settings - Custom settings are named setting values that you can reference in JavaScript code and in your component definition.

Watch Video - Part 1
Watch Video - Part 2

Download Component

 

To define Custom Settings go to the Properties Pane in the UX builder. The Custom settings property appears in the Advanced section.

 

 

Click the smart field and the Custom Settings dialog is shown.

 

 

 

The dialog allows you to create an unlimited number of custom settings. Each custom setting has a name and a value.

If the value is a string, just enter the string value. If the value is a JavaScript object, you must prefix the definition with '{javascript}'. If the value is a function definition, you must also prefix the value with '{javascript}. In the example below, three custom settings are defined showing how the value of the custom setting is set to a string, object and function:

Custom Setting Name Value
setting1 Some string value
setting2 {javascript}{name: 'Fred', city: 'Boston'}
setting3 {javascript}function(name) { alert('Hello name.toUpperCase());}

 

You can export Custom Setting definitions and import them using the Export and Import hyperlinks at the bottom of the screen.

 

Using Custom Settings

Custom settings can be used in your Javascript code and also at the time the UX component is rendered.

 

Using Custom Settings when a Component is Rendered

When you define the properties of a UX component, any place that you define some text you can use a Custom Setting value using this syntax:

[CustomSetting:settingName]

 

For example, assume you have a Button control in your UX. You could set the Button text to:

[CustomSetting:button1]

 

If you had defined a Custom Setting called 'button1' with a value of 'Save new record' then when the UX component was rendered, the label on the button would be 'Save new record'.

 

Using Custom Settings in JavaScript Code

The UX object has a method that allows you to read and set Custom Setting values:

{dialog.object}.customSetting(settingName [, newSettingValue])

 

If you do not provide the optional second parameter the method is used to read the value of a Custom Setting. If you provide the second parameter, the method is used to update a Custom Setting value.

For example, assume you had defined a Custom Setting called 'string1', with a value of 'this is the value of string1'. You could use this in your JavaScript code:

var txt  = {dialog.object}.customSetting('string1');

alert(txt);

 

If the value of 'string1' had been set to an object (using this for the value: {javascript}{name: 'Fred', city: 'Boston'} ), then your JavaScript might look like this:

 

var obj = {dialog.object}.customSetting('string1');

alert(obj.name + ' -- ' + obj.city);

 

If the value of 'string1' had been set to a function (using this for the value: {javascript}function(name) {alert('Hello ' + name);} ), then your JavaScript might look look like this:

 

var fn = {dialog.object}.customSetting('string1');

//now call the function

fn('Fred');

 

To set a new value for the 'string1' Custom Setting:

{dialog.object}.customSetting('string1','this is a new value for string1');

 

Overriding Custom Settings when Opening a UX Component

When you use Action Javascript to define an action that opens a UX component, if the target UX component has defined any Custom Settings, you can override the value of the Custom Settings.

In the image shown below, the Action Javascript action opens a UX called 'uxWithCustomSettings'. Since this UX has defined some Custom Settings, the dialog shows an option to override any of the Custom Setting values.

 

Note The overrides defined here are applied when the UX is initially rendered. If this action is called from a button and the target UX is opened in a Window and the 'Use cached UX Component' property is checked, the second and subsequent times the button is clicked to open the target UX, the Custom Settings are remain at the values they were set to when the target UX was initially opened.

 

Using Language and Text Dictionary Tags in Custom Settings

You can use language tags (<a5:r>...</a5:r>) and text dictionary tags (<a5:t>...</a5:t>) in the Custom Setting values.

 

 

UX Component Builder - Buttons and StaticText Objects -  Double-clicking on a Button in the UX Builder will now open the editor to edit the click or onClick event for the button. Similarly, double clicking on a static text control will bring up the text editor.

MongoDB - Using MongoDB in Grid and UX Components and with Xbasic AlphaDAO - Alpha Anwhere has an API for working directly with a Mongo database. This API is useful if you want to write your own server side code to query and update a Mongo database. However, if you want to use a Mongo database as the data source for a Grid, or UX component, you cannot use the API.

In order to use Mongo as the data source for a Grid or UX, it is necessary to impose a schema on the Mongo database, much like any SQL table has a schema.

Alpha Anywhere now allows you to define a connection string to a Mongo database (much like you would define a connection string to any SQL database). Once you have define a connection string, you can build Grid and UX components against the Mongo database in exactly the same way that you would build a Grid or UX against any SQL database. You can also use AlphaDAO in Xbasic to perform CRUD operations against the Mongo database

When you define a connection string to a Mongo database you define a schema for each table  (i.e. collection) in the database. This schema defines the fields and data type of each field in each table.

When you define a connection string to a Mongo database you define:

The image below shows the connection string builder for a Mongo database.

 

NOTE: In the above screenshot the manifest filename stats with '.\'. This syntax is used to indicate the the manifest is stored relative to the Web Project folder. In the above example, the manifest will be stored in a folder called 'schemas' in the Web Project folder, and when the project is published, the schema.json file will be published to a folder called 'schemas' in the web root.

 

 

Alpha Anywhere has a number of helper function that help you define the schema for the Mongo database.

 

Structure of the Schema JSON File

A sample schema JSON file is shown below. The JSON file defines two objects, 'schema' and 'collection' and an optional property, 'sourceconnection'.

 

The 'collection' object contains a property for each collection in the Mongo database and the name of the corresponding schema in the 'schema' object.

For example, the entry in the 'schema' object shown below specifies two schemas, one called 'Categories' and another called 'Employees'. For each schema, the primary key column is specified and the list of columns and their corresponding data type are identified.

The optional 'sourceconnection' identifies if the schema was obtained from a looking at the schema in some other SQL database.  If so, the 'sourceconnection' property is the connection string to that database.

 

			
{
    "schema": {
        "Categories": {
            "primary": [
                "_id"
            ],
            "columns": {
                "_id": "String",
                "CategoryID": "Number",
                "CategoryName": "String",
                "Description": "String",
                "Picture": "String"
            }
        }
        "Employees": {
            "primary": [
                "_id"
            ],
            "columns": {
                "_id": "String",
                "EmployeeID": "Number",
                "LastName": "String",
                "FirstName": "String",
            }
        }
    },
    "collection": {
        "Categories": {
            "schema": "Categories"
        },
        "Employees": {
            "schema": "Employees"
        }
    },
    "sourceconnection": "::Name::northwind"
}
			
		

Creating the Schema

To define the Mongo database schema, click the More... button on the connection string build.

 

 

This will open an intermediate dialog:

Then click the 'Edit/create Schema definition...' hyperlink.

This will open a dialog when you can edit the schema definition.

 

 

 

At the bottom of the dialog you will see several hyperlinks:

 

More on the 'Guess From Content...' Option

When you click the Guess From Content... button, Alpha Anywhere will examine the data in the Mongo database specified at the 'Database' prompt on the connection string builder. This is the dialog that was displayed before you clicked the 'More...' button to get to the dialogs when you define the schema.

 

 

 

Using a MogoDB Connection String

Once you have built the connection string to the MongoDB database you use it in the same way that you use any other connection string (that connects to SQL databases). You can build Grid and UX components against the Mongo database. You can also use Xbasic and AlphaDAO objects to work with the data in the Mongo database.

When you use a connection string that points to a Mongo database you are essentially using SQL syntax to interact with the Mongo database. Behind the scenes Alpha Anywhere is automatically converting the SQL commands to the appropriate commands that then Mongo API understands.

You can see how Alpha Anywhere makes this translation but turning on the 'Trace SQL' option in the connection string build (shown below). Once you do this, the trace information will be shown in the Trace window (View, Trace window) if you are working in the Alpha Developer Version - i.e. the IDE) or in a folder where your logs are created if you are in the Server.

 

Here is some sample output from the Trace window showing the SQL statement and how that statement was translated to Mongo commands.

 

SQL Statement: SELECT FIRST 11 [_id], CustomerID, CompanyName, ContactName, ContactTitle, City, Country FROM Customers ORDER BY ContactTitle, [_id]
Time to prepare URL: 0.001
Time to execute REST call: 0.041
Mongo Commands:
{
    "verb": "GET",
    "collection": "Customers",
    "select": "_id , CustomerID , CompanyName , ContactName , ContactTitle , City , Country",
    "groupby": "",
    "where": {},
    "orderby": "ContactTitle, _id",
    "limit": "TOP 11 "
}

 

Because Mongo is not a SQL database, there are obviously limitations as to what SQL commands you can send to Mongo. For example, you cannot execute a SQL statement that performs a JOIN since the concept is meaningless to Mongo. You also cannot perform CRUD operations that affect more than a single record. For example, the following SQL statement will update multiple records

UPDATE customers set Status = 'B' where Balance > 100

This will not work if you are connected to a Mongo database if there is more than one record with a Balance that is > 100.

 

 

 

 

 

 

 

Grid Component - Arguments - Array Arguments - IN Clause in SQL Statements - You can now use the IN clause in a SQL statement in a Grid, where the IN clause is tested against an argument.

For example, you might set the SQL query for a Grid to

Select * from customers where customerId IN (:array_customerIds)

 

IMPORTANT: The parentheses around the argument in the above SQL statement are required when using an IN clause.

 

The argument in the above SQL is 'array_customerIds'. The 'array_' prefix in the array name is significant. It informs Alpha Anyhwere that the argument is an 'array argument'

When you define the 'array_customerIds' argument in the Grid you might (for example), bind the array to a session variable. For example, you might bind the argument to session.whatCustomerIds.

The session variable would be set to a comma delimited list of values.

 

 

 

  Report Events - BeforePrint and AfterPrint - You can now define two new events for Reports. The beforePrint event fires before any report is printed and the afterPrint event fires after any report is printed.

These events must be defined in an Xbasic Function Library. The name of the functions to call to handle these events are defined in the Web Project Properties dialog, as shown below.

 

Xbasic - AlphaDAO - SQL::Resulset.ToCSVFile() and .ToStringFile() - Two new methods on the SQL::Resultset object allow you to create a file directly without first having to call .toCSV() or .toString() to create an intermediate variable.

 

 

List with Detail View - Synchronizing Data - Synchronization Log Table - The synchronization log table helps prevents a sync command being processed more than once.

If you do offline-data entry in a List, there is a small chance that the SQL updates to the underlying table will be executed more than once. This can happen if the mobile device loses connectivity to the server AFTER the synchronize command has been received by the server, but BEFORE the mobile device has received the response from the server. Under this condition, the next time the List is synchronized, the previously submitted edits will be submitted a second time. By checking the 'Use server-side synchronization log table' property, a special server-side log can be used to prevent the possibility of duplicate SQL updates. When you check this property an extra Ajax callback fires after the client-receives acknowledgement from the server that the synchronization was performed.
 

By default, after a successful sync, the sync log table is cleared out.

Now, a new property has been added to not clear the sync log table automatically. This provides an extra level of protection against duplicate sync commands being executed by the server.

NOTE: If you turn the 'Clear sync log table after successful sync' off, then may need to periodically clear our the sync log table manually as it will continue to grow as users sync their data.

 

Application Server - SSL - Alpha Anywhere now includes the latest stable release of OpenSSL, version 1.0.2f.

Why make the change?

No coding changes were required in Alpha Anywhere to move to OpenSSL 1.0.2.

For more information on OpenSSL releases please go to: http://www.openssl.org

 

a5_sqlToJSONTree() Function - Generates a JSON tree structure from a SQL database table - To display cascading data in a List control (i.e. user selects an item in the List and a sub-list is displayed and a back button is enabled to allow user to navigate to the previous list) a new helper function has been added to Xbasic.

 

Watch Video

 

The function will generate the JSON for the hierarchical List.

 

The function takes the name of a table and a list of fields. For example, if the field list is Country, City, ContactName, the generated JSON data will have a list of Countries. In each Country record there will be a nested array of Cities and in each City record there will be a nested array of ContactNames.

The syntax for the function is:

c JSON = a5_sqlToJSONTree as c (c connectionString, c table,c fieldList [, c endPointFfieldName [ ,c filter  [,c order [p arguments]]]])

Where

Example
 

dim args as sql::Arguments
args.add("c1","USA")
args.add("c2","UK")
json = a5_sqlToJSONTree("::name::northwind","Customers","Country,City,ContactName","CustomerID","Country = :c1 or Country = :c2","",args)

 

A partial listing of the JSON returned by the above function call is shown below:

Notice that for each 'endpoint' the display value is the ContactName, but the 'action' property is set to the CustomerID.


 

[
    {
        "display": "UK",
        "children": [
        {
            "display": "Cowes",
            "children": [
            {
                "display":"Helen Bennett","action":"ISLAT"
            }
        ]
    },
    {
        "display": "London",
        "children": [
        {
            "display":"Ann Devon","action":"EASTC"
        },
        {
            "display":"Elizabeth Brown","action":"CONSH"
        },

        ........
 

 

 

FormView Control - API Changes - The FormView Control API has been changed to simplify the passing of data to the Editors that are associated with fields in the FormView control. As a result of this change, existing UX components that use the FormView control will not be affected. But you should use new syntax when building new Editors.

For example, this syntax

settings['*a5column'] is replaced with settings.formView.active.path

settings.data is replaced with settings.formView.data

All information dynamically generated by the FormView when an Editor is invoked is now encapsulated in the settings.formView namespace. This reduces the chances of a user's settings conflicting with system settings.

 

 

Calling SOAP Services - A new set of genies makes it easy to register and call SOAP services from Xbasic code.
 

Watch Video

 

The Web Projects Control Panel has a new category called 'Web References' where your registered SOAP services are displayed.

 

 

To register a new SOAP web service, select the Web References category in the Web Projects Control Panel and then click the New button.

This will open the New Web Reference dialog where you can register your SOAP web service.

At the 'Service address' prompt, enter the URL of the service WSDL. For example:

http://bernera.zapto.org/astronomy/astronomy.asmx?WSDL

 

Also specify the local name of the service. This can be any name you want.

Once you click the OK button, Alpha Anywhere will create a proxy file in the bin\webreference folder in the web projects folder. The proxy file has the same name as the the Name you entered into the New Web Reference dialog and it has a .dll.

 

NOTE: When you publish your Web Project the 'bin' folder will automatically be published. Your Xbasic code that calls the SOAP service will need to be able to reference the proxy .dll file at run-time.

 

Once you have create the Web Reference you can explore it method by double clicking on the entry in the Web Control Panel:

 

 

This will open the Explorer. The explorer shows the methods exposed by the service and the arguments for each method and the return values for each method.

 

 

 

 

Calling a Registered SOAP Service from Xbasic

Once you have registered your SOAP service as described above, you can call it from your Xbasic code. A genie will help you write the Xbasic code.

 

To get to the genie open the Xbasic editor where you will be writing your Xbasic function to make the SOAP call (this might in the Xbasic Function Declarations section in a component, or while exiting an Xbasic Module file), and right click on white space.

Then select the Genies...., Web Reference Call... menu item.

 

 

 

This will then bring up a dialog where you can select the Web Service you want to call. The list of services that you previously registered are shown here.

 

 

 

Once you select the service, the Explorer is shown where you can choose the method that you want to call.

 

 

 

Finally, when you press the OK button, Alpha Anywhere generates the sample Xbasic code needed to call the service. You can paste this code in the Xbasic function you are writing.

 

 

 

Web Applications - Publishing - HTTP Publishing - When you publish a web application to a remote server you first define the Publishing Profile to use. The publishing is currently accomplished by using FTP to upload the files to the remote server. Now, a new way of publishing files to a remove server is available using the HTTP protocol.

Watch Video - Configuring the Server
Watch Video - Defining a Publishing Profile
 

The HTTP Publishing method requires that the Alpha Anywhere server on the remote site be running because the Alpha Anywhere server is actually handling the uploading of the data.

The HTTP Publishing method is more reliable and faster than the FTP method.

For more details on HTTP Publish, click this link:

http://downloads.alphasoftware.com/a5v12Download/ReleaseNotes/HTTPPublish/httpPublish.html

 

PhoneGap App Builder - Third Party Plugins (iOS) - Keyboard Plugins -  Added support for the cordova-keyboard and the ionic-keyboard plugins. These plugins provide functions to make interacting with the iOS keyboard a bit easier and include events to indicate the keyboard will show/hide.

For the full plugin documentation, see the links below.

cordova-plugin-keyboard
cordova-plugin-ionic-keyboard


PhoneGap App Builder - Third Party Plugins (Android, iOS) - Media With Compression Plugin - The Alpha cordova-media-with-compression plugin has been updated to include three (3) new methods.


For the full plugin documentation, see the link below.

cordova-plugin-media-wth-compression
 

 

UX Component - Data Binding - Server-side Save Submitted Data to Table(s) Action - onSQLError Event - A new event has been added to the action to allow you change the error message shown to the user when a SQL database error occurs.

For example say that the user tries to enter a new record. When the INSERT SQL statement is executed, the database returns some error (perhaps a foreign key violation). The error message returned by the database is displayed to the user. However, this error message is often quite cryptic and is certainly not 'friendly'. The onSQLError event handler allows you to intercept the error before it is displayed to the user and replace it with a friendlier message.

 

 

TabbedUI Component - Keyboard Shortcuts - You can now define keyboard shortcuts for the action buttons in a TabbedUI component.

Watch Video

To define a keyboard shortcut for a TabbedUI button, click the smart field and select the key combination. The user will be able to open the component by using the keyboard shortcut in addition to clicking on the button.

 

UX Component - Server-side Events - canAjaxCallback - afterAjaxCallback - Two new server side events have been added:

 

 

In the canAjaxCallback event handler, if your code sets:

e.authorized = .f.

 

then the Ajax callback action will not be performed. Your code can examine data in request.variables to see what type of callback was being attempted.

 

In the afterAjaxCallback event, the 'e' object that is passed into the event handler contains:

e.ajaxResponse

 

Your code can modify this response.

 

UX Component - List Control - SQL Datasource -  beforeQuery  - The beforeQuery server side event fires before a query is performed to get data for the List.

 

 

The event allows you 'authorize' the query.

In your Xbasic code in the function, you can set:

e.authorized = .f.

 

This will cause the query for the List data to return no data.

 

 

 

UX Component - CustomControl - 'Other Controls' - A new control type has been added to the 'Other Controls' section in the UX builder:

 

 

The CustomControl allows you to specify arbitrary HTML and Javascript for the control. You can specify the HTML and Javascript at design-time, or you can specify an Xbasic function that will generate the HTML and Javascript for the control at run-time.

A very powerful use case for the CustomControl is to dynamically generate a form based on a definition stored in a database.

 


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

 

When you add a CustomControl to a UX component, the PropertySheet for the control is displayed as follows

 

Clicking on the smart field for the Custom Control Properties brings up the builder.

 

If you select the 'Specify Now' option in the Custom Control builder you can specify the HTML for the control and (optionally) any Javascript you want to execute before the UX is 'prepared' and after the UX has been rendered.

 

 

For example, if you wanted your CustomControl to render a standard UX component input control (called, say, 'CUSTOM1')  you would add this code to the HTML:

 

<input id="{dialog.componentname}.V.R1.CUSTOM1" name="V.R1.CUSTOM1" class="{dialog.style}Edit" ></input>
 

And you would add this Javascript to the 'Javascript - Before Prepare' property:


{dialog.object}.columnInfo['CUSTOM1'] = { info: {controlType: 'Textbox'}, hiddenVal: false, type: 'input,label', isCalc: false, hlp: '', isArray: false, dataType: 'C' };
 

On the other hand, if you wanted your CustomControl to render a standard UX component button control (with an ID of, say, 'B1') you would add this code to the HTML:

 

<div id="B1" style="width: .5in;">MyButtonGoesHere</div>

 

And you would add this Javascript to the 'Javascript - After Render' property:


//add an event handler for the button
$e.add('B1',A5.d.evnts.click,function(e) {
alert('this is button b1');
},this,false,'B1');


//define a  new button object
{dialog.object}._buttons['B1'] = new A5.Button({
layout: 'text',
style: 'box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; -webkit-box-sizing: border-box; width: 1.5in;',
html: 'Button',
onClick: function() {
},
theme: '{grid.style}'
})
 

//bind the button object to the html element
{dialog.object}._buttons['B1'].bind('B1');

 

 

If you wanted to generate the HTML and Javascript at run-time you can set the Method to 'Xbasic' and then define an Xbasic function that generates the HTML and Javascript.

 

 

 

PhoneGap Shell Template UX Component - Statusbar Plugin - iOS - The template UX component that implements a PhoneGap shell has been modified so that it now uses the PhoneGap Statusbar plugin. When running the Shell UX on an iOS device the status bar will now display above the UX component. Previously, the status bar was overwritten by the UX component. The code that implements this is in the UX components onPhoneGapReady client-side event.

NOTE: Search for PhoneGap - PhoneGap Shell - for more information on the PhoneGap Shell.

UX Component - List Control - Lists with Detail View - Synchronization - onSynchronize Server-side event -  The onSynchronize event fires when the user clicks the synchronize button on the UX to submit edited List rows to the server. The primary purpose for this event is to allow the developer to take complete control of the synchronization process and implement a custom handler to synchronize the edited List data.

When the user synchronizes a List with a Detail View, the dirty List records are submitted to the server. If the List is based on SQL queries, the CRUD operations to update the database are automatically computed by Alpha Anywhere. However, you may want to process the dirty List data yourself.

 In the case where the List is not based on SQL queries, you have no choices - you have to handle the List synchronization yourself.

 

 

NOTE: If the List is not based on SQL queries, the List Builder also has these events:

 

 

The onSynchronize server-side event is a higher level event that fires before any of the 'Synchronization Handler' events are fired. For example, the 'Commit data handler function' is called after the server has processed validation rules. The event is called once for each dirty composite record submitted to the server.

 

 

Application Server - Self-Signed Certificates - Self-signed SSL certificates are now signed using the SHA-256 algorithm. Previously they were signed using the md5 algorithm, which is no longer considered secure for these purposes. It is still recommended that a public-facing server use a certificate from a commercially supported Certificate Authority (e.g. Verisign, Comodo, GoDaddy, etc.) for browser compatibility, but this change increases security in situations where self-signed certificates are desired.
 

UX Component - PanelOverlay - Windows - A new property has been added to PanelOverlays to make the PanelOverlay behave like a window. When the 'PanelOverlay is window?' property is checked, the PanelOverlay is initially hidden (when the Panel that contains the PanelOverlay is shown).

Watch Video
Download Component
 

To show the PanelOverlay you can use Action Javascript. There are two new actions in Action Javascript:

These actions allow you to animate the PanelOverlay as it is shown or hidden.

NOTE: The animation option uses jQuery. Your application must load jQuery. See the Project Properties dialog (accessed from the Web Applications Control Panel).

.Net Framework v4.6 - Alpha Anywhere now uses .Net Framework v4.61. If the machine you are installing to does not include the .Net Framework v4.61, Alpha Anywhere will install it. It can take quite a bit of time to install the .Net Framework. However, this is a one-time event.

 

Web Applications - Xbasic Error Log - A new warning message is now written to the Xbasic error log if you run a component that was last edited with a build that is greater than the version of the server.

For example, say your server is running using build 4600 and you run a component that was built with build 4610. This is a version mismatch that might cause an error.

For example if the component built using build 4610 calls some function that was added after build 4600, it will definitely lead to a run-time error. On the other hand if the the component does not use any new functionality, then it is unlikely that there will be an error.

Because it cannot be know with certainty if this version mismatch will lead to errors, the message written to the Xbasic error log is termed a 'warning' and not an 'error'.

 

Xbasic - Web Applications - How to Write to the Xbasic Error Log - Xbasic_Write_to_Error_log() - A new Xbasic function allows you to write messages to the Xbasic error log.

The text is written to the error log exactly as specified in the function. Therefore it is recommended that you format the message so that it appears in the log in a useful manner.

For example

dim message as c

message = "Warning: " + crlf() + chr(9) + "This is a warning message" + crlf()

Xbasic_write_to_error_log(message)

 

The message will appear in the log as:

 

Warning:

    This is a warning message

 

 

 

 

UX Component - ButtonList Control - Allow Null Property - The ButtonList now has a new property - 'Allow NULL selection'. The options for this property are:

 

 

 

UX Component - ButtonList - Class name - You can now specify a class name for the items in a ButtonList.

 

 

 

In the above example the class name is set to 'foobar'

Here is how you might want to define this class:

 

.foobar {color: red;}

.{dialog.style}ButtonPressed.foobar {color: orange;}

 

Notice that two CSS selectors are defined.

.foobar - defines the appearance when the Button is not selected

.{dialog.style}ButtonPressed.foobar - defined the appearance when the Button is selected.

 

UX Component - Checkbox and RadioButton Controls - Vertical Alignment - Vertical Spacing - A new property has been added for Radio Button and Checkbox controls that allows you to control the vertical spacing between each item.  The 'Vertical spacing' property is shown when the Orientation is set to 'Vertical'.

 

 

 

 

UX Component - Data Bound Image Control - imageIsEmpty() Method - A new method on the Dialog object allows you to test if an image control is empty.

Example:

var flag = {dialog.object}.imageIsEmpty('PICTURE1');

 

 

UX Component - Explore Structure - A new dialog is available to help you understand the structure of complex UX component layouts.

 

Watch Video

 

When you build large UX components with many Panels, Windows, PanelOverlays, etc. it can be difficult to get an 'overview' of the underlying structure of the component. The new 'Structure View' can help you quickly explore the structure of a UX.

The 'Structure Explorer' is implemented as another view in the Quick Find dialog.

To open the 'Structure Explorer' click the 'Find' button on the toolbar and then select the 'Explore Structure' radio button.

 

UX Component - List Control - Configuring a List Control to Display Nested Lists - A new genie is available to configure a List to display a series of cascading Lists.

 

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

 

To select the Genie, create a new List, then select the 'Quick Access...' button at the bottom of the List Builder. Then select the 'List Quick Setup Genie'. This genie can be used to quickly configure a List that has a data source that defines hierarchical data to display a series of nested Lists.



UX Component - List Control - Static Data Genie - Nested List Data - A new genie is available to help you defined the static JSON data for a List that is intended to display a series of cascading Lists.

For example in the images shown below the List initially displays the data shown in the image on the left. When the user selects an item in the List that has a sub-list (indicated by the icon at the right edge of the List item), the List is repopulated with the sub-choices defined by the item that was selected and a 'back' button is shown. In order to implement a List that behaves in this manner, the List is populated with JSON data that defines the choices for each item in the List.

 



For example, for the List shown in the above two images, the following JSON data is used to populate the List.

 

[
    {
        display: 'Menu1',
        children: [
            {
                display: 'Menu1_A',
                action: 'Action_1'
            },
            {
                display: 'Menu1_B',
                action: 'Action_2'
            },
            {
                display: 'Menu1_C',
                action: 'Action_3'
            }
        ]
    },
    {
        display: 'Menu2',
        action: 'Action_4'
    },
    {
        display: 'Menu3',
        action: 'Action_5'
    }
]

 

Notice that the 'Menu1' item has a property called 'children' that defined the sub-choices for that item. The actual text displayed in the List is defined by the 'display' property in the JSON. Any item in the List can have a 'children' property.



It can be tedious to define this JSON data manually. The 'Nested List Genie' can help you define the JSON. Once you have the basic structure of the JSON defined, you can then make making further edits to the JSON manually. To get to the 'Nested Lists Genie', open the List builder, set the List Data Source to 'Static', click the smart field to open the Static Data dialog. Then click the 'Sample data' hyperlink at the bottom of the dialog (as shown in the image below).

 

 

 




UX Component - Sample Template - MobileAppFramework_with_SplitView_Hierarchical_Menu - When you create a new UX component, a new sample template is available. This template is similar to the MobileAppFramework_with_SplitViewMenu template. The only difference is that, unlike the MobileAppFramework_with_SplitViewMenu, which implements a 'flat' list of choices for the menu, the MobileAppFramework_with_SplitView_Hierarchical_Menu template implements a hierarchical list of menu choices.

 

UX Component - List Control - Paginated List - SQL Data - Change Page Size - You can now dynamically change the page size of a paginated List that is based on SQL data.

For example, say you want to change the page size of a paginated List (called, say, 'LIST1') to 20 records per page.

 

//get pointer to List object

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

//set the new page size
lObj._state.pageSize = 20;'

//refresh the List

dialog.object}.refreshListData('LIST1');

 

 

 

 

UX Component - Embedded Report - HTML - Option Buttons - When a report is embedded into a UX component and is rendered as HTML, the report is displayed with a series of buttons that allow the user to print the report as PDF, export the report to Word or Excel, etc. There was no ability to control which of these buttons were shown. Now, when a report is embedded into a UX, the 'HTML report options' property allows you to control which button are shown.

 

UX Component - Persisting Variables to Local Storage - Variables to Omit - When you build a disconnected application using a UX component, it is typical to persist the variables (i.e. the Data Bound controls in the UX) in your component to Local Storage so that when the application is restarted, the variables (i.e. Data Bound controls) in the UX will have their values restored automatically from Local Storage. However, there may be certain variables that you do not want to persist to Local Storage. For example, your UX may contain a login section that contains a UserId and Password field. You might not want to persist the Password field to Local Storage.

The UX now has a new property that allows you to define an exclusion list. The Variables to NOT persist property in the Local Storage section (on the Properties pane) allows you to select a list of variables.

 

 

 

UX Component - Panels - .resize() Method - A new method has been added to allow you to force Panels (Cards, Layouts and Navigators) to resize themselves. Typically this is not necessary, but if the Panels were initially sized and then the window was resized (and a resize event was not triggered -- for example, the PhoneGap Statusbar plugin), then Panels will have been laid out based on incorrect size information and the .resize() method can be useful.

For example:

var obj = {dialog.object}.getPanelObject()
obj.resize();

 

 

UX and Grid Component - Date Picker - 'Today' Button - A new property in the Date Picker and the Calendar control (UX component) allows you to turn off the 'Today' button.

Web Security - Alpha Anywhere Server - Publishing Data - Publishing Roles - Publishing web security to an Alpha Anywhere server from the Publish genie or the Web Security menu "Publish Security Files" has new options. These are available only if using Optimized FTP publishing. You can now publish security roles without publishing the security tables. The options are:

The option to publish security tables is available in all publish profiles that publish to an Alpha Anywhere server.

UX Components - File Save Format - UX Components can now be saved as formatted JSON instead of binary (the default). Formatted JSON saves the properties in clear text. This is useful if you are using some type of source or version control system and the system has a method to show differences between versions. The save format can be selected in the UX Properties under 'Advanced-> Save component format'.

You can do a bulk conversion of the storage format by selecting the 'Edit, Bulk Operation, Change UX Component storage type' menu option when the Web Control Panel has focus.

 

Xbasic - Dot Variables - .set() Method - A new method has been added to dot variables to allow you to set properties on the variable. The .set() method complements the .data() method which is used for reading a property value.

Example

dim p as p

p.name = "Fred"

?p.data("name")

= "Fred"

p.set("name","John")

?p.data("name")

= "John"

p.set("city","Boston")

?p.city

= "Boston"

 

Reports - Free-Form Reports - UTF8 - SQL Data - Free-form reports that are based on SQL data can now use the full UTF8 character set. This means that reports can now, for example, easily include Chinese, Hebrew, Arabic and other characters on the same report. Previously this was only possible by setting the localization settings on the machine where the Application Server was running. Since you had to pick a particular locale that meant that you could not combine characters from different code pages (e.g. you could not have Chinese and Hebrew on the same report).

This feature can be turned off in web applications in the Project Properties dialog by un-checking the PDF Printing option to "Allow all international character in free-form reports".

For desktop applications, the option can be turned off in "View-> Settings-> Preferences-> Reports-> SQL Support All International Characters". When the feature is off, the reports will use temporary dbf tables for report data.
 

UX Component - Publishing Session Variable Values to Client Side - Ajax Callback - If an Ajax callback made a change to a session variable that had been published to the client-side the value of the session variable on the client-side is now automatically updated.

 

Application Server - Session Variables - Session.Sequence - A change was made to the way session variables are stored internally by the Alpha Anywhere server. This change should not affect any application.

This change makes the method used by the Alpha Anywhere server and the Alpha Anywhere Server for IIS the same and it opens the possibility for a future enhancement to the Alpha Anywhere server to use the IIS session state provider. This will allow for improved scalability and fail over (sessions shared across instances).

As a result of this change a new property is now available on the session object. Session.Sequence is a character value and is an unformatted string representation of a GUID. It will automatically be updated when a session variable is created, modified, or deleted.

UX Component - List Control - Detail View - Synchronizing in Batches -  Client-side Events - The client-side events for batch synchronization - afterSynchronizeListBatch and afterSynchronizeListBatch now both allow your Javascript to reference the e.countInfo object which has information in it about the number of records in each batch, the number of successful updates and the number of errors in the batch.

 

UX Component - Signature Control - .signatureIsEmpty() method - This method has been improved and it now gives accurate answers regardless of the browser that is being used. Previously, the method would be inaccurate for Chrome.

In addition, this method can now be used when the signature control is in 'signing' mode. Previously it could only be used after the user had clicked the 'accept' button to accept the signature.

You can also now pass in an optional second parameter to specify a length parameter The control is considered to be 'empty' if the base64 encoded value of the signature is less than the specified length. Note that even an 'empty' signature will have a non-null value for its base64 encoded value.

 

Reports - Calculated Fields - User Defined Functions - When you create reports you can define calculated fields that use user-defined functions in the calculate field expression.

Now, the user-defined functions that the report references can be defined in an Xbasic Function Library. Previously these functions had to be in an .aex file that was published along with the other files in the project.

Placing the Xbasic functions in a Function Library is more convenient than having to create an .aex file.

NOTE: This feature only applies to Project Reports (i.e. reports defined in the Web Projects Control Panel).

 

To attach an Xbasic Function Library to a report, right click on the report and select the Xbasic Function Library References.. command.

 

 

 

UX Component - Ajax Callbacks - Caching - When an Ajax callback is made to a component, the first thing that the Alpha Anywhere server does when handling the callback is de-serialize the component ( the .a5wcmp file). For very large components, the time taken to de-serialize the .a5wcmp file can be significant (perhaps as much as 200ms). Now, the de-serialized components are cached. As a result, the performance of Ajax callbacks will be improved.

NOTE: Caching is only used on UX component that do not user security or server-side show/hide expressions. For example, if you have a button that is only show to members of the 'Sales' group, caching is not used.

UX Component - List Control - Convert Data Source from Static to SQL or SQL to Static - A new genie in the List Builder allows you to convert the Data Source for a List from Static data to SQL or vice-versa. When you convert the data source from static to SQL, the following options are available:

When you convert the data source from SQL to Static, the following options are available:

 

PhoneGap Applications  - _phoneGapSettings() Function - In PhoneGap applications you can now call a special system function to return information about your PhoneGap application. For example, you might want to know if a particular option was selected, if a particular plugin was loaded or what the application id is.

For example:

To get the application id:

alert( 'app id: ' + _phoneGapSettings().appId );
 

To find out if the sqlite plugin was loaded:



var flagSQL = _phoneGapSettings().plugins['com.brodysoft.sqliteplugin'];

if(typeof flagSQL == 'undefined') flagSQL = false;

 

NOTE: When a PhoneGap application is built, a special .js file called _phoneGapSettings.js is created in the 'www' folder.



Below is a sample of the _phoneGapSettings.js file:


function _phoneGapSettings() {
    return {
        "appId": "com.yourCompany.yourApp",
        "preferences": {
        "permissions": "none",
        "orientation": "default",
        "target-device": "universal",
        "fullscreen": "true",
        "webviewbounce": "true",
        "prerendered-icon": "true",
        "stay-in-webview": "false",
        "ios-statusbarstyle": "black-opaque",
        "detect-data-types": "true",
        "exit-on-suspend": "false",
        "show-splash-screen-spinner": "true",
        "auto-hide-splash-screen": "true",
        "disable-cursor": "false",
        "android-minSdkVersion": "7",
        "android-installLocation": "auto",
        "phonegap-version": "3.7.0",
        "FadeSplashScreen": "true",
        "FadeSplashScreenDuration": "2",
        "EnableViewportScale": "false",
        "MediaPlaybackRequiresUserAction": "true",
        "AllowInlineMediaPlayback": "false",
        "TopActivityIndicator": "gray",
        "BackupWebStorage": "cloud",
        "iosPersistentFileLocation": "Library",
        "KeyboardDisplayRequiresUserAction": "true",
        "SurpressesIncrementalRendering": "true",
        "android-maxSdkVersion": "",
        "android-targetSdkVersion": "",
        "KeepRunning": "true",
        "splash-screen-duration": "5000",
        "ErrorUrl": "error.html",
        "LoadingDialog": "Please wait, the app is loading.",
        "LoadingPageDialog": "Please wait, the data is loading.",
        "LoadUrlTimeoutValue": "20000",
        "AndroidPersistentFileLocation": "Internal"
    },
    "plugins": {
        "battery-status": "npm",
        "console": "npm",
        "device": "npm",
        "file": "npm",
        "file-transfer": "npm",
        "geolocation": "npm",
        "inappbrowser": "npm",
        "media": "npm",
        "network-information": "npm",
        "com.phonegap.plugins.pushplugin": "pgb",
        "com.brodysoft.sqliteplugin": "pgb",
        "com.alphasoftware.plugins.camera.withexif": "pgb",
        "statusbar": "npm"
    }
    };
}

 

 

 

Xbasic - YELP API - You can make requests against the YELP API using Xbasic - The following example shows how to make a request against the YELP API:

Example:

The query syntax for the YELP API is described on the YELP website (see the YELP API dashboard).

Say that the syntax for the query you want to make is as follows:

https://api.yelp.com/v2/search/?location=lexinton ma&radius_filter=10000
 

This query will show businesses within 10,000 meters of Lexington, MA.

To perform this API query using Xbasic

1. Extract the URL from the query (everything up to the ?) and set the URL variable (in the code shown below) to this value.

2. DIM an Xbasic dot variable (DIM P  as p in the code shown below) and set properties in this dot variable for each parameter in the query string. Note that when setting parameter values, spaces in the parameter values must be converted to + signs.

dim p as p

p.location=stritran("lexington ma"," ","+")

p.radius_filter = "10000"

 

 

Here is the complete example:

 

dim ao as extension::OAuthClient

ao.consumer_key = "consumer key value - get from the YELP website"

ao.consumer_secret = "consumer secret value - get from the YELP website"

ao.oauth_token = "oauth token - get from the YELP website"

ao.user_secret = "user secret - get from the YELP website"

ao.oauth_signature_method = "HMAC-SHA1"

ao.url_encode_flags = "+plusspace"

url = "https://api.yelp.com/v2/search/"

dim p as p

p.location=stritran("lexington ma"," ","+")

p.radius_filter = "10000"

dim result as n

result = ao.Exec("GET",url,p4)

if result = 200 then

    dim jsonResponse as c

    'reformat the json response to make it readable

    jsonResponse =  json_reformat(ao.response_content)

    showvar(jsonResponse)

else

    showvar("Error")

end if


Once you get the response from YELP you can use the json_parse() function to get an Xbasic variable and then generate code to (for example) populate a List control on a UX component showing the results.

 

UX Component - {dialog.object}.refreshDropdownBoxChoices() Method - Refreshing Multiple Controls in a Single Ajax Callback - You can now refresh multiple Dropdown controls in a single Ajax callback. Previously, if you wanted to refresh the choices in multiple controls you had to make multiple Ajax callbacks.

There are two syntax options.

You can specify a comma delimited list of controls to refresh. For example:

{dialog.object}.refreshDropdownBoxChoices('COUNTRY,CITY')


Or, you can specify a JSON string. Using the JSON string method you can specify optional parameters for each Dropdown control.

For example:


var arr = [];
arr.push({ controlName: 'country');
arr.push({ controlName: 'city', dynamicFilter: 'country = \'usa\' or country = \'uk\''});
var json = JSON.stringify(arr);
{dialog.Object}.refreshDropdownBoxChoices(json)

 

Application Server - Configuration Changes - Many Application Server configuration changes are now effective immediately (without requiring a server restart)

Changes made to the Application Server's configuration are now effective as soon as those changes are saved, including when the server is currently running. This allows the server configuration to be modified without having to restart the server and interrupt user activity.

For example, many server administrators do not enable server logging in order to conserve disk space and other server resources. However, since logs are very helpful when an unexpected problem occurs, it is often times desirable to turn them on temporarily. Previously, this would require a server restart which meant either interrupting users of your applications or going without logging until some later time when the server became idle. Now changes such as this can be made with no impact on application users.

Some changes cannot be made effective without a server restart however. These are changes to the listening IP address or port, the server's license, and the SSL configuration.

IMPORTANT: Changes must be made through the Alpha Anywhere or Alpha Anywhere Application Server user interfaces. If the server's configuration file is directly edited then the changes will not be effective until either the server is restarted or changes are saved through the user interface.

 

UX and Grid Component - Auto-Suggest Control - Return Value - By default, the return value for an auto-suggest control is the same as the search field. Now you can specify a different return value than the search field.

PhoneGap App Builder - Status Bar Plugin (iOS)  - The Status Bar Plugin default behavior has changed to reflect the styling recommended by Apple for iOS 7 and greater apps. By default, the iOS status bar is now overlaid on top of the PhoneGap WebView. This will require the addition of a 20px spacer to a Panel header to accommodate the status bar. If you would like to set the behavior to the previous iOS 6 style, which does not overlay the WebView, you must set the properties for the status bar from within the onPhoneGapReady event in the Client-side events.

Example:

Add this code to the onPhoneGapReady event:

StatusBar.overlaysWebView(false);

StatusBar.styleDefault();

 

NOTE: While the PhoneGap documentation for the Status Bar plugin indicates that a preference setting within the config.xml file can be used to set the default behavior as required, this is not currently supported by PhoneGap Build.

 

IMPORTANT: The PhoneGap StatusBar plugin resizes the size of the WebView control asynchronously. That means that if your UX component uses Panels (which is very likely) the Panels will have been laid out using the original size of the WebView control. This will cause layout errors - most likely manifested as Panel Footers being incorrectly sized. Therefore, it is very important that you add this code to the onPhoneGapReady event to resize the Panels in your component. This code must be wrapped in a setTimeout() so that it runs after the Statusbar plugin has completed.

For example:

StatusBar.overlaysWebView(false);

StatusBar.styleDefault();


setTimeout(function() {
    var obj = {dialog.object}.getPanelObject()
    obj.resize();
},100);

 

 

 

 

 

UX Component - Action Javascript - File Upload - Amazon S3 Action - Alpha Anywhere Server - This action previously only allowed upload to S3. Now you can use the same action to upload files to the Alpha Anywhere server. In the case of the Alpha Anywhere server, you specify the name of an Xbasic function to call after each file us uploaded. This action allows you to select multiple files for upload. The files are all uploaded at once and separate progress bars are shown for each file. The Xbasic function will be called once for each file selected.

UX Component - PanelOverlay - zIndex Property - You can now specify an explicit z-index for a PanelOverlay. Previously the zIndex for a PanelOverlay was hard-coded to '4'. The default value has been changed from '4' to '6'. This means that it is possible that you might see a change in behavior when running a UX in that a PanelOverlay that was previously shown when another Panel was brought into view would now be hidden. To restore the prior behavior simply set an explicit value of '4' for the PanelOverlay's zIndex property.

 

Xbasic -  a5_word_merge_dotNet() Function  - Merge Data into Word Template - Merges data that results from executing a SQL query into a Microsoft Word template document.

IMPORTANT: You must install the Microsoft Office 2010: Primary Interop Assemblies Redistributable in order to use this function. http://www.microsoft.com/en-us/download/details.aspx?id=3508

 

Syntax:

p pResult = a5_word_merge_dotNet(c folder,c templateFile, c connectionstring,c sql,sql::arguments args [,l flagPortableSQL [c outputFilename]])

 

Where:

 

Example:

 

dim folder as c = "c:\data\wordMerge"
dim template as c = "Template.docx"
dim ConnectionString as C = "::Name::Northwind"
dim sql as c = "select customerid, contactname, address, city, region, country, postalcode, contactname as [salutation] from customers where country = :whatcountry"
dim args as sql::arguments
args.add("whatcountry","uk")
dim outputfilename as c = "Invoice for {customerid}"
dim pr as p
pr = a5_word_merge_dotNet(folder,template,connectionstring,sql,args,.t.,outputFilename)
 

 

The Xbasic source code for this function can be download here. The reason for including the source code is that it serves as a useful guide to calling .Net code from Xbasic and it allows developers to tweak the function to expose other Word features.

 

 

: UX and Grid Component - Building Real-time Applications - Web-sockets Server - Publish/Subscribe - The web-socket server functionality has been enhanced to support a publish/subscribe model. When a client-connects to the web-socket server they can specify the 'message types' that they are interested in receiving.

If the client is not subscribed to a particular 'message type' then when the web-socket server will not send any messages of that type to the client.

In the component properties, you can specify what message types the component should listen for.

You can use the Web-socket server actions in Action Javascript to dynamically change the types of messages that the component has subscribed to.

For example, in the image shown below, the component will be subscribing to messages of type 'messageboard' and 'alpha'

 

 

 

The 'message types' are completely arbitrary. When a message is sent, it is given a specific (arbitrary) message type.

For example, the code below sends a message of type 'myspecialtype':

 

var obj = {type: 'myspecialtype', messageText: 'this is the message};
{dialog.object}.wsclient.socket.send(JSON.stringify(obj));

 

Alpha Anywhere comes with certain 'built-in' message types. You can add you own built-in message types by writing a node.js handler for your user-defined message type.

The built-in 'messageboard' message type (for example) is written so that when the user connects to the web-socket server (or re-connects after having lost the connection) any messages of type 'messageboard' that were sent prior to their connecting are automatically sent to the client (assuming, of course, that the user has subscribed to messages of type 'messageboard'). The 'messageboard' special type is written to keep a certain maximum number of messages in is 'history' stack, but you can edit this value.

The custom message types are stored in the <Alpha Anywhere executable folder>\node_services\ws_queue folder.  For example, the 'messageboard' special type is in a file callled messageboard.js.

To add your own message type (called say 'type1') create file called type1.js in the ws_queue folder. Use the messageboard.js code as

 

The web-socket server actions in Action Javascript allow you to specify what message types to subscribe to when you select the following actions:

 

Using the Web-Sockets Server when Alpha Anywhere is Using a Load Balancer

A load balancer is commonly used to distribute incoming requests to one of several Alpha Anywhere Application Server instances running on a single Windows computer. Alpha Anywhere uses a Node.js server running on a different port in order to provide WebSockets functionality, so the load balancer will need additional configuration if you will be using WebSockets with your application. The URL used for your application points to the load balancer so it must know about all incoming traffic that is to be expected and passed along.

Configuring the load balancer to work with the WebSockets server is simpler than configuring it to work with the Alpha Anywhere Application Server instances because only one Node.js server is used. There is no balancing to be done, just allow the incoming traffic to pass through to the Node.js server. The load balancer should be configured to accept traffic on the port that has been specified in the web project properties and send that traffic to the same machine as the Alpha Anywhere Application Servers, but on the port specified. The exact configuration steps vary from load balancer to load balancer, but it is essentially the same as creating the alpha Anywhere Application Server load balancing that was already done but with just a single target.

 

 

Action Javascript - File Upload - Amazon S3 Storage Action - Base64 Encoded Data - Previously this action assumed that the user would select the files to be uploaded. The action has been enhanced so that you can now specify the file to upload by supplying base64 encoded data (which must be in the form of a data URI).

 

 

Tabbed UI - Initial State of Buttons Pane - If you specify that the Buttons Pane on the Tabbed UI can be collapsed, you can now specify its initial state.

 

 

The use case for this is typically when you have a Tabbed UI with integrated login. Before the user logs in you do not want the Buttons pane to display, but after login, in the afterLogin client-side event you want to display the Buttons pane. This is done by adding code to the client-side afterLogin event:

 

tbiObj.showTabbedUIMenuPanel(false);

 

Note that the .showTabbedUIMenuPanel() event is called with a false parameter to indicate that animation should not be used.

 

UX Component - Data Bound UX Component Quick Start Genie - You can now create a data bound (SQL Database) UX with full CRUD support using a quick start genie.

To get started, create a new UX component, go to the Controls pane and then click on the [Textbox] item in the toolbox on the left. The following dialog is shown:

 

 

Select the 'Create multiple new controls at once' option and then click the 'Populate list from a table' option.

 

The following dialog will be shown:

 

 

The highlighted properties are new. When the controls are added to the UX you can specify that a server-side action to load primary keys should be added to the onDialogIntialize event, that a server-side action to save submitted data to the database to which the UX is bound should be added to the afterDialogValidate event, that buttons to submit/cancel the UX should be added and that buttons to navigate from record to record in the bound table should be added.

This genie makes it much quicker to get started building a data bound UX component.

NOTE: You can also build UX components that perform CRUD operations by creating a List with a Detail View.

 

 

 

 

UX Component - Quick Find - When a UX component has a large number of controls, finding the control that you want to edit in the Tree View can be difficult. The existing Find feature (accessed by clicking the Find button on the toolbar) was not very helpful. The Find command has been re-implemented as shown in the image below.

To open the Quick Find dialog, click on the highlighted icon in the image below.

The tree view of your UX controls is shown below. You can filter this list by typing into the Filter box, or by clicking on one of the categories in the lists on the left.

You can then double click on an item in the tree view or click the Goto Control button.

 

 

PhoneGap App Builder - Added support for the latest CLI versions of PhoneGap - The PhoneGap App Builder has been updated to support the latest CLI versions of PhoneGap. As of early October, 2015 the latest CLI vesrion supported by PhoneGap Build is 5.2.0.

PhoneGap App Builder - Configuration options - Backup config.xml file - A new option has been added to the PhoneGap App Builder that controls the generation of a backup of the config.xml file when any changes are saved. The backup config.xml option is enabled by default. You may disable or enable this option as required. The backup config.xml files are stored in the projects resources folder and the files are date and time stamped. A .bak extension is included.



PhoneGap App Builder - Added support for the new NPM Plugin Registry - The PhoneGap App Builder has been updated to load all of the core PhoneGap plugins from the NPM registry. All prior versions of the PhoneGap App Builder loaded the core and 3rd party plugins from the PhoneGap Build Registry, which is being deprecated by PhoneGap in favor of NPM. If you are using any of the CLI versions of PhoneGap, the NPM core plugins are required. PhoneGap Build will no longer accept any updates to the plugins listed within the PhoneGap Build Registry.

Approximately 30% of the 3rd party plugins listed within the PhoneGap App Builder have been listed within the NPM registry by their respective authors and the PhoneGap App Builder will load those plugins from NPM when appropriate. Some of the plugins must still be loaded from the PhoneGap Build registry in order to work properly within PhoneGap Build. A new property has been added to all 3rd party plugins that identifies the registry that is being used. This information is available within the help of each plugin from within the builder.



All previous PhoneGap Build project config.xml files will be automatically updated to use the NPM listed plugins if they are used within a project. This includes the 3rd party plugins that have been updated to the NPM registry.

PhoneGap App Builder - Added support for the Android Crosswalk plugin - The Crosswalk plugin for Android is now supported. You must use one of the CLI versions of PhoneGap in order for this plugin to be enabled. Crosswalk replaces the Android WebView with the most recent revision of Chrome. This generally provides enhanced app performance and consistency among different Android devices.


json_filter() Function - Extracts or omits certain properties from a JSON string.

NOTE: Conceptually, this function is similar to the filter_string() function, except that it operates on JSON strings.

 

Syntax:

c result = json_filter(c json [, c properyNames [, L exclude]] )

 

Where:

 

Examples:

 

 

'extract object with a single field

dim json as c

json = <<%txt%

{

    one" : 1 ,

    two" : "TWO" ,

    three : [ 1 ,2 ,3 ]

}

%txt%
 

? json_filter(json,"one")
= {  "one" : 1}


? json_filter(json,"two")
= {  "two" : "TWO"}

? json_filter(json,"three")
= {  "three" : [ 1 ,2 ,3 ]}

'exclude a single field
? json_filter(json,"one",.t.)
= {  "two" : "TWO" , "three" : [ 1 ,2 ,3 ]}


? json_filter(json,"two",.t.)
= {  "one" : 1 , "three" : [ 1 ,2 ,3 ]}

? json_filter(json,"three",.t.)
= {  "one" : 1 , "two" : "TWO"}


'include multiple (comma separated) fields
? json_filter(json,"one,two")
= {  "one" : 1 , "two" : "TWO"}
? json_filter(json,"one,three")
= {  "one" : 1 , "three" : [ 1 ,2 ,3 ]}

 

 

compile_xbasic_function_library() Function - Allows you to use Xbasic Function Libraries in an .a5w page.

Syntax

 

p nameSpace = compile_xbasic_function_library(c functionLibraryName)

 

Where:

 

To call a function you must prefix the function name with the nameSpace. See example below.

 

Example:

 

<%a5

    dim p as p

    p = compile_xbasic_function_library('myFunctionLibrary');

    ?p.functionInMyLibrary()

%>

 

 

Amyuni PDF Printer Driver - Amyuni V5.0 - Windows 10 - Alpha Anywhere uses the Amyuni PDF Printer driver to produce PDF output from reports. Previously Alpha Anyhwere included V4.5 of the Amyuni Printer Driver. Alpha Anywhere now bundles V5.0 of the Amyuni Printer Driver. The V5.0 driver is compatible with Windows 10 whereas the V4.5 driver is not.

 

Grid Component - Sorting - Add Primary Key to ORDER BY Clause - By default, when you sort a Grid component, the Primary Key of the primary table for the SQL statement that the Grid is based on is now automatically added to the ORDER BY clause. This is done to ensure that even when the user sorts on a field that would not normally generate unique sort keys (e.g. user sorts on the 'City' column), that the sort keys are unique.

If you do not add the primary key to the ORDER BY clause and if the user sorts on a non-unique field, then when the user navigates from page to page in the Grid, it is possible for records that have appeared on a prior page to re-appear on a subsequent page.

You can control whether this feature is enabled or not by setting the 'Add primary key to all ORDER BY clauses' property on the Properties pane of the Grid Builder.
 

 

 

a5_copyLayout_to() Function - Can now be used without bringing up any UI.

The a5_copy_layout_to() function is used to copy a Report, Label, or Letter from one data dictionary to another (does not apply to 'Project' reports). This function brings up a user interface for the user to enter the target dictionary. Now, you can use this function programmatically, without bringing up a user interface.

 

Example:

a5_copy_Layout_to("Report","report1@c:\alphasports\customer.ddd","report2","c:\a5v12\packages\alphasports.ddd")


Where the arguments are:

 

 

: OData Support - Consume Data from OData Sources - You can now use standard AlphaDAO methods to access data exposed by OData data sources.
 

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

 

OData is a very popular standard for accessing data using REST calls. Alpha Anywhere now allows you to connect to OData services and then execute standard portable SQL code against the connection.  Obviously, the SQL that you execute is limited to functionality supported by the OData service. That means, for example, that while you cannot execute JOIN commands.

To use OData data, you define a named AlphaDAO connection string, and then select OData as the connection type.

The dialog will prompt for the Base URL of the OData service. Once you have the named connection string, you can then continue to build Grid and UX components in the same manner that you would for any SQL database.

 


 

: node_request() Function - Calling Node.JS Code From Xbasic - Node Code Defined at Project Level - The node_request() function allows you to execute some Node.js code.

The syntax is:

c Result = node_request(c NodeServiceName, p data [L flagRestartNode [, L flagShowNodeConsoleWindow]]);

 

Where:

 

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

 

NOTE: Contrast this with the technique for running Node code shown in video XB_V12-3 "Calling into Node.JS from Xbasic". The technique shown in this video are for Node services defined at the Alpha Server level (the Node services can be called from any project), whereas the node_request() function discussed here is for Node services defined at the Web Project level.

 

IMPORTANT: The Node services must be defined in a special location in your Web Project. You must define the Node .js file in the Node\Node_Services folder in the Web Project.

Example:

Assume you have defined a Node service called 'hello' (name is case-sensitive). This service will be defined in a file called hello.js in the 'node\node_services' folder in the Web Project folder.

The contents of the hello.js file is:

 

exports.handler = function(packet,response,sendResponse) {
    var e;
    var attachments = null;
    var msg = 'Hello there <b> ' + packet.firstname + ' ' + packet.lastname + '</b>';
    response.result = msg;
    console.log(msg);
    sendResponse(response,attachments);
};
 

This is the standard format for a Node module.

 

Notice the following about the hello.js file:

 

To run this Node service from the Interactive window:

 

'define an object (i.e. an Xbasic dot variable) to contain the input parameters

dim p as p

p.firstname = "Fred"

p.lastname = "Smith"

'restart the Node service so that any edits to the hello.js file are picked up and show the console window

?node_request("hello",p,.t.,.t.)

 

The result, shown in the Interactive window will be:

{"_id":"e38bcc7c-581f-4b6b-9d13-d4da6eb0aa8a","error":"","result":"Hello there <b> Fred Smith</b>"}

 

This string is a JSON object that can be parsed:

 

For example:

dim json as c

json = node_request("hello",p)

dim pOut as p

pOut = json_parse(json)

showvar(pOut.result)

 

 

TECHNICAL NOTE: The node_request() function is actually a simple wrapper around these low level Xbasic commands:

dim n as helper::node

dim p as p

p._id = "some_unique_id"

p._command = "name of the Node service"

p.param1 = "value of parameter 1"

p.param2 = "value of parameter 2"

dim jsonCmd as c

jsonCmd = json_generate(p)

dim folder as c

folder = "fully qualified path to the  'node\node_services' folder"

n.request(folder,jsonCmd)

 

NOTE: The files in the 'node\node_services' folder in your Web Project are automatically published when you publish your application. When you do a Live Preview of a component you are working on and you choose the 'Full Preview' option from the menu, the files in the  'node\node_services' will also be published to the LivePreview folder in the server webroot.

 

 

: Client-side Data Cache - The client-side data cache allows you to define one or more 'data items' that are cached on the client-side so that you can reference this data in a UX component. The data in the data cache is in the form of Javascript arrays.

 

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

 

For example, you might define a client-side data cache with these items:

For each item in the data cache you specify the server side query that generates the JSON data for the data item. For example, you might specify that the data for the 'customer' data item is obtained by executing a SQL SELECT command against a SQL Server database.

The data for the 'orders' data item might be obtained by executing some custom Xbasic code that returns a string of JSON data.

The data source for a data item can be:

 

The data in a data-item can, optionally, be saved on the client-side so that it is available when you are running the application in disconnected mode. When you choose to save the data on the client, you have the option of storing the data in:

The amount of data that can be stored in local storage is limited. If you store data in a file on the device you will be able to store significantly more data than would be possible in local storage.

The UX has methods that allow you to refresh the data in a data item and to read the data from a data item into a Javascript array. When you read data from a data item into an array you can, optionally, specify filter and order conditions so that only 'records' that meet your filter criteria are in the array returned by the read method.

You can specify that the data in a data-item should be 'delayed'. This means that when the UX is initially rendered, the query for the data item is not performed and no data is initially sent to the client. Only when the user executes an explicit command to 'refresh' the data item will an Ajax callback to the server be made and then the data item query is performed and the data are sent to the client.

If you have specified that the data in a data item should be persisted to Local Storage, there is no way of knowing, at the time the query to get the data for the data item is performed, if the data that is returned to the client will actually be able to be stored in Local Storage - because there is not enough available space in Local Storage. Therefore, when you specify that a data item should be stored on the client side you can also specify an event handler that will get fired if the data could not be successfully persisted to Local Storage. This will allow you to display some UI to inform the user to enter more selective search criteria for the query that returns the data for the data item.

 

IMPORTANT: If you want to use the FileSystem option in a PhoneGap application you must include the Device, File and File Transfer plugins when you build your PhoneGap application.

 

 

Defining a Client-side Data Cache

To define a client-side data cache, you open the Client-side Data Cache Editor. There are two ways to open the editor. You can use the dropdown menu by clicking the Menu button, as shown below:

 

 

Or, you can click the smart-field for the 'Client-side data cache' property on the Properties pane in the UX builder

 

 

 

Client-side Data Cache Editor

The Client-side Data Cache editor, shown in the image below, shows the names of data items in the Data Cache. The dialog show summary information about each data item.

 

 

To edit an item in the Data Cache, click the 'Edit item' button, or double click on the item in the list. This will open the Data Item editor.

 

 

 

For each item you can specify:

 

Persisting Data

If the Delay query until explicit refresh property has been checked, the dialog shows additional properties that allow you to specify that the data item should be stored on the device.

 

 

 

The options for Store where are:

IMPORTANT: If you are persisting to the file system and you are using Xbasic to generate the data for the data items, be sure to generate properly formed JSON. For example: [ {"name" : "fred"} ] and not [ {name: 'fred'} ]

 

When Store data on device option is checked you can specify a Maximum payload size property. This is the maximum size (in bytes) that a query is allowed to return. If you specify the default value of -1 there is no maximum. This property is designed to allow you to protect against the user trying to download too much data to the device. When the

Maximum payload size property is set to some value greater than -1, the payloadSizeExceeded Javascript Event property is shown. You can put code in this property to alert the user that their query for the data item returned too much data and they they must enter a more restrictive query.

 

Other Settings

If any of the data items in your Client-side Data Cache are configured to store data in the file system on the device then you can set additional settings in the Other Settings tab of the Client-side Data Cache editor.

These settings control whether a progress bar is shown while the device is downloading the data from the server to be stored in files on the device.

If you are storing large amounts of data on the device you will generally want to show the user a progress bar so that they know that something is happening.

 

 

You can specify the color and width of the progress bar and you can also specify a placeholder or an explicit element id for the position of the progress indicator. Say for example, and element with an ID of 'progress1' and you want to display the progress indicator in this element, you specify the Placheholder for progress indicator as element:progress1

 

Before file download begins - This event fires after the Ajax callback to get the data for the data items that are being refreshed has completed, but before the device actually starts downloading data.

The use case for this event is as follows:

Say you have defined a Client-side data cache with a large number of data items, (or a few data items, some of which return a large amount of data.) The Ajax callback to refresh all data items will take some time on the server to complete. While the server is busy performing the queries to get the data in the data items, the user has no indication that anything is happening. So, it is likely that you will want to display a wait.. dialog when the user clicks a button to refresh the data in the data items (which triggers the Ajax callback to the server). Once the server has obtained all of the data it sends a response back to the client telling the client to start downloading the data. At this point the progress indicator will start moving, giving feedback to the user. The Before file download begins event will allow you to dismiss the wait... dialog (since it is no longer needed -- the user can now watch the progress indicator).

 

Action Javascript

Action Javascript allows you to perform several actions on data items in the Data Cache. Select the 'Client-side Data Cache Actions' action from the list of available actions.

 

 

Then in the editor, select the action type:

 

The actions currently currently supported are:

 

Read Data Action

The builder for the Read Data action is shown below. You specify the name of the data item you want to read and then you define the Javascript code you want to execute once the item has been read. You code can reference data - a Javascript array that contains the data in the data item.

 

The filter allows you to define an arbitrary filter to filter the data. The filter builder dialog is shown below. The filter is in the form of a Javascript expression that evaluates to true or false. Fields in the data item are referenced with the data. prefix. In the screenshot shown below only records in London or Berlin are included in the data array passed to the onSuccess event handler.

 

 

The order allows you to define an arbitrary sort order for the data in the data array. The order builder is shown below:

 

 

The order builder allows you to define a multi-level sort. It also allows you to parse numeric, logical and data strings into data of the correct type so that the data are ordered correctly. For example data values in your data cache might be in form of date strings (e.g. 12-31-2015). In order to sort these values correctly, they have to first be parsed into real date objects.

 

Data Cache Methods

The UX object has several methods for working with data items.

 

Refreshing Data-cache items:

{dialog.object}.refreshDataCacheItem(listOfItemsToRefresh, onCompleteFunction)

 

Where:

 

Reading a data-cache item:

{dialog.object}.getFromDataCache(itemName,onSuccessFunction, onFailFunction, filter, order)

 

Where:

Here is an example of the filter parameter specified as a string:

var _filter = 'data.Country == "USA" || data.Country = "France"';
 

Here is an example of the filter parameter specified as a function:

var _filter = function(data) {
if(data.City == 'Boston') return true;
    else return false;
}
 

Here are examples of the order parameter specified as an object:

//sort by City, then by Lastname (descending)
var _order = {'City' : 1, 'Lastname': -1};

 

//sort a date string that is in the format MM-dd-yyyy

var _order = {'DateOfBirty:date:MM-dd-yyyy' : 1);
 

Here is an example of the order parameter specified as a function:

//sorts by Lastname, then by DOB ( a date field with a format of MM-dd-yyyy) in descending order
 

var _order = function(a,b) {
    if(a.Lastname > b.Lastname) return 1;
    else if(a.Lastname < b.Lastname) return -1;
    else {
        if(new Date().fromFormat(a.DOB:date:MM-dd-yyyy,'') > new Date().fromFormat(b.DOB:date:MM-dd-yyyy,'')) return 1;
        else return -1;
   }
}
 

 

 

: UX and Grid Component - Building Real-time Applications - Web-sockets Server - You can now build 'real-time' applications by enabling a 'web-sockets' server to broadcast messages to all 'connected clients'.

Use cases for  'read-time' applications include:

 

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

 

In a typical web-application, the server can only respond to a request from a client. The server cannot push information to clients. But in web-socket applications, the server and the client can establish a permanent 'channel' that allows the server to send messages to all of the connected clients.

In addition to the server, all of the other connected clients can send messages and all of the connected clients will receive the messages.

To turn on web-socket server support in your application you must first go to the Project Properties dialog:

 

Then navigate to the 'Web-socket Applications' section and turn on web-socket applications and specify the port that the web-socket server should run on. This needs to be a different port than your Application Server. Be sure to specify a port that is not in use.

 

 

Web-socket support must then be turned on at the individual UX or Grid component level. For a UX component, go to the Properties Pane, Advanced section and check the 'Web-socket server' property.

 

 

For a Grid component, go to the Grid, Properties pane and check the 'Web-socket server' property.

 

 

 

Once the 'Web-socket server' property has been checked, when the UX or Grid component is run, it will automatically launch the web-socket server (if it is not already running) and it will start listening for messages. When a message is received, the client-side webSocketOnMessage event will fire and your Javascript code can decide what (if anything) to do with the message.

 

Web-socket Client-side Events

The UX and Grid components have method for web-socket server applications. These methods are:

 

Web-socket Server - Action Javascript

Action Javascript has actions for the web-socket server. The Web-sockets Server Actions option allows you to perform the following actions:

 

 

web_socket_server_sendMessage() Function

The web_socket_server_sendMessage() Xbasic function can be used to broadcast messages to all connected-clients.

The syntax is

P pResult = web_socket_server_sendMessage(C message)

 

Where

pResult - object with two properties - error (.t. or .f.) and errorText.

message - message text to send

 

: UX Component - List Control - De-select a Row - If a row in a List has been selected, and the List allows NULL selection, you can now set a property to de-select the row (so that no row is shown as selected) by clicking on the selected row a second time.

 

 

: UX Component - List Control - Loop Navigation - You can now set a property in a List to turn on 'loop navigation'. With loop navigation, if the last row in the List is selected and the user presses the 'down' key, focus will go to the first row in the list (if Loop navigate null selection is unchecked) or will be set to NULL (if Loop navigate null selection is checked)

 

 

 

: UX Component - List Control - Dynamically Set Columns Shown in List - A new helper method has been added that allows you to dynamically set the columns shown in a List and populate the List with some data. The columns are based on the data with which you are populating the List.

For example, assume you have a List and you have a Javascript variable with this data:

 

[
    {
        "Firstname": "John",
        "Lastname": "Smith",
        "City": "Boston",
        "State": "MA"
    },
    {
        "Firstname": "Henry",
        "Lastname": "Rhodes",
        "City": "New York",
        "State": "NY"
    },
    {
        "Firstname": "Allison",
        "Lastname": "Berman",
        "City": "Los Angeles",
        "State": "CA"
    }

]

 

The 'columns' in the above data are Firstname, Lastname, City and State.

You might want to populate the List with this data and simultaneously set the display columns in the List to Firstname, Lastname, City and State.

At some later point you might have another Javascript variable with this data:

 

[

    {"Name" : "Fred Smith", "Age" : 30},

   {"Name" : "Tim King", "Age" : 23}

]

The 'columns' in the above data are Name and Age. You might want to populate the same List with this data and simultaneously set the display columns in the List to Name and Age.

 

The {dialog.Object}.setListColumnsAndPopulate(listName,data,options) method can be used to populate the List and set the List columns (based on the columns in the first row of data).

 

Examples:
 

var data = [
    {
        "Firstname": "Kathy",
        "Lastname": "Morton",
        "City": "New York",
        "State": "NY"
    }
];

//populate List 'mylist' with the first 3 columns in data
var ops = {columnCount: 3};
{dialog.object}.setListColumnsAndPopulate('mylist',data,ops);

//specify columns
var ops = {columns: ['Firstname','State']};
{dialog.object}.setListColumnsAndPopulate('mylist',data,ops);



 

: AlphaDAO - ToJSONFile() Method - A new method has been added to both the SQL::Connection and SQL::ResultSet object to create a file in JSON format with the data in a query.

 

Example:


dim cn as sql::Connection

?cn.open("::Name::Access_Northwind")
= .T.
?cn.tojsonfile("c:\temp\cncustomer.json", "select * from customers")
= .T.
 

 

: PhoneGap Shell - Memory Management - The sample PhoneGap shell component, used for testing UX components that use PhoneGap features, has been improved. Now, when you go back to the menu screen to load a different UX for testing, the UX that you were using is completely removed from memory. This will prevent the PhoneGap shell from becoming sluggish after you have cycled back and forth from the main menu to a test component several times.

 

: PhoneGap Builder - Android APK Version Code Property - A new property has been added to the PhoneGap Builder that allows you to define the APK Version Code.



This code is required for Android apps published to the Google Play store and it must be unique for each version/update that your submit to Google Play. If you fail to change the APK version code, your app submission to Google Play will be rejected.

: PhoneGap Builder - 3rd Party Plugins - Camera With Exif Plugin - The Camera with Exif plugin has been added to the PhoneGap 3rd party plugins.



The Camera With Exif PhoneGap plugin, developed by Alpha Software, is a modified version of the cordova-plugin-camera that provides the addition of the EXIF and geolocation metadata to all camera and gallery images and returns this metadata along with the image file URI to the success callback. This allows the image metadata to be stored to a database along with the image or the image file reference. The metadata does not need to be parsed from the image itself because it is included in the success callback.

See GitHub: cordova-plugin-camera-with-exif for the full documentation.

 

TIP: If you use the Image Capture - Camera/Photo Library action in Action Javascript and you use the Camera with Exit plugin, then when you write the Javascript code for the Javascript to execute when image has been captured property, you will be able to reference this variables in your code:

 


 


: PhoneGap Builder - 3rd Party Plug- ins - Media With Compression plugin - The Media With Compression plugin has been added to the PhoneGap 3rd party plugins.



The Media With Compression plugin, developed by Alpha Software, is a modified version of cordova-plugin-media that provides the ability to record and play back audio files on a mobile device. This plugin adds MPEG4 compression to both iOS and Android audio recording, making the recordings compatible for playback on either an iOS or Android device and within most modern browsers. MPEG4 compression typically results in a significant reduction in the recorded audio file size when compared to the stock Media plugin. The reduction in file size is required for efficient online/offline storage and retrieval of the audio files.

See GitHub: cordova-plugin-media-with-compression for the full documentation.
 

 

Web security - E-mail  - The data recovery options in web security can be configured to send an email to the user with the requested data. Previously, this process could only use an email profile configured on the Application server. Email can now be sent using email settings defined in the Web Security Settings, email settings defined in the Web Project Properties, or using Mandrill in addition to a defined profile.


UX Component - PhoneGap - Image Picker Plugin - A new plugin is now available in the PhoneGap Builder. The Image Picker plugin can be used to select multiple images from the Photo Library. The typical use case for this plugin is in a disconnected application where you want to add an image to a record, but instead of adding one record with an associated image at a time (to a List control with an associated Detail View), you want to select multiple images at once and then automatically add a new record to a List for each selected image and associate each new record with one of the selected images.

You can watch videos demonstrating this use case here:

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

 

The Image Picker plugin is invoked with this Javascript function:

window.imagePicker.getPictures(successFunction, failureFunction, options);

 

To see the options supported by the plugin do a Google Search on the PhoneGap Image Picker.

Here is how the image picker is used to add a new row to a List control for each selected image. In the code example below, the field in the List that contains the image filename is imageChar.

 

 

function getImages() {
    var success = function(results) {
    //add the selected image names to the child List.
    for(var i = 0; i < results.length; i++) {
        var _d = {};
        _d.imageChar = results[i];
        var lObj = {dialog.object}.getControl('LIST1');
        lObj.addTableRow(_d);
        }
    }

    var fail = function(error) {
    }

    var settings = {width: 800};
    window.imagePicker.getPictures(success,fail,settings);

}
 

In the above example, the imageChar field in LIST1 should be set to an Image control type (on the Fields tab in the List builder). Also, when is LIST1 synchronized, you can upload the selected images to either Amazon S3, or to the Alpha Anywhere server. See the medial files property on the Detail View tab in the List builder for LIST1.
 

PDF Printing - Windows 10 - Microsoft PDF Printer - Windows 10 includes a PDF printer driver. This printer driver can be used instead of the Amyuni PDF printer driver that is bundled with Alpha.

You can set Alpha Anywhere to use the Microsoft PDF printer by going to the View/Settings menu in the Development version and then selecting Preferences/Reports/PDF Driver.

 

 

 

For the Application Server there is no UI currently to set the preferred PDF printer. Instead you can open the Interactive Window by right clicking on the Alpha Anywhere Server icon in the system tray and then entering these commands:

 

dim p as p

registry.load_settings("preferences",p)

p.reports.pdf_driver = "Name of the driver you want to use"

registry.save_settings("preferences",p)

 

 

where 'name of the driver you want to use' one of:

 

AMYUNI printer driver

Microsoft Print to PDF

Microsoft XPS Document Writer

 

 

 

UX Component - Watermark - Dynamically Setting the Watermark - .setWatermark() Method - A new method has been added to controls that have a watermark property that allows you do dynamically change the watermark text.

For example, say you have a control called 'LASTNAME' and you want to set its watermark property.

var obj = {dialog.object}.getControl('LASTNAME');

obj.setWatermark('Enter your last name');

 

In the case where the watermark text contains international characters, you must use a unicode encoded value. For example, to set the watermark text to 'Prénom', you would use:

var obj = {dialog.object}.getControl('LASTNAME');

obj.setWatermark('Pr\u00E9nom');

 

TIP: To get the unicode encoded value of a string you can go to the Tools menu when the Web Control panel has focus and select the Open text encoder window menu command. The encoded string will be of this form:  Pr{unicode}00E9nom. Replace {unicode} with \u.

 

 

PhoneGap - PhoneGap Shell - Alpha Anywhere Developers enjoy a very rapid design-test cycle. You can test a component you are working on by simply going to the Working Preview or Live Preview tab in the builder. However, when you are working on a PhoneGap application and you want to test any PhoneGap specific functionality in your component (such as accessing the native file system on a device), you cannot test your application in the Working Preview or Live Preview tab. You have to create a PhoneGap application and then install the PhoneGap application on your mobile device. This is a time consuming process.

Using a PhoneGap shell you can dramatically shorten this cycle. The basic idea behind the shell is that you build the PhoneGap shell once and install it on your device. You then dynamically load the UX that you are developing into a Panel in the PhoneGap shell. If you make a change to your component, you can simply click the Refresh button on the PhoneGap shell and the new version of your component is loaded. You don't need to submit the component to PhoneGap build.

Alpha Anywhere now ships with a sample PhoneGap shell that you can use for testing your UX components on a device.

Watch Video - Part 1
Watch Video - Part 2

 

When you create a new UX component, you can select the PhoneGap-Shell.

 

 

Once you have created a new UX using the PhoneGap shell template, save the component using any  name that you want. The next step is to build a PhoneGap project from your shell UX component.

When you build your PhoneGap project it is extremely important that you set the URL For All Ajax Callbacks correctly. If you do not set this property correctly, your shell will not work - it will not be able to dynamically load the UX component that you want to test.

 

 

It is also important that you specify the plugins that your components will need when you build the PhoneGap shell. That's because the dynamically loaded components cannot load PhoneGap plugins.

For example, assume that you are building a UX component that uses the SQLite PhoneGap plugin. You will need to ensure that this plugin is selected when you build the PhoneGap shell.

Obviously, you can't know ahead of time what plugins the components you are going to build in the future will need. So, from time to time you will need to rebuild your shell component to specify a different set of plugins to load.

 

 

When you open the PhoneGap shell on your device, it will look something like this.

Since you have not previously loaded any UX components, the list is empty.

Click the Add button and enter the name of the UX component you want to test.

 

 

 

Here is what the List will look like after entering the name of a UX component called 'ux1'.

 

 

'

 

 

Now, to run this component in the shell, simply tap on the row in the List.

 

The shell will transition to a new Panel and load the component into the Panel as shown below.

 

 

If you make any changes to the 'UX1' component that you are testing, simply republish the component then hit the 'Refresh' button. If you want to load a different component into the shell, tap the 'Back' button, and add the component name to the List.

 

UX Component - PhoneGap File Download Action - Force Download Property - The 'Force download if file found on device' property allows you to force the file(s) to be downloaded even if a file with the specified name is already on the device. If you force download, the existing file(s) on the device will be overwritten. Previously, if a file with the specified name was found on the device, the source file was not downloaded.

 

 

Bugs

AlphaDAO - MySQL - Stored Procedures - Multiple Resutsets - If you create a MySQL stored procedure that returned multiple resultsets, the SQL::Resultset.nextResult() object failed. As a result you could only read the first resultset returned by the stored procedure.

Web Applications - Repository Database - Case Sensitive Databases - If you configured your Web application to use a Repository database (for example, to save searches in a Grid component) and your defined the repository tables in a SQL database that case case-sensitive for table and column names, saving data to the repository did not work.

Script Editors - Windows Server 2008 - The status bar in the Xbasic and Javascript Script editors contain several 'hot' areas that you can click on to navigate to a line in the script or navigate to a particular function in the script. These 'hot' areas did now work on Windows Server 2008.

UX and Grid Component - Live Preview - In some cases if the browser you selected for Live Preview was installed as a 64 bit program, the selected browser was not found. This is now fixed.

 

UX Component - List with Detail View - Local Storage - Minify - If the minify option was turned on to compress the data stored in Local Storage when a List's data was updated, under some circumstances you could be sync errors when syncing a List's data after restoring the List data from Local Storage.

Xbasic - Stringdictionary Object - Clearing Existing Entries when Initializing - When the stringdictionary object was initialized (using its .initialize() method) , existing entries in the stringdictionary were not being cleared out. Now, they are. An optional flag has been added to the initialize() method to allow you to specify that existing entries should not be cleared out.

Example:

 


dim map1 as c = "alpha=this is alpha"
dim map2 as c = "beta=this is beta"
dim sd as stringdictionary
sd.Initialize(map1)
?sd.get("alpha")
= "this is alpha"

?sd.get("beta")
= ""

sd.Initialize(map2)  'clear out existing entries
?sd.get("alpha")
= ""    'because existing entries were cleared

?sd.get("beta")
= "this is beta"

sd.Initialize(map1,.f.) 'do not clear out existing entries
?sd.get("alpha")
= "this is alpha"
?sd.get("beta")
= "this is beta"   'because existing entries were NOT cleared
 

UX Component - Action Javascript - File Upload Action - Repeating Section - Fixed a problem when using the File Upload action in a Repeating Section.

UX and Grid Component - Action Javascript - Send E-mail  Action - If you used the Send-mail action multiple times on a component, the settings for the last instance were used for all instances.

UX Component - Image Capture - Character Fields - PhoneGap - In a PhoneGap application if captured images were uploaded to the Alpha Anywhere server (as opposed to Amazon S3), the images would not render correctly after the component was refreshed.

UX Component - Image Capture - Character Fields - Thumbnails - If you were capturing images in a character field and you had specified that you wanted to create thumbnails for the image and the stored filename expression for the field was <Shortname> (as opposed to <Fieldname>), the thumbnail was not created correctly.

UX Component - Panels - Google Map - Touch Events - When a Google Map is displayed in a PanelCard, certain touch events on the Map that the Google Map should have responded to were not being seen by the Map control.

Report Preview - Two Page Preview - When you switched to Two Page preview mode, a 'Print Progress' dialog was displayed. This dialog could not be dismissed and should not have been displayed.

Runtime - Debug(1) - In a Runtime application, if a debug(1) statement was inadvertently left in some user-defined code, Alpha would hang.

Grid Component - QBE - Hidden Columns - Fixed a problem in the generated HTML for the QBE feature if a Grid contained hidden columns.

Web Applications - Publishing - FTP Publishing - History - In certain cases the History list was not being maintained correctly when using FTP publishing. As a result of the bug, files were published in some cases when they did not have to be published.
 

UXComponent - Hierarchical Lists with Detail View - Data Synchronization - Fixed errors that occur under certain circumstances if the initial sync returns sever-side validation errors and then a subsequent sync is performed after the validation errors are corrected.

Oracle CLOB Fields - Limit of 4000 Characters - When reading data from an Oracle CLOB field, only the first 4,000 characters were read. This is now fixed.

Xbasic CURL Genie - Fixed an issue in converting certain CURL statements to Xbasic.

international_days_of_week() Function - This function was returning the days in the incorrect order when with a specific start of week day. For example:


?international_days_of_week("start-monday,short")

= Mon

Tue

Wed

Thu

Fri

Sun

Sat

 

UX Component - List Control - Detail View - Synchronizing in Batches - If a UX contains List controls that are in a parent-child hierarchy, and the parent List is configured to synchronize data in batches, then there were errors when the data was submitted that prevented all dirty rows from being synchronized. This error was only if the List was set to synchronize in batches.

Grid - Export Data - Security - The export function was not honoring security settings for columns in a Grid.

Web-Sockets Server - Fixed a bug where the web-sockets server was not starting correctly if the user was running the application on the default port (i.e. the URL for the application did not specify an explicit port).

UX Component - Repeating Sections - Xbasic Validation - Immediate Validation - Improvements were made in how immediate Xbasic validations are performed on fields in Repeating Sections.

 

Grid and UX Component - Searching SQL Databases - 'Is blank' and 'Is not blank' Search Options - The generated SQL for the 'Is blank' and 'Is not blank' search options has been changed to:

 

 

Previously, the generated SQL was:


 

The change was made because in some Oracle databases the previous generated SQL did not return the expected results. The stringLength() function is a portable SQL function.

Alpha Anywhere Server - 500 Error - Fixed an error that would, under some circumstances, cause the server to crash with a 500 Error. Also improved server memory utilization.

UX Component - Data Bound - Repeating Sections - Unbound Controls - Default Values - If you had unbound controls in a Data Bound UX component and you had set default values for the unbound controls, then when UX was initially rendered and the data bound controls were set to their bound values, the unbound controls did not show their default values. If the component did not use Repeating Sections, this bug did not occur.

UX and Grid Component - jQuery - Internal Version - The version of jQuery and jQuery UI that Alpha Anywhere includes when you choose the 'built in' version have been updated to jQuery 1.11.3 and jQuery UI v 1.11.4.

UX and Grid Component - Oracle - Search for Records that End with '_ some character' - A user was trying to search for records in an Oracle table that ended with '_1'. This was failing because SQL treats the _ as a wildcard character. To perform the search the search has to be entered as '\_'. Alpha Anywhere will now automatically add the ESCAPE '\' clause to the generated SQL statement for Oracle.

UX Component - Signature Capture Control - Initially Hidden - If the Signature Capture control was initially hidden when the UX component was rendered, but was then made visible by some Javascript, in some cases, it did not work correctly.

UX Component - List Control - .addTableRow() Method - Fixed issues with the .addTableRow() method when the rows were being added to a child List control.

UX and Grid Components - Google Maps - Google made some changes to the Google maps API fairly recently, and now recommends a different URL to access the API. They also changed Google Premier and now use a "key" value in the URL instead of "clientId". The existing code added the ClientId property which has been deprecated. The URLs generated by the UX and Grid to access the Google Maps API have been updated to reflect the changes Google made.

Another issue occurred if the map was run on a server using SSL, but was not set to use SSL. Most browsers blocked the request for the API JavaScript. A change has been added to force the Google URL to SSL if the server is using SSL in places where the link is built at run time.

The standard public Google map access will throttle map requests, and currently that public access limit is listed at 2,500 requests per day.

The latest Google method to get a higher limit is to sign up for a Google developer account (previously called Google Premier), create a project (free), and then activate the Google Maps JavaScript API. This will create a special API key that can be added to any Alpha Anywhere Map configuration in the builders as the "Google Premier ID". If you use an API key, Google tracks the number of requests, but allows a much higher free limit, currently listed as 25,000 per day. For large companies, they do start charging if the requests exceed that limit. If a key is not provided, the standard public map access will be used.
 

UX Component - Auto-suggest Control - Fill in Fields - The fill in fields were only filled in if you selected from the auto-suggest list by clicking on a row in the suggestion list. If you typed in a matching value (and did not select by clicking on the suggestion list), the fill-in values did not fill in.

UX Component - List Controls - List with Parent List - Pre-fetched Data - Arguments in Child List WHERE Clause - Fixed a bug where you would get an error after synchronizing data in a List with a Detail View if the SQL for the List used arguments in the WHERE clause.

 

Tips

AlphaDAO - Stored Procedures - Output Arguments - When you use execute SQL statements from Xbasic using AlphaDAO it is very common to use the SQL::Arguments object to pass parameter values to the SQL statement that you execute. For example

dim args as sql::arguments

args.add("customerId","alfki")

dim cn as sql::connection

dim flag as l

flag = cn.open("::Name::Northwind")

dim sql as c

sql  = "Select * from customers where customerId = :customerId"

flag = cn.execute(sql,args)

 

In the above example, the argument (customerId) is termed an 'input' argument - it is passing a value to the database engine.

However, Alpha Anywhere also allows you to create 'output' arguments and 'inputOutput' arguments. These argument types are used when you want the database engine to return a value to Xbasic.

Watch Video - Part 1
Watch Video - Part 2

 

For example, consider the following (very simplistic) stored Procedure defined in a SQL server database:

 

CREATE PROCEDURE [dbo].[output]

-- Add the parameters for the stored procedure here

@Param1 integer output,

@Param2 varchar(30) output

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- Insert statements for procedure here

set @Param1 = 100

set @Param2 = 'Hello world'

return

END

 

In this stored procedure, the parameters (Param1 and Param2) are being set.

Here is how an Xbasic script could call the stored procedure and get the value of the parameters set in the stored procedure:

 

dim args as sql::arguments
 

'define to arguments, 'inout' and 'inout2' as inputOutput arguments
args.add("inout",0,sql::ArgumentUsage::inputoutputargument)

 

'notice that a dummy value of the correct size needs to be defined for the argument
args.add("inout2",replicate(" ",40),sql::ArgumentUsage::inputoutputargument)

dim cn as sql::Connection
cn.open("::Name::sqlserver_northwind")
 

'call the stored procedure and pass in the two argument values
?cn.Execute("exec output :inout, :inout2",args)
= .T.

?args[1].data
= 100

?args[2].data
= "Hello world"

 

If the size of the argument is not big enough then when you execute the stored procedure you might get an error like this:

?cn.CallResult.text
= "Internal Error - Data Truncated - The buffer for receiving data is too short"
 

In some cases your stored procedure will also return one or more resultsets in addition to setting the value of output arguments.

Depending on the database you are using you might have to read each of the returned resultsets before you can read the values in the output arguments.

For example, consider the following modification to the above stored procedure:

 

CREATE PROCEDURE [dbo].[output]

-- Add the parameters for the stored procedure here

@Param1 integer output,

@Param2 varchar(30) output

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- Insert statements for procedure here

set @Param1 = 100

set @Param2 = 'Hello world'

select * from customers

select * from orders

return

END

 

This stored procedure now returns two result sets.

 

Below is the Xbasic to execute the stored procedure and get the values from the output arguments:

 

dim args as sql::arguments
args.add("inout",0,sql::ArgumentUsage::inputoutputargument)
args.add("inout2",replicate(" ",50),sql::ArgumentUsage::inputoutputargument)
dim cn as sql::Connection
cn.open("::Name::sqlserver_northwind")
?cn.Execute("exec output :inout, :inout2",args)
= .T.
 

'value of the output arguments not yet available because we have

'not read the resultsets
?args[1].data
= 0
?args[2].data
= ""

dim rs as sql::ResultSet
rs = cn.ResultSet
 

'still not available
?args[1].data
= 0
?args[2].data
= ""

'get the next resultset
?rs.NextResult()
= .T.
 

'still not available
?args[1].data
= 0
?args[2].data
= ""
 

'no more resultsets to read
?rs.NextResult()
= .F.
 

'argument value are now available!!
?args[1].data
= 100

?args[2].data
= "Hello world"

 

 

Web Applications - Windows 10 - Acrobat PDF Viewer - Internet Explorer 11 - Unlike Chrome and Firefox, Internet Explorer 11 does not have a built-in PDF viewer and therefore it relies on Adobe Acrobat Reader to display PDF files. On some machines, when you try to view a PDF report in IE, Acrobat will not open. You will need to turn off 'Enhanced Protected Mode' in IE11 to solve this problem. For more information, see this post.

 

UX Component - Panel Cards - Vertically Centering a Container - A common requirement when building mobile applications is to vertically (and horizontally) center content in a Panel Card.

Watch Video
Download Component

 

For example, in the image below, the content in the blue frame is always vertically and horizontally centered, regardless of the device orientation.

 

 

This is achieved by putting the following code in the onSize event of the Panel Card that contains the container.

Assume that the content to be centered is in a container called CONTAINER_1 and that the in-line style on this container has been set to 'visibility: hidden'. Setting the visibility to hidden will prevent the container from being seen until it is correctly positioned.

 

 

if({dialog.object}) {
 var p = $(this.contId + '.BODY');
 var v = {dialog.object}.getPointer('CONTAINER_1');
 var ph = p.offsetHeight;
 var vh = v.offsetHeight;
 var pw = p.offsetWidth;
 var vw = v.offsetWidth;
 var offsetH = (ph-vh)/2;
 var offsetW = (pw - vw)/2;
 v.style.left = offsetW + 'px';
 v.style.top = offsetH + 'px';
 v.style.visibility = '';
 v.style.position = 'absolute';
}

 

 

Windows 10 - Default Printer - PDF Printing - When you save a report as a PDF, Alpha Anywhere uses the special 'AlphaFive' printer driver that is automatically installed with Alpha Anywhere. After the report has been saved to PDF the default printer (that was defined before the report was saved) is restored. On Windows 10 this does not work because of a change Microsoft made. After the report has been saved to PDF, the default printer is now set to the AlphaFive printer. To disable this new Microsoft feature, see this document.

 

AlphaDAO - Microsoft Access - Can't Load ODBCJI32.dll Error - If you have installed Office 365 on your computer you might find that you can no longer connect to a Microsoft Access database.

To fix the error you will have to install the Microsoft Access Database Engine.

Here is a link to the installer on the Microsoft site.

If you already have the Microsoft Access Database Engine installed, then running a 'Repair' on the engine should fix the problem.

 

 

 

Working with XML Data in Xbasic - JSON_from_XML() Function - Xbasic has extensive support for parsing XML data. However in some cases, the Xbasic XML parsing features are too granular and you might want a quick and simple way to convert an XML document into an Xbasic object (i.e. dot variable). The xml_from_json() function provides such a mechanism.

 

Here is an example of some simple XML that is first parse into a JSON string which is then parsed into an Xbasic object using the json_parse() function.

 

dim xml as c
xml = <<%html%
<customers>
    <customer>
        <name>Dion Jones</name>
        <city>Boston</name>
        <more attribute1="val attr1" attribute2="val attr 2">More for Dion Jones</more>
    </customer>
    <customer>
        <name>Donald Trumpet</name>
        <city>Washington</name>
        <more attribute1="val attr1" attribute2="val attr 2">More for Donald Trumpet</more>
    </customer>
</customers>
%html%
dim json as c
json = json_from_xml(xml)
json = json_reformat(json)
showvar(json)

 

dim p as p

p = json_parse(json)

 

 

 

UX Component - Radio Button and Checkbox Controls - Render as Button List - Right to Left - For languages that use right-to-left text, when you render a radio button or checkbox control as a Button List, you might want the Button List to render as shown below (text right aligned and icon to the right of the text).

 

 

In the property sheet for the Radio Button or Checkbox, set a custom class name for the 'Class name - choices' property.

 

 

Then, in the CSS for the component, define this custom class as follows:

 

.myButtonListClassName {
    direction:rtl;
    text-align:right !important;
}

 

 

UX Components - List Control - Nested Lists - Hierarchical JSON Data from SQL Tables - If you want to display a List control with nested Lists (ile. when the user selects an item in the List, the List is repopulated with that item's child data), you typically define JSON data for the List using this format:

 


Watch Video
Download Component

 

[
    {
        display: 'Menu1',
        children: [
            {
                display: 'Menu1_A',
                action: 'Action_1'
            },
            {
                display: 'Menu1_B',
                action: 'Action_2'
            },
            {
                display: 'Menu1_C',
                action: 'Action_3'
            }
        ]
    },
    {
        display: 'Menu2',
        action: 'Action_4'
    },
    {
        display: 'Menu3',
        action: 'Action_5'
    }
]

 

In some cases you might want to generate this JSON data by querying a SQL database. This is easily done by using the a5_xbasicTreeToJSONTree() function.

For example, consider the following Xbasic string which defines a tree structure in Xbasic syntax:

 

 

dim txt as c
txt = <<%str%
MA.Boston.Smith
MA.Boston.Jones
MA.Cambridge.King
CA.Los Angeles
%str%

json = a5_XbasicTreeToJSONTree(txt,".","display")

 

The syntax for the a5_XbasicTreeToJSONTree() function is:

 

a5_XbasicTreeToJSONTree(c XbasicTreeDefinition, c delimiter [, c propertyName])

 

 

   This will generate a JSON string in this format:


[
    {
        "display": "MA",
        "children": [
                        {
                            "display": "Boston",
                            "children": [
                                            {
                                                "display": "Smith"
                                            },
                                            {
                                                "display": "Jones"
                                            }
                                         ]
                           },
                            {
                                "display": "Cambridge",
                                "children": [
                                                {
                                                    "display": "King"
                                                }
                                            ]
                              }
                        ]
        },
        {
            "display": "CA",
            "children": [
                            {
                                "display": "Los Angeles"
                            }
                        ]
        }
]

 

With this understanding of how the   a5_XbasicTreeToJSONTree() function works, it is easy to see how to generate the JSON from a SQL database. The key is to simply define a query that returns data in the Xbasic tree format and then call the a5_XbasicTreeToJSONTree() function.

For example, to generate data that displays a list of Countries, Cities and Contact Names, you can use this Xbasic:

 

dim cn as sql::Connection
cn.open("::Name::northwind")
dim sql as c
sql = "SELECT Country, City, ContactName FROM Customers ORDER BY Country"
dim flag as l
cn.PortableSQLEnabled = .t.
flag = cn.Execute(sql)
dim rs as sql::ResultSet
rs = cn.ResultSet
dim txt as c

'generate the Xbasic tree format data using a | as the delimiter
txt = rs.ToString(-1,-1,.t.,"|")

dim json as c

'generate the JSON tree specifying the | as the delimiter and 'display' as the property name
json = a5_XbasicTreeToJSONTree(txt,"|","display")

 

 

Reports - Calculated Fields - User Defined Expressions - Slow Performance in Report Design Mode - A common pattern in reports is to define calculated fields that use user defined functions. Sometimes these functions are quite complex and because the functions get evaluated repeatedly when you are design mode, the performance of the report designer is degraded.

You can easily solve this problem by adding code to your user defined functions that cause the functions to exit when you are in report design mode.

For example, say you have a calculated field that references a function defined as follows:

 

function my_report_calc_field as ()

    'some code here that does a database query

    my_report_calc_field = "function return value"

end function

 

You can rewrite this function as follows:

function my_report_calc_field as ()

    if eval_valid("topparent.window_title") then
           'in report design mode, so bail out

            my_report_calc_field = "some dummy return value"

            exit function

    end if

    'some code here that does a database query

    my_report_calc_field = "function return value"

end function

 

 

 

 

 

Reports - Calculated Fields - User Defined Expressions - 1024 Character Limit - A common patter in reports is to define calculated fields that use user defined functions. In some cases the function might return a long value. However, calculated fields have a limit of 1024 characters.

You can easily work around this limit by converting the calculated field to an HTML type. For example, suppose you have a function that returns a long string of text. You could define your calculated field in the report as follows:

myCalcField = *mime_object("html",myFunction())

 

 

UX Component - Columnar Lists Not Displaying Correctly - If a List control is initially hidden when the UX is rendered, and then it is later shown (for example, using some Javascript that shows the container in which the List is contained), the List will not display correctly (if the List is defined as a columnar List as opposed to a free-form layout List). In order to get the List to display correctly you must refresh it. For example:

var lObj = {dialog.object}.getControl('name of your list');

lObj.refresh();

 

In many cases when you build your UX, Alpha Anywhere will be able to detect automatically that a List is not displayed when the UX is initially rendered and it will automatically generate the code to refresh the List when it is shown (for example, if you put a List on Pane number 2 of a Tab control, the List is not initially shown, bug when Pane 2 is given focus, the List is automatically refreshed). However, there are cases where it is not possible for Alpha Anywhere to detect this and you will need to add the refresh code yourself.

NOTE: Lists that use a free-form layout do not need to be refreshed when they are shown.

 

UX Component - PhoneGap - Disconnected Applications - Storing Read-only Data in the Device File System -  When you build applications that are designed to be used while you are disconnected, you typically load the data that you want to have while you are disconnected into List controls and then you set these List control to persist the data to Local Storage.

 

TIP: You can download a working example of the component described in this topic here. You can also watch a video tutorial on the steps.
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

However, if your application is designed to be run in a PhoneGap shell, then you can store the 'read-only' data in your application in the file system on a mobile device. Only the editable data needs to be stored in List controls. By storing the 'read-only' data in the file system, you leave more of the available space in Local Storage for your editable data.

NOTE: The technique described here is different from linking in a static Javascript file in the Javascript linked files property in the UX component. You certainly can include read only data in linked Javascript files, but after the PhoneGap application has been built, you will not be able to refresh the data in the Linked files. The technique described here allows the user to click a button at any time to make a callback to the server to refresh the data that is stored in the mobile device's file system.

When the user wants to update the 'read-only' data stored on their device, you might perform the following steps:

  1. Make an Ajax callback to the server. Include data in the callback describing what data you want to load onto the device. Include with the callback data the name of the file in the file system on the mobile device where the data should be saved.

    NOTE: When you define an Ajax callback you can specify 'additional data' to be sent to the server when the callback is made. Assume that you want to store the data in a file called 'data1.json' on the device. If you are using Action Javascript to define this Ajax callback, you would set the 'Additional data to submit' property to '_filename=data1.json'.
  2. The Xbasic function that handles this callback will perform the necessary database queries to get the data. The function will create a file that contains this data (in JSON format) and will store the file as a temporary session file. (See 'The Xbasic Function to Handle the Ajax Callback' below for details)
  3. The Xbasic function will send a response back to the client with the URL of the temporary session file and call a Javascript function that uses the PhoneGap File Transfer plugin to download the temporary file from the server (using the URL that the Ajax callback returned). Once the file has been retrieved, it will be stored in a file in the file system on the mobile device. (NOTE: You don't have to write the code to use the PhoneGap File Transfer plugin yourself - there is an Action in Action Javascript that will write the code for you. See below for more details).

Now that the data is in a file, you can use PhoneGap to read the file into memory. Once the file has been read into memory, you can call the JSON.parse() Javascript function to crate a Javascript object with the data and your UX component can then use this data as needed.

 

The Xbasic Function to Handle the Ajax Callback

The Xbasic function that handles the callback to fetch data from the server will have to create a file with data in JSON format. Here is an example of what the file might look like:

{

    "table1" : [

        { "field1" : "alpha", "field2" : "beta"},

        { "field1" : "alpha", "field2" : "beta"},

        { "field1" : "alpha", "field2" : "beta"}

 

    ],

 

    "table2" : [

        { "field1" : "a", "field2" : "b", "field3": "c"},  

        { "field1" : "d", "field2" : "e", "field3": "f"}  

 

    ]

}

 

Notice that the file is in JSON format. In this case, the file defines two objects (you can think of these as 'tables') called 'table1' and 'table2'. 'table1' has 3 records and each record has these fields: field1 and field2. 'table2' has 2 records and these fields: field1, field2, field3

This file must then be stored as a session file so that the client (i.e. the mobile device) can download it from the server.

Assume that you used Action Javascript to define the the Ajax callback and that in the action definition you specified that the name of the Xbasic function to handle the callback was xb_getData. Assume also that you specified  Additional data to submit as '_filename=data1.json'.

 

 

Here is how xb_getData() might be defined.

 

Function xb_getData as c (e as p)

'in this example the json data is statically defined.

'in a real-world case you would likely execute database queries here to generate the json

 

dim json as c

json = <<%txt%

{

    "table1" : [

        { "field1" : "alpha", "field2" : "beta"},

        { "field1" : "alpha", "field2" : "beta"},

        { "field1" : "alpha", "field2" : "beta"}

 

    ],

 

    "table2" : [

        { "field1" : "a", "field2" : "b", "field3": "c"},  

        { "field1" : "d", "field2" : "e", "field3": "f"}  

 

    ]

}

%txt%

 

'get a temporary filename

dim tempFn as c

tempFN = request.GetRequestTempFileName(".json")

 

'save the json data to the temporary file

file.from_string(tempFn,json)

 

 

'get the filename to use from the 'additional data' submitted by the ajax callback

dim clientSideFileName as c

if eval_valid("e._filename") then

    clientSideFileName = e._filename

else

    'user did not specify the client-side filename in the Ajax callback

    'so generate a random filename

    clientSideFileName = remspecial(api_uuidcreate()) + ".json"

end if

 

'now put the temporary file into session storage

session.SaveFileToSessionFile(tempFN,clientSideFileName)

 

'get the URL for this session file
dim url as c
url = Session.FormatFileDataURL(clientSideFileName)
 

 

'construct the Javascript response that will be sent to the client

'note that we specify that a function called 'fetchFile()' should be called

'on the client-side with the name of the URL that points to the temporary

'file in session storage. This 'fetchFile()' function is a user-defined

'Javascript function that you will need to add to your UX component

 

dim js as c
js = js + "fetchFile('" + js_escape(url) + "');"

 


 

'return the javascript code

xb_getData = js

 

 

End function

 

 

At run-time, the user might click a button to trigger the Ajax callback. The Xbasic function will prepare the file and then send a response back to the client (i.e. the browser) and call a function (called 'fetchFile' in this example).

Here is how the fetchFile function could be initially defined (in the Javascript functions section of the UX) to test that the Ajax callback is working:

 

function fetchFile(url) {

    alert('Server has prepared this file: ' + url);

 

    /*

        eventually, we will put the Javascript here to make a

        callback to the server to fetch the file

        however, in the mean time, we are just going to store the URL

        in a variable so we can reference it from another function

    */

   

    {dialog.object}._urlToDownload = url;

   

 

 

}

 

Flushing out the 'FetchFile' Action

In order to fetch the file from the server and store it in the file system on the device we can use Action Javascript to get started.

Add a temporary button to your UX (label it 'Fetch File') and then use Action Javascript to define the button's onClick action. Select the PhoneGap - File Download action.

NOTE: The reason for putting the temporary button on the UX is so that we can use Action Javascript to assign an action to this button and then copy the generated Javascript. This is easier than writing the Javascript by hand.

 

 

The genie for this action will open:

 

 

The builder allows you to specify the names of the files on a remote server (in this case the Alpha Anywhere server) that you want to download. You do this by specifying the name of a Javascript function that will return an array of filenames.

You can specify the name of the folder on the device where the downloaded file(s) should be stored.

The 'Force download if file found on device' property allows you to force the file(s) to be downloaded even if a file with the specified name is already on the device. If you force download, the existing file(s) on the device will be overwritten.

You can also specify if you want to display a progress bar while the files are being downloaded. Since you might be downloading large files or many files, displaying progress to the user is always a good idea.

Finally, you can specify some Javascript to execute once the file(s) have been downloaded and stored in files on the device.

 

Set the 'Files to download Javascript Function' property to 'getFiles' and add this function to the Javascript functions in the UX component.

 

function getFiles() {

 

    /*

        recall that in the fetchFile() function we put

        the url in a temporary variable (called _urlToDownload)

        in the UX object

    */

    var url = {dialog.object}._urlToDownload

 

    /*

        this function must return an array of filenames, so

        put the url into an array

    */

    return [url];

 

}

 

We can add a [Placeholder] control to the UX and set the 'Placeholder for progress indicator' to the name of our placeholder.

 

Finally, we can set the 'On Download Complete (all files)' property to some Javascript code.  Let's set it temporarily to this:

alert('File was downloaded');

 

 

After you have filled in all of the properties that you need to fill in in the PhoneGap File Download genie, click the OK button. Here is the Javascript code that was generated to download a file on the server (specified by a URL) and store that file in local file on the mobile device.

Note: To see this code, click the View Javascript button in Action Javascript editor.


 

 

var _list = window['getFiles']();
var arr = [];
for(var i = 0; i < _list.length; i++) {
    arr.push( {filename: _list[i]} );
}
var options = {
    targetFolder: '__myAlphaFiles',
    showProgress: true,

    forceDownloadIfFileExists: false,
    onComplete: function(array) {
        alert('file was downloaded');
    },
    onError: function(array,arrayIndex) {
        alert('error');
    },
    progress: {
        color: '#9fa1e8',
        width: '300px',
        allowCancel: false,
        progressElement: '{dialog.componentname}.V.R1.PLACEHOLDER_1'
    }
}
{dialog.object}.phoneGapFileDownload(arr,options);

 

 

Next, we need to write some Javascript that will read the contents of the file that has been stored on the mobile device. Again, rather than write this Javascript by hand, we will use the same technique we just used - add a temporary button to the UX and then use Action Javascript to set the button's action. We will be using the PhoneGap - File System Actions action to define this action.

 

 

Add a temporary button to the UX (label it 'Read file') and select the PhoneGap - File System Actions action. The builder for this action will then open.

 

 

The PhoneGap File System Actions genie allows you to select from many different types of actions (such as read file, delete file, read directory, delete directory, etc.). Set the Action name to Read File.

Next, set the Filename to __myAlphaFiles/A5SessionFile/data1.json.

Recall that when you defined the File Download action you specified __myAlphaFiles as the folder where the downloaded file(s) were to be stored. Recall also, that when we made the Ajax callback to create the file of JSON data we specified that the file should be called data1.json. Our Xbasic function that handled the callback created the JSON file and then added it to temporary session storage using the name data1.json as the key. Our Xbasic function then called the Session.FormatFileDataURL() method to get a URL for this session file. The format of the URL that this function returns has A5SessionFile/ as a prefix. So, the actual name of the file that is stored in the file system on the device is not __myAlphaFiles/data1.json as you might have expected, but is instead __myAlphaFiles/A5SessionFile/data1.json.

 

The OnSuccess property allows you to specify the Javascript to run once the file has been read and the OnFailure property allows you to specify the Javascript to run if the file cannot be read.

The onSuccess function can refer to a variable called data, which contains the contents of the file that was read. The data that was read will be a string in JSON format, so we will need to use the Javascript JSON.parse() function to turn it into a Javascript object.

 

Edit the onSuccess property and enter this Javascirpt:

 

var _d = JSON.parse(data);

var _dt = '';

for (var tableName in _d) {

       _dt = _d[tableName];

       var msg = 'Rows in table \'' + tableName + '\': ' + _dt.length;

       alert(msg);

}

 

Here is what this code does.

  1. Parse the string of data in data into a Javascript object called _d .
  2. Loop over all of the properties in the _d object. The properties in this object should be 'table1' and 'table2'.
  3. Get an object for the table  _dt = _d[tableName]. This object will be an array containing the rows of data in the table. Get the number of rows in the table and alert it in a message that says (for example) Rows in table 'table1' : 3.

You can set the onFailure code to

alert('could not read file');

 

After you have completed filling in the genie, click ok and then view the generated Javascript. The generated code will look like this:

 

{dialog.object}.phoneGapReadFile('__myAlphaFiles/A5SessionFile/data1.json',function(data) {
    var _d = JSON.parse(data);

    var _dt = '';

    for (var tableName in _d) {

           _dt = _d[tableName];

           var msg = 'Rows in table \'' + tableName + '\': ' + _dt.length;

           alert(msg);

    }

    },function() {
        alert'Could not read file');
    }

)

 

 

Putting it All Together

At this point we have separate buttons for:

  1. Making the ajax callback to prepare the file of JSON data
  2. Downloading the file of JSON data and store it in a file on the device.
  3. Reading the file and process the data.

Ideally, we would like to combine all of this into a single action so that the user can click a button, which makes a callback to the server and then the file is automatically downloaded to the device, read and processed.

As you will recall, the whole client-side process starts when the Ajax callback completes and it calls the 'fetchFile' function which is current defined as follows:

 

function fetchFile(url) {

    alert('Server has prepared this file: ' + url);

 

    /*

        eventually, we will put the Javascript here to make a

        callback to the server to fetch the file

        however, in the mean time, we are just going to store the URL

        in a variable so we can reference it from another function

    */

   

    {dialog.object}._urlToDownload = url;

   

 

 

}

 

Also recall that when we created a button to download the file from the server and we then examined the code to download the file, the generated code looked like this:

 

var _list = window['getFiles']();
var arr = [];
for(var i = 0; i < _list.length; i++) {
    arr.push( {filename: _list[i]} );
}
var options = {
    targetFolder: '__myAlphaFiles',
    showProgress: true,

    forceDownloadIfFileExists: false,
    onComplete: function(array) {
        alert('file was downloaded');
    },
    onError: function(array,arrayIndex) {
        alert('error');
    },
    progress: {
        color: '#9fa1e8',
        width: '300px',
        allowCancel: false,
        progressElement: '{dialog.componentname}.V.R1.PLACEHOLDER_1'
    }
}
{dialog.object}.phoneGapFileDownload(arr,options);

 

So let's take this code and inject it directly into the fetchFile() function. We know the url of the file that needs to be downloaded (it is passed into the fetchFile() function), so we don't need to call the getFile() function as we did previously. The fetchFile() function will become:

 

 

Let's change this function to:

function fetchFile(url) {

 

    /*

    we need to put the url into an array of objects where the filename is

    specified by the 'filename' property.

    */

    var arr = [];

    arr.push({filename: url})
 

    var options = {
        targetFolder: '__myAlphaFiles',
        showProgress: true,

        forceDownloadIfFileExists: false,
        onComplete: function(array) {
            alert('file was downloaded');
        },
        onError: function(array,arrayIndex) {
            alert('error');
        },
        progress: {
            color: '#9fa1e8',
            width: '300px',
            allowCancel: false,
            progressElement: '{dialog.componentname}.V.R1.PLACEHOLDER_1'
        }
    }
    {dialog.object}.phoneGapFileDownload(arr,options);

}

 

The next step is to replace the onComplete code above, which current simply does:

alert('file was downloaded');

 

with the code that reads and processes the JSON file.

As you will recall when we defined the action to read the file and then examined the generated Javascript, the code to read the file was:

 

{dialog.object}.phoneGapReadFile('__myAlphaFiles/A5SessionFile/data1.json',function(data) {
    var _d = JSON.parse(data);

    var _dt = '';

    for (var tableName in _d) {

           _dt = _d[tableName];

           var msg = 'Rows in table \'' + tableName + '\': ' + _dt.length;

           alert(msg);

    }

    },function() {
        alert'Could not read file');
    }

)

 

We need to simply replace the codeblock that says alert('file was downloaded'); with the above code block. However, rather than simply injecting the read file code into the onComplete event let's wrap the code that read the file in a function and then call this function in the onComplete event.

 

So we have:

 

function readFileAfterDownload() {

    {dialog.object}.phoneGapReadFile('__myAlphaFiles/A5SessionFile/data1.json',function(data) {
        var _d = JSON.parse(data);

        var _dt = '';

        for (var tableName in _d) {

               _dt = _d[tableName];

               var msg = 'Rows in table \'' + tableName + '\': ' + _dt.length;

               alert(msg);

        }

        },function() {
            alert'Could not read file');
        }

    )

}

 

And the fetchFile() function becomes:

 

function fetchFile(url) {

 

    /*

    we need to put the url into an array of objects where the filename is

    specified by the 'filename' property.

    */

    var arr = [];

    arr.push({filename: url})
 

    var options = {
        targetFolder: '__myAlphaFiles',
        showProgress: true,

        forceDownloadIfFileExists: false,
        onComplete: function(array) {
            readFileAfterDownload();
        },
        onError: function(array,arrayIndex) {
            alert('error');
        },
        progress: {
            color: '#9fa1e8',
            width: '300px',
            allowCancel: false,
            progressElement: '{dialog.componentname}.V.R1.PLACEHOLDER_1'
        }
    }
    {dialog.object}.phoneGapFileDownload(arr,options);

}

 

 

 

 

 

 

 

UX Component - Abstract Events - Tweaking Settings - For mobile applications built with the UX component, several abstract events, such as tap, double tap, swipe, etc. are implemented. In certain cases you might want to customize aspects of the way these abstract events are implemented. For example, you might want to:

 

This can be done by setting properties on the $e.abstractEvents object. You could, for example, set these properties in the onRenderComplete client-side event.

 

Examples:

//if the user's finger moves by more than 20px after touching the screen, the 'tap' event will not fire.

$e.abstractEvents.tap.wiggle = 20

 

//if the user puts a finger on an element that has a 'click' event handler and then scrolls the screen by

//more than 20px, the 'click' event will not fire.

$e.abstractEvents.click.scrollMax = 20

 

 

//if the time between the first tap and the second tap is less than 600ms, a 'dblTap' event will fire.

$e.abstractEvents.dblTap.duration = 600

 

 

$e.abstractEvents.dblClick.duration = 600

//see dblTap example

 

//if you hold down on an element for less than 600ms the 'downHold' event will not fire

$e.abstractEvents.downHold.duration = 600

 

//if you hold down on an element for more than the 'downHold' duration, but move your finger

//by more than 10px after you touch the screen, the 'downHold' event will not fire

$e.abstractEvents.downHold.wiggle = 10

 

//specify the 'swipe' velocity - a smaller value will mean that a less 'dramatic' gesture is needed

//to register a 'swipe' event on an element

$e.abstractEvents.swipe.velocity = .75

 

 

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

 

UX 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 work 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.template.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 then 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.json",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_storageJSONformat(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 named 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>

 

In the case of a UX component, add a Container control around any controls that you want to be selectable and then set the in-line style of the container to:

-webkit-user-select: text;

 

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.

Apperian’s 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