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.

 

 

Build 2446-4365 1-Oct-2014

Bugs

UX Component - List Control - Detail View - A bug was introduced in build 2442 that caused the Detail View to not populate correctly in certain rare situations when a row in the List was selected.

Application Server - Reports - Under certain circumstances, a report would print correctly the first couple of times it was printed, and then start to fail.

UX and Grid Component - Grid Linked Content Section - .getParentObject() Method - If a UX or Grid was opened in a parent Grid's Linked Content Section, the child component could not use the .getParentObject() method to get a pointer to the parent Grid.

 

Build 2442-4362 29-Sept-2014

Videos

Tabbed UI Component Using Alternative Login The 'Alternative Login' feature allows a user to log in to an application using their credentials from a social network, such as Google, Twitter, LinkedIn, etc.

The UX component allows you to build Login dialogs that allow users to log into an application using an Alternative Login. The integrated login feature in the Tabbed UI, however, does not allow you to expose Alternative Logins. Therefore, if you want to allow a user to login into an application that uses the Tabbed UI, you must use a UX component in the Tabbed UI to do the log in.

In this video we show how this can be done.

Watch Video

Date Added: 2014-09-11
UX Component Downloading a Google Chart as a Bitmap In the video 'Using Google Charts as an Alternative to the Built-in Chart Controls' we showed how you can use Google Charts in a UX component. In this video we show how you can add a button to the UX to download a Google chart as a bitmap image. The user can then save the image to disk, or print the image.

Note: Not all Google chart types support this feature.

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

Date Added: 2014-09-13
Xbasic Working with SQL Databases A common requirement in server-side events handlers (including custom Ajax callbacks) is to write some Xbasic code that manipulates data in a SQL database.

Xbasic has a very powerful set of objects (called AlphaDAO) for interacting with SQL databases.

In this video we give a quick overview to using Xbasic to work with SQL databases.

(For a full introduction and tutorial on using Xbasic to work with data in SQL databases, go to the Help, Open Documentation menu command and type 'Using Xbasic with SQL Tables' in the filter box.)

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Xbasic Calling Into Node.JS from Xbasic Node.js is a popular technology for implementing server-side utilities. Xbasic has very tight integration with Node and it is possible to create Node services that can be called from Xbasic.

In this video we show how a Node service can be defined and then called from Xbasic.

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

 

Features

UX and Grid Component - Ajax Callbacks - OnComplete Javascript - A new option has been added to the method that makes an Ajax callback from the Grid and UX component. You can now specify Javascript to run when the callback is complete.

This option has been exposed in the Action Javascript Ajax Callback action as shown in the image below:

The Javascript that you specify is run after the callback is complete and after any Javascript returned by the callback function has executed.

To specify the after callback complete Javascript in the UX or Grid's .ajaxCallback() method, you set the onComplete property in the optional optionsObject passed in.

 

For example:

{dialog.object}.ajaxCallback('','','myXbasicFunction','','',{onComplete: function() {

        alert('callback is complete')

    }

})

 

Tabbed UI - Integrated Login Feature - When the Login window is opened, the User name field is now automatically given focus. Previously the user needed to explicitly click on the user name control. In addition, when the password field has focus, pressing the Enter key will now execute the Login button.

Security Framework - Importing Data into the User Table - The previous import method, a5ws_ImportUsersDBF(), did not support import into SQL based security tables. The import feature has been rewritten and a new method, a5ws_ImportUsers(), is available. The import will now properly add records into SQL security tables.

The a5ws_ImportUsers() method can be used to import data into either .dbf security tables or SQL security tables. When importing into .DBF tables security tables, this new method is up to twice as fast.

TIP: You can also now use the a5ws_ImportUsers() function from the Interactive Window of the Application Server control panel to import users into your security tables on your server. When you use this function from the Interactive Window it will display a list of all web projects that have security and you can select the project into which you wish to import data.

 

Xbasic - Node.JS - Extending Server-side Functionality using Node.js - Node.js is a popular program for writing server side utilities in Javascript. Alpha Anywhere now has tight integration with Node and you can now define your own Node modules that can be called from Xbasic.

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

To create a new 'Node Service' that can be called from Xbaisc, you create a new .js file in the Node_Services folder in the Alpha Anywhere executable folder. The syntax for this .js file is the syntax you would use for any Node module.

To call a Node service from Xbasic, you:

 

In the following example, we have defined a trivial Node service that takes as its input two variables, 'firstname' and 'lastname' and sends back a string showing: Hello firstname lastname.

The Node service in this example is called 'hello'. Therefore the '_command' property of the JSON command object is set to 'hello'

You must also set an '_id' property in the JSON command object. This can be any value. Using a UUID for this value is convenient.

The Node service is called using the .NodeRequest() method and the result is returned as a JSON string with properties for the error text (if there was an error) and 'result' - the result of the request. The JSON response can be parsed to get Xbasic varibles, or the json_extract() function can be used to extract the 'result' property.

 

 

 

dim n as helper::V8
dim p as p

'generate an id for the request we are about to send to Node.

'we just use a GUID for convenience
p._id = api_uuidcreate()

 

'set the _command property. This is the name of the Node service we want to call
p._command = "hello"
 

 

'specify any variables you want to pass to the Node service

p.firstname = "Nellie"
p.lastname = "Jones"
 

'convert the Xbasic .dot variable to a JSON string.

dim jsonCommand as c

jsonCommand = json_generate(p)


?n.NodeRequest(jsonCommand)
= {"_id":"id1","error":"","result":"Hello Nellie Joness"}
 

 

Here is how the corresponding Hello.js file is defined. This file must be in the Node_Services folder in the Alpha Anywhere executable folder. This is a standard Node module. It can 'require' any other Node modules that you have written, or that have been installed using NPM (the Node Package Manager).

 

exports.handler = function(packet,response,sendResponse) {
    var e;
    var attachments = null;

    var msg = 'Hello ' + packet.firstname + ' ' + packet.lastname;
    response.result = msg;

    sendResponse(response,attachments);
};
 

 

If you edit the .js file in the Node_Services folder after having called it, your edits will not be seen until you shutdown the Node service. The next time you call the Node service you will see a short delay as Node starts up.

To shut down the Node service you can all the .NodeShutDown() method on the helper::V8 object instance. For example, in the above example the helper::V8 object instance was called 'n', so the following command will shut Node down.

 

n.NodeShutdown()

 

NOTE: Node.exe is automatically installed in the Alpha Anywhere executable folder when you install Node. You do not need to install Node yourself.

 

UX Component - Client-side Events - onPhoneGapReady - This event fires when the UX component is running in a PhoneGap shell and the PhoneGap library has been loaded.

NOTE: The existing onCordovaReady event has been deprecated and will be removed at some point. Move any code defined for the onCordovaReady event to the onPhoneGapReady event.

 

UX Component - {dialog.object}.phoneGapLoaded() Method - Returns true if the UX component is running in a PhoneGap shell.

 

List Control - Detail View - Disconnected Application - Count Records to Be Synchronized - A new method gives a count of the number of unsynchronized records.

 

Syntax:

object = {dialog.object}.countRecordsToSynch(listId)

 

Returns an object with properties showing the number of records that have not yet been synchronized with the server. The object has these properties: count, updatedRecords, newRecords, deletedRecords. 'count' is all dirty records (edits, inserts and deletes), 'updatedRecords' is all records that were edited, 'newRecords' is records that were added and 'deletedRecords' is records that were deleted.

 

Example:


var o = {dialog.object}.countRecordsToSynch(listOrders)
alert('You have ' + o.count + ' records to synchronize')

 

 

List Control - Detail View - New Events to Transform Data Before Display and Save - When you define a List control with a Detail View, two new properties are exposed for each List field.

 

These properties allow you to transform the data before it is displayed in the Detail View and before the Detail View is saved back to the List. The code you you specify in these two properties must 'return' the transformed value.

The Javascript for both of these properties can refer to

this._value

 

to get the default value that the Detail View control should be populated with when the user clicks on a Detail View row and to get the default value that the List should be updated with when the user clicks the Save button to save the Detail View back to the List.

For example, say that in the List data for row 2, the value for the Lastname field was 'Smith'.

In the onDetailViewPopulate event, you might specify this Javscript

return this._value.toUpperCase()

 

When the user clicked on row 2, the value shown for the Lastname field in the corresponding Detail View control would be:

SMITH

even though the actual data in the List for that field was 'Smith'.

Similarly, in the onListUpdate event, you might specify this Javascript:

return this._value.toLowerCase()

 

When Detail View edits were saved back to the List, the List would be updated with the the lowercase version of the data in the Lastname field


 

 

 

UX and Grid - Edit-Combo - Filter choices by searching anywhere in field -  Previously, in an edit-combo, as you typed into the textbox, the choices were filtered, starting the search with the first letter in the entry. Now, you can set the 'Search style' property to search anywhere in each entry.

 

For example, if the choices in the edit-combo were

 

Austria

France

USA

UK

 

and you typed 'U' in the textbox, the choices would be filtered to

USA

UK

 

Now, if you set the 'search style' to 'Anywhere in field', the choices will be filtered to

Austria

USA

UK

 

 

UX Component - HTML Editor - Toolbar Icons - You can now customize all of the icons used in the HTML editor toolbar.

Reports - SQL - Native SQL - Previously, if a report was based on a custom SQL statement and the SQL type was set to 'Native', during execution of the report the SQL statement was parsed (sometimes more than once). Parsing the SQL was necessary in order to determine if the report used arguments that were not defined (and therefore if a prompt should be shown for missing arguments) and in order to add in dynamic filters and order definitions.

In certain cases, the native SQL being passed to the report engine was so complex that parsing the SQL added a substantial delay to rendering the report.

Now, if you specify that the report data source uses native SQL the SQL query for the report will never be parsed. It will simply be passed to the database engine to execute.

As a result of this change if your native SQL statement uses arguments and you do not pass in values for all of the arguments used in the SQL, the report will no longer be able to dynamically prompt for missing argument values. Also if you are attempting to dynamically add a filter or order to the report at runtime, this will no longer work in the case were the report is based on native SQL.

 

UX Component - List Control - Scroller - Previously, the 'scroller' feature was only supported for Lists if the UX style was set to iOS7, AndroidDark or AndroidLight. Now, the scroller is supported for all styles.

Bugs

UX Component - Security Framework - Error Messages - Errors returned from the server-side Action Scripts to validate web security values, save web security values, and change web security passwords may not display property if the UX uses Panels, a placeholder is specified for the UX component validation errors, or the option to show errors in a popup window is selected. This is now fixed. The Action Scripting actions in the server-side events must be edited to apply the change. Select any of the web security actions in a server-side event and select "Edit action". Click OK to save and the code will be updated.

Grid Component - Oracle 9i - Fixed an issue using a Grid with Oracle9i.

UX Component - Textbox and Textarea Controls - Help Icon - Container With Layout Mode - If a textbox or textarea control had its help icon turned on, and if the icon was displayed left or right of the control and if the UX layoiut mode was set to 'Container width' (the default mode), the icon would show above or below the control. This is now fixed.

 

UX Component - Data Binding - Views - Auto-increment - Entering new records into a UX component that was bound to a View (rather than a Table) which had an auto-increment primary key would fail. The record was inserted, but not refreshed after insert.

UX Component - Display Wait Message on Ajax Callback - In some cases the wait message was not being cleared after the callback completed and the screen remained in a locked state.

UX and Grid Components - Lookup Grids  - SQL - Filter - If you defined a Lookup Field that used a Grid based on a SQL database and you specified that the Lookup Grid had both a static filter and a dynamic filter, you would get an error when opening the lookup Grid. The error only happened if the static filter was defined as a 'base' filter.

Grid Component - Image Download - Detail View - Image download of an image field in the Detail View part was not working correctly.

Grid Component - File Upload Action - New Record Rows - Uploading a file on a new record row caused an error.

UX Component - HTML Editor - Container Window - If you added a textarea control (configured as an HTML editor) into a Window Container, then when the window was displayed, the HTML editor was displayed, but you could not type into the editor.

Grid and UX Builder - Working Preview - Internet Explorer V10 and Earlier - If you had IE10 or earlier installed on your computer, in some cases you would get a Javascript error when testing a component in Working Preview.

 

Tips

AlphaDAO - Oracle - Returning a Resultset from a Stored Procedure - Returning a SQL::Resultset object from an Oracle stored procedure can be tricky depending on which version of Oracle you are using.

As an alternative to returning a resultset from a stored procedure, you can use an Oracle function.

In this example we show how a resultset is returned using an Oracle function.

NOTE: The Oracle database used in this example was created by using the Workspace Upsize Genie (see the 'Tool' menu when the Control Panel has focus) to upsize the sample Alphasports Workspace that ships with Alpha Anywhere.

 

 

dim cn as sql::Connection

dim flag as l
flag = cn.open("::Name::oracle_alphasportsUpsize")
 


dim sql as c
sql = <<%str%
create or replace FUNCTION REFCURSOR_CUST(p_city IN VARCHAR2) RETURN SYS_REFCURSOR AS p_recordset SYS_REFCURSOR;
BEGIN
OPEN p_recordset FOR select FIRSTNAME, LASTNAME, BILL_CITY from CUSTOMER where bill_city LIKE p_city;
return p_recordset;
END REFCURSOR_CUST;
%str%
 

 

'Oracle does not like CRLF in statements, so convert CRLF to spaces

dim sql2 as c
sql2 = stritran(sql,crlf()," ")
 

'Execute the SQL statement to define the function

flag = cn.Execute(sql2)

 

dim sql::arguments

args.add("Whatcity","Boston")
 

'Execute the function. Notice the 'from dual' syntax that Oracle requires
flag = cn.Execute("select REFCURSOR_CUST(:whatcity) from dual",args)
 

 

dim rs as sql::resultset

rs = cn.ResultSet
dim txt as c

txt = rs.ToString()

 

showvar(txt)

 

Here is what we see:


Mary McDonald Boston
Richard Queen Boston

 

If you are using Oracle 12, you have the option of using implicit cursors in a stored procedure.

The above function definition could be written as the following stored procedure:

 

CREATE OR REPLACE PROCESURE SP_GETCUSTOMERS (p_city IN VARCHAR2)

    AS

p_recordset SYS_REFCURSOR;

BEGIN

OPEN p_recordset FOR SELCT FIRSTNAME, LASTNAME, BILL_CITY FROM CUSTOMER WHERE BILL_CITY LIKE P_city;

DBMS_SQL_RETURN_RESULT(p_recordset);

END;

 

 

 

 

 

 

 

UX Component - In-Control Buttons - Delete Text - Only Show Icon if Existing Text  - The In-Control Button feature of a textbox allows you to embed icon inside a textbox. A typical use for for this feature is to allow the user to easily clear out existing text in the control.

You might want the icon to only show if there is existing text in the textbox, as shown in the the screenshots below.

 

 

In order to do this you will need to add code to t he Click action for the in-control button and to the onKeyUp event for the textbox control.

 

You will also need to add code to the onRenderComplete client-side event of the UX to set the initial state of the icon.

 

 

Here is the code you need to add to the Click action:

 

 

//clear the value in the control

{this}.value = '';
 

//get a pointer to the element that contains the icon and hide it
var ele = $('{dialog.ComponentName}.V.R1.TXT1.CUSTOMBUTTONSTATIC.0')
ele.style.display = 'none';

 

 

Here is the code to add to the onKeyUp event for the textbox.

 

//get a pointer to the element that contains the icon

var ele = $('{dialog.ComponentName}.V.R1.TXT1.CUSTOMBUTTONSTATIC.0');

//if there is text in the control, show the icon, else hide the icon
if(this.value == '') {
    ele.style.display = 'none';
} else {
    ele.style.display = '';
}

 

 

Here is the code for the onRenderComplete client-side event to set the initial state of the icon:

 

var ele = $('DLG1.V.R1.TXT1.CUSTOMBUTTONSTATIC.0')
ele.style.display = 'none';

 

 

Build 2399-4351  8-Sept-2014 - Alpha Anywhere Version 3

We are pleased to announce Alpha Anywhere Version 3. This release contains a huge number of new features, enhancements, performance improvements and bug fixes.

The standout feature in the release are the enhancements made to the List control to support building disconnected mobile applications. See the 'Features' section for details.

 

 

Videos

UX Component Tree Control - Populating Data using Javascript The data in a tree control on a UX component can easily be set using Javascript. In this video we show how to repopulate the entire tree, or dynamically add a node to an existing tree.

Watch Video
Download Component
UX Component Submitting all of the Data in a List Control on an Ajax Callback When an Ajax callback is made, the data in the variables on the UX are submitted, but the data in List controls are not submitted. There may be situations where you want to submit all of the data that are currently in a List control to the server.

In this video we show how you can 'harvest' the data that is in a List control and then submit that data to the server when you make an Ajax callback.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX and Grid Component Using Chrome for Working Preview - Debugging Javascript using the Chrome Debugger; When you are in the Component builders, the Working Preview window now allows you to choose whether you want to use Internet Explorer or Chrome.

Using Chrome has several benefits, including the ability to 'detach' the Working Preview window so that it can be moved to a second monitor and be kept open while you continue to design your component. You can also use the Chrome Debugger to debug your Javascript or inspect elements on the page.

Watch Video - Part 1
Watch Video - Part 2
UX Component List Control - Custom Control - Client-side When you define a List control in a UX component, one of the 'control types' that you can insert into the List is a 'Custom Control'. A 'custom control' is computed with an Xbasic function. Because Xbasic is used to render the custom control, it means that the custom control is rendered server-side when the List is initially rendered. If your UX component has code that modifies data in the List, the server-side custom control is obviously not re-rendered.

Therefore, you might want to define your custom control using client-side Javascript.

This video shows an approach to creating client-side custom controls in a List component.

Watch Video
Download Component
UX Component - List Control Vertically Justifying Data in a Row By default, data in a columnar List control is vertically top justified. In a Grid, on the other hand, data in a Grid row is vertically middle justified. In a Grid this is easily done because the generated HTML for a Grid uses an HTML table. The generated HTML for a List is not based on an HTML table, and so middle justifying the data is a little trickier.

In this video we show how you can vertically middle justify data in a List row.

Watch Video
Download Component
UX Component - List Control Displaying Data From Twitter The Twitter API returns data in JSON format. The List control on a UX component is easily populated with JSON data. The Twitter API, however, is a little tricky to work with because it requires an OAuth authorization before you can call the API functions. Xbasic contains two built-in functions that simplify this.

In this example we show how you can easily build a List control that displays Tweets that are retrieved by making a REST API call to Twitter.

In the example we use built-in Xbasic functions to get a 'bearer token' from Twitter. Once we have this token, we can make calls to the Twitter API to get data in a JSON format that is used to populate the List control.

IMPORTANT: The video shows selecting the Twitter List from the 'Defined Controls' section of the UX builder toolbox. This has been changed. You should now select the 'Twitter_Display_Tweets_in_a_List_Control' sample UX Component template in the dialog that appears when you create a new UX component.


Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Reports Suppressing Blank Rows in a Layout Table Report The Layout Table report editor exposes a property that you can set for each row in the Layout Table to suppress the row if it is blank.

In this video we show how blank lines in a Layout Table Report are suppressed. We also discuss how the report writer determines that a row is 'blank'.

Watch Video
UX Component Setting Content of Scrollable Containers/Windows Normally, you can set the content of an element in a component by simply getting a pointer to the element and then setting the element's .innerHTML property. However, if the element whose content you are setting has been configured to allow drag scrolling, setting the .innerHTML directly will destroy the drag scroll settings and the new content will no longer be scrollable.

The solution to this problem is to use the A5.u.element.setContent() function to set the element's content.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Edit-Combo Control - Specifying a Different Stored Value from the Display Value Dropdownbox controls allow you to specify that the stored value is different from the display value. For example, the control might display a 'ProductName' but the stored value in the control might be the 'ProductId'.

Edit-combo box controls can now also be configured to store a different value than their display value, just like a Dropdownbox control.

The benefit of using an Edit-combo control over a Dropdownbox control is that you can display multiple columns of data in the choice list and you can dynamically populate and filter the choices in the list with an Ajax callback every time the control is opened.

In this video we show how to configure an Edit-combo control to store a different value from its display value.

Watch Video
Interactive Window Executing Shell Commands Directly from the Interactive Window You can now execute shell commands directly from the Interactive Window.  You no longer have to open a separate CMD window to execute shell commands. This can be a very useful time saver for developers.

For example, when building an application that uses REST APIs, it is common for the API documentation to show how you can use CURL to execute the REST command. Using the Interactive Shell, CURL commands can be executed directly from the Interactive Window.

Watch Video - Part 1
Watch Video - Part 2
     
UX Component Dynamic Images - Client-Side When you add a 'Dynamic Image' column to a List control to display an image in the List that is based on other data in each List row you can specify if the computation of what image to show should be server-side, or client-side. If server-side, your expressions that define the conditional tests are specified in Xbasic. If client-side, your conditional expressions are expressed in Javascript.

The benefit of client-side dynamic images is that the image will be automatically recomputed when the data in a List row is updated.

In this video we show how client-side Dynamic Images can be defined and then we show another technique for creating client-side Dynamic Images using the List's Computed Columns feature. This second technique has the advantage of offering more flexibility.

Watch Video - Part 1
Watch Video - Part 2
Download Components
UX Component Client-side Template Tutorial Client-side templating allows you to generate HTML for display by merging a data object into a template. The client-side template library in Alpha Anywhere is extremely powerful and can be compared with similar functionality in 3rd party templating libraries, such as Mustache.js and Handlebars.js.

In this video we show how a complex template can be designed to display data (a list of Orders with OrderItems for each order) in a richly formatted display. The video shows how the templating system can compute values, including summary values.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
Watch Video - Part 9
UX Component - PhoneGap Displaying .PDF, .XLSX, .DOCX Files Unlike desktop browsers, the browsers on mobile devices typically do not have built-in handlers for displaying .pdf, .xlsx, .docx and certain other types of files.

If your mobile application is wrapped using PhoneGap you can easily use the built-in native document viewer on both Android and iOS devices.

In this video we show how to build a PhoneGap app that can display .pdf and Microsoft Office files.

Watch Video
UX Component - PhoneGap Using Native Transitions If you wrap a UX component in a PhoneGap shell you can now use native transitions to animate certain Panel Cards in your app into view. This feature relies on the Native Transitions PhoneGap plugin (iOS only).

In this video we show how the Native Transitions plugin can be called.

Watch Video
Web Security Framework Alternative Logins - Logging into an Application using Google, Facebook, LinkedIn or Twitter When the Application Server Security Framework is turned on you can require that a user must log into an application before they can use it. A user will enter the userid and password associated with their account in the Security Framework in order to log into the application.

You can provide an option for a user to login to their account using the credentials from a social network as an alternative to their account userid/password.

You can also allow someone to log into an application using social network credentials and then automatically create a new account in the Application Server Security Framework for that user.

These videos demonstrate this functionality. If you have not yet read the documentation on Alternative Login, it is recommended that you read the documentation before watching the videos. Click here to read the documentation.

Video 1 - Setting up the Providers
Video 2 - Creating Named Providers
Video 3 - Configuring Web Security
Video 4 - Adding Alternative Login to a UX Component
Video 4 - Testing Alternative Login
UX Component - List Control Dialing a Phone Number Shown in the List When running on a phone, it is a common requirement to be able to dial a phone number that is displayed on screen. For example, you might have a List control showing contact names and for each name you have an associated phone number.

In this video we show how you can configure a hyperlink control in the List to dial a phone number.

Watch Video
UX Component - List Control Displaying a Custom Message in the List if the List has No Records A common requirement in a List is to show a custom message if the List has no records.

The List control has built-in properties to make this easy. You can also automatically center the message horizontally and vertically in the List.

Watch Video
Video Finder Finding Videos in the Video Library There are a large number of videos that have been recorded to demonstrate and explain various features in Alpha Anywhere. The Video Finder application (accessed from the Help menu) allows you to search for videos. In Alpha Anywhere V3, the Video Finder application has been completely rewritten to make finding videos even easier and faster.

The new Video Finder application has been implemented as a UX component with two List controls - one for the list of categories, and one to list the videos in each category.

This video discusses the new Video Finder application.

Watch Video
     

 

UX Component - List Control Introduction to the List Control Detail View The List control can have an associated Detail View. The Detail View allows you to see details for the currently selected row in the List. The Detail View can be updateable, allowing you to update data that is in the List.

In this video we show how you can add a Detail View to a List. We show two different genies that you can use - one for setting up a List with a Detail View, and another for adding a Detail View to an existing List.

IMPORTANT: Lists with Detail Views are the essential building block for applications that can work while you are disconnected. For more information about the features of Lists with Detail Views, see the videos in the 'UX Component - Disconnected Applications' category. Even if you do not need to build mobile applications that work while disconnected, the information regarding Lists and Detail Views in these videos will be relevant.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07
UX Component - List Control Contrasting Data Binding at the UX Level with Data Binding at the List Level to Update a SQL Database When you want to update data in a SQL database using a UX component you previously could define Data Binding properties for the UX component, then define a server-side action that loaded the primary keys of the records you wanted to edit and another server-side action to save the edits back to the SQL database.

Now, using a List control with an updateable Detail View, you can perform edits on a SQL database using the List and its associated Detail View.

In this video we contrast the two methods of performing CRUD (create, read, update, delete) operations on a SQL database using Data Binding and List controls.


Watch Video - Part 1
Watch Video - Part 2


Download Components

Date Added: 2014-09-07
UX Component - List Control List Control Search Part The List control has a built-in Search Part that allows you to perform searches on the database that is used to populate the List. (This is very much like the Search Part in a Grid component).

The Search Part in the List can be configured in three different ways:
- individual fields for the Search Part (allowing the user for example to enter criteria in a Name, City or Country field)
- a single keyword field (allowing the user to enter criteria in a single field then then searching for matches in multiple fields)
- query by form (allowing the List's Detail View to be used to enter the search criteria)

In this video we show how the various options can be used to search a List.

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

Download Components

Date Added: 2014-09-07
     
UX Component - Disconnected Applications Introduction You can build applications that are designed to work when you are disconnected. The UX component and the List control are the fundamental building blocks of these types of applications.

In this video overview we show how a UX component is built using a List control with an associated Detail View to display and edit data, how the data in the List is persisted to Local Storage and then how the edits made to the List data are synchronized with the server. We also show how your disconnected data can be 'hierarchical' - i.e. a list of customers, with orders for each customer and order details for each order.

Watch Video 1 - Setting up a List with a Detail View using the Quick Setup Genie
Watch Video 2 - Editing Data and Persisting Data to Local Storage
Watch Video 3 - Introduction to Hierarchical Data Structures


For more information on building disconnected applications, click here.

Date Added: 2014-09-07
UX Component - Disconnected Applications Editing Data While Offline and then Synchronizing the Data When you build an application for disconnected operation, the List control is the basic building block for the application. The List control is used as the 'offline' data storage. The data in the List control can be thought of as an in-memory table. Edits to this data are persisted to Local Storage and then are pushed to the server to synchronize with the server database when a connection is available.

In this video we look at how data in the List are edited and then synchronized with the server database.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Editing Data While Offline - Behind the Scenes - What Data are Stored in the List In order to get a better understanding of how the data in a List control are stored to support disconnected operation, this video shows how you can debug into the internal data that is stored in the List when the user edits, enters and deletes records.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Errors - Validation Errors When a user synchronizes edits to data that were made while they were offline, there is the possibility of synchronization errors.

These errors can typically result because the user entered a value in a field that was rejected by some server-side validation logic, because of a write conflict, or because the database rejected the edit.

In this video we show how synchronization errors that result from server-side validation errors and database errors are handled.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Errors - Write Conflicts When a user synchronizes edits that were made while they were offline, there is the possibility that some other user edited and then synchronized the same data before the user had a chance to synchronize his/her edits.

If this happens a write conflict will occur and the user will be notified that the synchronize operation could not be completed. The user will have to choose how to resolve the conflict. The developer also has the option of handling write conflict errors programmatically.

In this video we show how write-conflict errors are handled.

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


Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronization Events When data in a List control is synchronized with the server database there are a number of events that fire (on both the client-side and the server-side) that give you a lot of control over the process and allow you to inject custom code to be executed.

In this video we discuss some of the events that fire when data are synchronized.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Custom Synchronization Handlers When the user synchronizes a List that is based on a SQL database, Alpha Anywhere automatically generates the SQL statements to perform the various CRUD (create, read, update, delete) operations.

However, if your List is based on a custom datasource (for example, a web service), then you must write your own functions to handle synchronization of the data.

In this video we show an example of how custom handlers can be written to synchronize data.

Watch Video - Part 1
Watch Video - Part 2

Download Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Incremental Refresh After a List has been populated with data from the server you can perform incremental refreshes on the List data to retrieve any edits that have been made to server data. Unlike a full refresh, only rows that have been edited are sent to the client, resulting in a much smaller payload being sent to the client compared to a full refresh of the List data.

You can also set a 'synchronization policy' in the List definition to specify that every time edits to the List data are synchronized with a server an incremental refresh of the List should also be performed.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Geographic Data - Capturing Location Information when the User Edits Data You can configure a List so that every time the user enters a new record, or edits a record, the user's location will be stored. This allows you to create applications where you capture the location of the device at the time a record was edited or entered.

In this video we show how this is done.

Watch Video - Part 1
Watch Video - Part 2

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Geographic Data - Capturing Location Information when the User Synchronizes Data In a  previous video we show how location information can be captured at the time the user edits a record in the List. But you can also capture location information at the time the user synchronizes the data.

In this video who show how to configure the List to submit location information at the time the user synchronizes the List.

Watch Video

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
     
UX Component - Disconnected Applications Geographic Data - Geocoding Data In order to perform geography searches on your data (for example, find all records that are within 5 miles of my current location), you need to geocode the data in your table. For example, if you have captured the address for the record, when the record is synchronized, you can make a call to a geocoding service to get the latitude/longitude for the record. Then when the record is written to the database you can also compute the location field value so that geography searches are possible.

In this video we discuss the features that the List control exposes to support working with geographic data.

Watch Video

Download Component
Schema for MySQL Table Used in Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Setting Default Values for Fields in New Records When you enter a new record in a List with a Detail View you might want to set default values for certain of the fields in the Detail View.

The List builder allows you to execute Javascript code to compute the default value for each field in the List. This allows for sophisticated computations for the default value, including setting the default value for a field to the value that was just entered into the previously entered record.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Synchronizing Data in Batches If the user has made a large number of edits while they were offline you might want to synchronize the data in batches, rather than sending all of the edits to the server at once.

In this video we show how you can configure the synchronization process so that data are sent to the server in batches.

Watch Video
Download Component

Date Added: 2014-09-07
UX Component - Disconnected Applications Delaying Populate List Till Active Search In an application designed for disconnected usage, the user will typically load a subset of the database onto their mobile device while they have connection.

This is usually done by adding a Search Part to the primary List control in the component and specifying the the List should not be populated until the user has performed a search to retrieve the 'records of interest'.

TIP: For more information on how to set up the Search Part for a List control see the video titled 'List Control Search Part'.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Settings Maximum Number of Records that a Search Can Return In an application designed for disconnected usage, the List controls in the UX component hold the data that will be available while the user is offline. These Lists are populated when the user does a search to retrieve the 'records of interest' that they want to have available to them while they are on-line.

Since the amount of data that can be held on a mobile device is limited, you will typically want to ensure that the user does not enter search criteria that retrieve too many records.

In this video we show how you can set limits on how large a result a user search is permitted to return.

Watch Video

Date Added: 2014-09-07
UX Component - Disconnected Applications Persisting Data to Local Storage When you build an application for disconnected operation you need to be sure that the data in the application is persisted to Local Storage so that edits that are made to any data are not lost if the application is restarted before the user has had a chance to synchronize the data with the server.

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


Date Added: 2014-09-07
UX Component - Disconnected Applications Working with Hierarchical Data The data for disconnected applications are stored in List controls. In many types of applications the data you need to work with is hierarchical. For example, you might have a list of customers. Each customer has orders and each order has order details.

In a connected application, you can make an Ajax callback to the server when a user selects a different customer to fetch to orders for that customer. However, in a disconnected application you cannot make callbacks to the server, so when the user selects a customer, the orders for that customer must already have been retrieved from the server so that the data can be shown without making an Ajax callback.

The List control can easily be populated with hierarchical data. In this video we explain how a List control is populated with a customers, each customers' orders, and each order's details.

Watch Video - Part 1
Watch Video - Part 2

In this follow on video we show how new records can be added to child tables and how the new records are automatically linked to their parent. In the video we show how a new order is added for the selected Customer record and then how new order detail records are added for the new order. When the data are synchronized, the linking fields are automatically filled in - the customer Id is filled into the new order record and the order id is filled into the new order detail records.

Watch Video - Part 3

Download Component


Date Added: 2014-09-07
UX Component - Disconnected Applications Managing Local Storage When you build an application that is designed for offline use (i.e. a disconnected application), the data in the List controls, and the variables in the UX component are persisted to Local Storage.

In this video we show how you can manage the data in Local Storage using the built-in Local Storage manager and using methods of the UX component.

Watch Video - Part 1
Watch Video - Part 2


Date Added: 2014-09-07

Features

Building Disconnected Mobile Applications - The UX component now allows you to build mobile applications that work while you are disconnected.

 

The following videos will give you a quick overview of building disconnected applications in the UX component:


Watch Video 1 - Setting up a List with a Detail View using the Quick Setup Genie
Watch Video 2 - Editing Data and Persisting Data to Local Storage
Watch Video 3 - Introduction to Hierarchical Data Structures
 

For detailed information about this feature, click here.

 

UX Component - List Control - Detail View and Search Part- List controls can now have an updateable Detail View and an integrated Search Part.

This feature is central to building disconnected applications, but should also be of great interest to developers of traditional desktop web application. (See the section in the detailed information - see link below -  that contrasts Data Binding with updateable Lists).

 

For detailed information about this feature, click here.

 

Application Server - 64 bit Machines - Alpha Anywhere is now compiled using a special compiler switch that allows access to more system RAM when running on a 64 bit machine. As a 32bit application, the amount of system RAM that Alpha Anywhere can access is limited to approximately 2GB. Now, up to 4GB of system RAM can be accessed. As a result of this change larger files can be uploaded, more simultaneous uploads can be performed, more sessions can be handled, and server restarts because of memory fragmentation should be needed less frequently.
 

 

Video Finder - The Video Finder (accessible from the Help/Video Finder menu) has been completely rewritten. The Video Finder now loads much more quickly and searches are much faster. Also, you can now click the 'Preferences' button on the toolbar to specify if the Video Finder should be opened in a MDI window or a modeless window. The modeless window option is useful if your computer has two monitors because it allows you to drag the Video Finder window to the second monitor and keep it open while you are working.

 

Watch Video

 

 

UX Component - List Control - Custom 'No Records in List' Message - A common requirement in a List is to show a custom message if the List has no records.

The List control has built-in properties to make this easy. You can also automatically center the message horizontally and vertically in the List. See image below.

Watch Video

 

 

 

UX Component - List Control - Hyperlink - Telephone - You can now configure a hyperlink control in a List to dial a telephone number. This is particularly useful in mobile applications that are run on a phone.

 

Watch Video

 

Assume you have a List control with this data:

name|phoneDisplay|phoneDial

John Smith (home)|(555) 555-5555|+15555555555

John Smith (mobile)|(555) 555-5556|+15555555556

 

The List data contains both the phone number to display in the List and the phone number to actually dial. Notice that the phone number that should be dialed includes the +1 prefix to indicate that this is a U.S. phone number. The phone number to be dialed must start with + and then the country code (1 in the case of the U.S.).

The phone number to be dialed can also include special directives. For example you can insert 'p' in the number to indicate a one-second pause and 'w' to indicate 'wait for dial tone'.

Using the sample data shown above, to configure the hyperlink to dial the telephone number in the 'phoneDial' field, but display the number shown in the 'phoneDisplay' field, you would set the 'Action type' property to 'Telephone', the 'Phone number' field to '{phoneDial}' (note that the placeholder is case-sensitive) and the 'Hyperlink text' property to '{phoneDisplay}', as shown in the image below.

It is permissible for the value passed in as the phone number to dial to include spaces and parentheses. For example, +1(555) 555-5555 is a valid number to dial.

 

 

If, for example, your List data had separate fields for the phone number (called 'phone' for example) and country code (called 'code' - without the leading + in the data), you could set the 'Phone number' field to:

+{code} {phone}

 

UX Component - List Control - Hyperlink - E-mail - You can now configure a hyperlink control in a List to open the associated e-mail client and fill in the 'to' address with a field.

To configure a hyperlink to open an e-mail client, set the 'Action type' to 'Email' and the 'Email address' to the value you want to put into the email client's 'to' address field. You can use placeholders in the 'Email address' property to refer to data in a field in the current row of the List.

 

 

UX Component - List Control - Hyperlink - Specifying a Target HRef - Previously, when you added a hyperlink control to a List, the action associated with the hyperlink was always some Javascript code. Now you can define standard HTML hyperlinks with an 'href' attribute that specifies the hyperlink target.

To specify a hyperlink target, set the 'Action type' to 'Href' and then specify the 'Hyperlink address'. You can use a placeholder for the address. For example if your List has a field called 'address', you can specify the 'Hyperlink address' as {address}.

The hyperlink address must include the protocol if the target is not a page in the application webroot. For example, to display bing.com, you would need to set the target to 'http://www.bing.com', but to display a page called 'page1.a5w' in the current webroot, you would just need to set the target to 'page1.a5w'.

 

 

 

 

Client-Side Template Tester - User Interface Improvements - The user interface in the client-side template tester window has been enhanced. The window is now resizable and has separate tabs for JSON Data, Template, Javascript and CSS.

As you edit in any of these windows the template preview is automatically updated in the right part of the window.

 

 

 

json_reformat_safe() Function - Reformats as string of JSON data with line-breaks and optional indentation.

Syntax:

c json_text = json_reformat_safe(json_text [, flagIndent = .t.])

 

For example:

 

dim json as c

json = <<%txt%

{firstname: 'Fred', lastname: 'Smith', Address: {
Street: '123 Main St',
City: 'Boston',
State: 'Ma'
}
}
%txt%

 

?json_reformat_safe(json)

= {
    "firstname": "Fred",
    "lastname": "Smith",
    "Address": {
        "Street": "123 Main St",
        "City": "Boston",
        "State": "Ma"
    }
}

 

NOTE: json_reformat_safe() wraps the lower level json_reformat() function. The json_reformat() function only accepts 'properly formed' JSON strings (property names must be double quoted and string values must be double quoted). json_reformat_safe() will automatically convert JSON strings where property names are not quoted and strings are single quoted.

 

json_extract() Function - Extracts a property from a JSON object .

Syntax

c text = json_extract( C json_text, c property_name)

 

NOTE The JSON text passed to the function must be properly formed (i.e. use double quotes on property and string names). You can use json_reformat_safe() to 'clean' up the JSON string before calling json_extract.

 

For example:

dim json as c

json = <<%txt%

{

    name: 'Fred',

    address: {

        street: '123 Main St',

        city: 'Boston',

        state: 'MA'

    }

}

 

'json_extract() requires properly formed JSON, so

'we first call json_reformat_safe()

dim json2 as c

json2 = json_reformat_safe(json)

?json_extract(json2,"name")

= "Fred"

?json_extract(json2,"address")

= "

{

        street: '123 Main St',

        city: 'Boston',

        state: 'MA'

    }

"

%txt%

 

 

Grid Component - Export - Comma Delimited ASCII - Quoting Fields with Commas - If the data you are exporting has commas in the data, the fields with commas are now quoted. If there are quotes inside a field, the quotes are escaped as double quote (e.g. "").

 

UX Component - Image Upload - Clear Image - Action Javascript has a method to upload an image and save the uploaded image in a field in the table that the UX is bound to. However there was no easy way to clear out a previously uploaded image - and set the field back to a null value. A new action in Action Javascript now support the 'Delete Image' action.

 

UX Component - Security Framework - Alternative Login - Login with Google, Facebook, Twitter and LinkedIn - You can now allow users to log into an Alpha Anywhere application using a 'social network' login.

The social network logins are referred to as 'alternative logins' because they provide an alternative way for a user to log into their account in the Alpha Anywhere security system using their social network credentials, rather than the userid/password associated with their account in the Alpha Anywhere security system.

The Alternative Login features are exposed as new actions in Action Javascript for use in a UX component.

For complete details on the Alternative Login feature click here.

 

Video 1 - Setting up the Providers
Video 2 - Creating Named Providers
Video 3 - Configuring Web Security
Video 4 - Adding Alternative Login to a UX Component
Video 4 - Testing Alternative Login

 

NOTE: In a previous pre-release build we added support for Google's OpenID protocol.Google has deprecated this protocol, and therefore we will not be supporting it in Alpha Anywhere.  If you attempted to test the OpenID protocol in a pre-release build, please send a bug report and we can provide instructions on removing the OpenID elements as they are not compatible with the current system, which is based on oAuth.

 

Xbasic - CURL - CURL is a popular utility that can be used for many tasks, such as making REST API calls. CRUL is now exposed as a top level Xbasic object, allowing you to execute CRUL commands from your Xbasic code.

Many APIs are documented using CURL examples.

You can use a built-in genie to convert a CURL command into an Xbasic script.

To get to the CURL genie, right click on white space in the Xbasic code editor and select the 'Genies...' command. The select the 'CURL command to Xbasic....' command.

 

 

 

This opens the CURL to Xbasic Genie where you can type in a CURL command then then click the 'Generate Xbasic' button to generate the Xbasic code to execute the specified CURL command.

For more information on the Xbasic CURL object, click here.

 

 

Xbasic - Parsing a Name/Value String - extension::URIQuery Class - Xbasic now has a new utility class that makes it very easy to parse name/value pairs in a 'query string'.

The following Interactive Window session demonstrates use of this class:

 

 

dim qs as c = "name=fred&city=boston&country=&age=25"
dim postQ as extension::URIQuery
postQ.ParseURIQuery(qs)
?qs
= "name=fred&city=boston&country=&age=25"

?postq.age
= "25"

?postq.country
= ""

?postq.ToJson()
= {"name":"fred","city":"boston","country":"","age":"25"}

 

Template Tester - Tools Menu - The Template Tester can now be opened directly from the Tools menu when the Web Control Panel has focus.

The Template Tester is useful when you are constructing templates that generate HTML by expanding data in an object. See 'Client-side Templates' in the Release Notes for information on templates.

NOTE: While templates are documented in a section called 'Client-side Templates' this is somewhat misleading because you can also use templates in server-side code using the a5_merge_JSON_into_template() Xbasic function.

 

Client-side Template Enhancements - Client-side Templates (first introduced in build 2091 - 4284 - see Release Notes for more information) have been enhanced.

 

The {*root} Tag

Previously if the data you passed into the  A5.u.template.expand() function was an array (as opposed to an object with an array as property of the object), you could not use the {*header} and {*footer} directives in your template to generate a header or footer for the array data.

Now, you don't have to artificially structure your data as a top level object with an array as a property of the object. The {*root} tag is now supported when the data passed in is an array.

 

Consider the following sample data:

var data = [
    {firstname: 'Fred', lastname: 'Smith'},
    {firstname: 'John', lastname: 'Jones'}
]

 

and the following template:

 

var template = [
                            '{*root}',
                            '{*header}There are {root.length} people<br />{/*header}',
                            '{firstname} {lastname}<br />',
                            '{*footer}Count: {root.length} {/*footer}',
                            '{/*root}'

                        ].join('');
 

This data and template will product this output:

 

There are 2 people
Fred Smith
John Jones
Count: 2

 

Because the template uses the {*root} tag, the data that is passed in is implicitly restructured as:

 

var data = {

    root: [
            {firstname: 'Fred', lastname: 'Smith'},
            {firstname: 'John', lastname: 'Jones'}
           ]
    }


 

Escaping the { and } Characters in a Template

The { and } characters in a template indicate placeholders for merged data. If you want to explicitly output either of these characters you can escape them using a leading backslash.

Assume that the data you pass to the template expander is:

{firstname: 'Fred'}

Assume that you want the output from the template to be

{Fred}

You would define your template as:

\{{firstname}\}
 

 

Pre-processing Arrays Before They are Expanded

You can now pre-process arrays before they are expanded.

For example, assume you have the following data:

 

var data = {

    company: [
        {firstname: 'Fred', lastname: 'Smith'},
        {firstname: 'John', lastname: 'Jones'},
        {firstname: 'Andrea', lastname: 'Jones'},
        {firstname: 'Margo', lastname: 'Jones'}
    ]
}
 

And the following template:

var template = [
    '{company}',
    '{firstname} {lastname}<br>',
    '{/company}'

].join('');
 

This template and data combination will result in this output:

Fred Smith

John Jones

Andrea Jones

Margo Jones

 

But, say you only wanted to output the top two customers. To do this you would need to pre-process the company array before it was expanded. You can specify the name of a function (which can be a global function, or a function in a namespace) to call before an array is expanded using the @functionName directive in the placeholder for the array.

 

For example, notice in the template below, the placeholder for the company array specifies that the processCompany function should be called before the data are expanded:

var template = [
    '{company@processCompany}',
    '{firstname} {lastname}<br>',
    '{/company}'

].join('');
 

The array pre-processor function gets called with three arguments

Your array pre-processor function must return the array that you want to render.

Here is how the processCompany array pre-processor function could be defined:

function processCompany(data,temp,root) {

    //limit to first two items in the array

    data = data.slice(0,2);

    return data;

}

 

The resulting output is now:

Fred Smith

John Jones

 

Now assume you want to first sort the data by the 'firstname' property, then return the top two entries. In this case, the array pre-processor function would be defined as:

 

function processCompany(data,temp,root) {

    //sort on the 'firstname' property

    data.sort( function(a,b) {
        if (a.firstname < b.firstname) return -1;
        if (a.firstname > b.firstname) return 1;
        return 0;
        }
    )
 

    //limit to first two items in the array

    data = data.slice(0,2);

    return data;

}

 

The resulting output is now:

Andrea Jones
Fred Smith

 

An important use for the array pre-processor function is to compute summary data for the array. See Using the Special "root" and "temp" Variables in Templates below. You can compute all of the summary values your template needs in a single function, rather than defining separate functions for each summary value your template outputs.

 

Using the Special "root" and "temp" Variables in Templates

You can use the special "root" and "temp" variables in a template by enclosing them in [ and ].

The example below demonstrates the use of both [root] and [temp] in the template.

Download component that demonstrates this example.

 

TIP: To watch a video of how the template used in this example was developed, watch these videos:

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
Watch Video - Part 9

 

For example, consider the following data set:

 

var data = [
    {

        orderId: 1,

        date: '1/1/2014',

        orderItems: [

                {itemId: 1, qty: 3, price: 23.4},

                {itemId: 23, qty: 2, price: 3.3},

                {itemId: 7, qty: 5, price: 5.3}

            ]

    },
    {

        orderId: 2,

        date: '1/2/2014',

        orderItems: [

            {itemId: 31, qty: 7, price: 3.8},

            {itemId: 17, qty: 4, price: 9.2}

        ]

    },

    {
        orderId: 3,
        date: '1/5/2014',
        orderItems: [
            {itemId: 11, qty: 9, price: 13.3},
            {itemId: 27, qty: 2, price: 19.2},
            {itemId: 6, qty: 19, price: 3.6},
            {itemId: 7, qty: 22, price: 9.1}
        ]
    }
]

 

The data are an array of order objects. Each order has a nested array called 'orderItems' that have the order items for that order.

Assume that you would like the template to render as shown below:

 

Order Id: 1 (Order number 1 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/1/2014
#Item IdQuantity PriceExtended Total
113$23.40$70.20
2232$3.30$6.60
375$5.30$26.50
Count: 3Avg Quantity: 3.33Avg Price $10.67Total: $103.30

Order Id: 2 (Order number 2 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/2/2014
#Item IdQuantity PriceExtended Total
1317$3.80$26.60
2174$9.20$36.80
Count: 2Avg Quantity: 5.50Avg Price $6.50Total: $63.40

Order Id: 3 (Order number 3 of 3 orders - for orders placed between 1/1/2014 and 1/5/2014)
Order Date: 1/5/2014
#Item IdQuantity PriceExtended Total
1119$13.30$119.70
2272$19.20$38.40
3619$3.60$68.40
4722$9.10$200.20
Count: 4Avg Quantity: 13.00Avg Price $11.30Total: $426.70

Grand total for all 3 orders is: $593.40

 

There is a lot going on in this example. The template for this example is shown below.

Items of note in this example include:

Here is the template for this example:

var template = [
    '{*root}',
        'Order Id: {orderId} (Order number {[countOneBased]} of {[root].length} orders - for orders placed between <b>{[root][0].date}</b> and <b>{[root][-1].date}</b>) <br>',
        'Order Date: {date}<br>',
        '{orderItems@orderItemsPreProcessor}',
            '{*header}',
                '<table border="1" cellspacing="1" cellpadding="3" style="border-collapse: collapse;" >',
                '<tr>',
                    '<th>#</th>',
                    '<th>Item Id</th>',
                    '<th>Quantity</th>',
                    '<th>Price</th>',
                    '<th>Extended Total</th>',
                '</tr>',
            '{/*header}',
            '<tr>',
                '<td>{[countOneBased]}</td>',
                '<td>{itemId}</td>',

                '<td style="text-align:right;">{qty}</td>',
                '<td style="text-align:right;">{price:number(\'$#,###.00\')}</td>',
                '<td style="text-align:right;">{qty*price:number(\'$#,###.00\')}</td>',
            '</tr>',
            '{*footer}',
                '<tr>',
                    '<td>Count: {[temp].itemCount}</td>',
                    '<td></td>',
                    '<td>Avg Quantity: {[temp].averageQuantity:number(\'#.00\')}</td>',
                    '<td>Avg Price {[temp].averagePrice:number(\'$#,###.00\')}</td>',
                    '<td style="text-align:right;">Total: {[temp].totalExtendedPrice:number(\'$#,###.00\')} </td>',
                '</tr>',
                '</table><br>',
            '{/*footer}',
        '{/orderItems}',
        '{*footer}',
            'Grand total for all {[root].length} orders is: {[temp].grandTotal:number(\'$#,###.00\')}<br>',
        '{/*footer}',
    '{/*root}'
].join('');
 

The array pre-processor function for the 'orderItems' array is defined as follows:

 

function orderItemsPreProcessor(data,temp,root) {
    var totalQuantity = 0;
    var totalPrice = 0;
    var totalExtendedPrice = 0;
    var extendedPrice = 0;
    var _d = '';
    for(var i = 0; i < data.length; i++) {
        _d = data[i];
        extendedPrice = _d.qty * _d.price;
        totalExtendedPrice = totalExtendedPrice + extendedPrice;
        totalPrice = totalPrice + _d.price;
        totalQuantity = totalQuantity + _d.qty;
    }

    //the first time this function is called temp.grandTotal will be undefined

    //so we initialize it to 0
    if(typeof temp.grandTotal == 'undefined') temp.grandTotal = 0;

 

    //we can then accumulate the grand total for all orders
    temp.grandTotal = temp.grandTotal + totalExtendedPrice;
 

    temp.averagePrice = (totalPrice / data.length);
    temp.averageQuantity = (totalQuantity / data.length);
    temp.totalExtendedPrice = totalExtendedPrice;
    temp.itemCount = data.length;
    //it is CRITICAL that the pre-processor function return an array to be expanded
    //even though this function has not modified the data in the 'data' array,

    //it must still return the 'data' array
    return data;
}

 

Templates Can Reference Functions in Any Namespace and Can Take Arguments

Previously, when a template referenced a function, the function needed to be defined as a global function. Now, templates can reference functions an arbitrary namespaces.

Consider the following simple example:

Data:

 

var data = [
    {firstname: 'Fred', lastname: 'Smith'},
    {firstname: 'John', lastname: 'Jones'}
]
 

 

Javascript function definition:

(Notice that the function takes two arguments and is in the 'obj' namespace.)

var obj = {
    fullname: function(fn,ln) { return 'Hello <b>' + fn + ' ' + ln + '</b>'}
}
 

Template:

(Notice that the template calls the function in the 'obj' namespace and passes in argument values from the current row.)

var template = '{firstname} {lastname} Function call is output here: {@obj.fullname(firstname,lastname)}<br>'

 

The output HTML produced is:

Fred Smith Function call is output here: Hello Fred Smith
John Jones Function call is output here: Hello John Jones

 

Defining Custom Formatters

Templates can format data before it is output using the built-in format directives. For example, you can format a number so that it has $ and two decimal places by using the :number() format directive.

For example:

{price:number(\'$#,###.00\')}

 

However, you can also define your own custom format directives. This is done by adding functions to the A5.u.template.formats object.

Consider the following example:

 

Data:

var data = {

    company: [
        {firstname: 'Fred', lastname: 'Smith', phone: 7815551234},
        {firstname: 'John', lastname: 'Jones', phone: 2125551234},
        {firstname: 'Jane', lastname: 'Jones', phone: 4155551234},
        {firstname: 'Margo', lastname: 'Jones', phone: 4325551234}
    ]
}
 

Template:

var template = [
    '{company}',
    '{firstname:formatName(\'l\')} {lastname:formatName(\'u\')} {phone:phoneNumber}<br>',
    '{/company}'

].join('');
 

Notice the template uses custom formatters for the each of the fields. Both 'firstname' and 'lastname' use a custom formatter called 'formatName' and in one case an argument value of 'l' is passed in (to format the data as lower case) and in the second case, an argument value of 'u' is passed in (to format the data as upper case).

The 'phone' field uses a custom formatter called 'phoneNumber'. This formatter does not take any arguments.

To define these two custom formatters, the following Javascript is used to add the format functions to the A5.u.template.formats object:

 

A5.u.template.formats.formatName = function(value,flag) {
    if(flag == 'u') return value.toUpperCase();
    else if(flag == 'l') return value.toLowerCase();
    else return value;
}

 

 

A5.u.template.formats.phoneNumber = function(value) {
    return value.toFormat('=(###)-###-#####');
}

 

Notice that the custom format functions all get passed 'value' - the value to be formatted.


Arguments Passed to Template Functions

If a template function does not explicitly specify arguments, the implicit arguments passed to the function now include the special 'temp' and 'root' variables.

For example, consider the following template snippet:

{@myCustomFunction}


This template function does not specify any arguments. Therefore the 'implicit' arguments for the function called are:

Previously, only 'data' and 'context' were passed to the function.

Where context is a string with the name of the variable that the function was being called in the context of. For example, in a {*header} or {*footer} directive for an array called 'company' the 'context' would be 'company'. Hhowever in an individual item in the company array, the context would be blank (as the context is implicit).

 

 

UX Component - List Control - Dynamic Images - Client-Side - The List control now allows you to define client-side Dynamic Image fields.

Previously, Dynamic Images were computed on the server. This meant that if the List was populated dynamically using Javascript code, the Dynamic Images would not be computed.

The Dynamic Image builder now allows you to specify the type of Dynamic Image.

 

If you choose the 'Client-side' option, then you must enter the condition expressions using Javascript. Keep in mind that Javascript is case-sensitive, you must use double equals (i.e. ==) and not a single equals for equality tests, and that strings must be single quoted. Also, when referring to a field in the current row, the field name is prefixed with data. .

The major benefit of client-side dynamic images is that if the data in a List row is edited, the Dynamic Image is immediately recomputed.

Watch Video - Part 1
Watch Video - Part 2
Download Components

 

 

UX and Grid Components - Javascript - Trapping Syntax Errors - When you save a component, Javascript function declarations are checked for syntax errors. Also when you edit the Javascript for an event handler, the syntax is checked for syntax errors. Previously this functionality was available, but was turned off by default. Now, it is turned on by default because a more robust method for checking Javascript syntax is used. (Based on the Node.JS 'Grasp' module).

If you want to disable Javascript syntax checking, go to View, Settings, Preferences, Javascript.

 

 

OLE Automation - Named Parameters - You can now use named parameters in an OLE automation call. The technique for doing this involves defining a dot variable with the parameters, then passing in the dot variable to the OLE method.

Previously, if you want to specify a value for an optional parameter you had to supply values for all of the optional parameters preceding the one you wanted to define. This could be very tedious.

For example, consider the function prototype for the Microsoft Word .open() method.

 

.Open(FileName, [ConfirmConversions], [ReadOnly], [AddToRecentFiles], [PasswordDocument],
 [PasswordTemplate], [Revert], [WritePasswordDocument], [WritePasswordTemplate], [Format],
 [Encoding], [Visible], [OpenAndRepair], [DocumentDirection], [NoEncodingDialog],
 [XMLTransform])
 

As this prototype shows, only the first argument (FileName) is required. All other arguments are optional. If you wanted to supply a value for (say) the 'ReadOnly' argument, you would need to specify a value for the 'ConfirmConversions' property as well.

Now, you can define a dot variable and define property values for just the arguments you want to set.

For example:

 
Dim wrdApp As P 'Word.Application
Dim wrdDoc As P 'Word.Document
wrdapp = ole.create("word.application")
 

'define a .dot variable and define the arguments you care about

dim args as p
dim args.FileName as c = "e:\files\hello.docx"
dim args.ReadOnly as l = .t.

 

'pass in the .dot variable to the OLE .open() metehod
wrdDoc = wrdapp.Documents.Open(args)
 

 

OLE Automation - Bubble-help for OLE Methods - The Xbasic editor and Interactive window now show the argument list for OLE methods. This is especially useful when you want to use named parameters and pass in a dot variable to the method because it lets you see the argument names, which you will use in the dot variable.

 

 

 

Interactive Window - Shell Commands - You can now execute shell commands directly from the Interactive window. Examples of the different use cases for this feature include:

Watch Video - Part 1
Watch Video - Part 2

 

Any command with a $ prefix that you enter in the Interactive window is considered to be a shell command. For example, type the following in the Interactive window:

$dir c:\windows

 

For detailed information on the Interactive window shell commands click here.

 

 

 

Action Javascript - Open .a5w Page Action - Page URL - If the page URL is specified by a placeholder that references fields in the current component, or uses placeholders in the URL, you can now specify that the value in individual placeholders should not be URL encoded by entering the placeholder name as:

{nourlencode:placeholderName}

For example:

{nourlencode:field1}

By default all placeholder values are URL encoded when they are replaced in the URL.

 

UX Component - Edit-Combo Control - Specifying Different 'Stored' and 'Display' Values - Dropdownbox controls allow you to specify that the stored value is different from the display value. For example, the control might display a 'ProductName' but the stored value in the control might be the 'ProductId'.

Edit-combo box controls can now also be configured to store a different value than their display value, just like a Dropdownbox control.

NOTE: If you configure an Edit-combo to have a different stored value from its display value, then you must check the option to only allow the user to select values in the choice list. The user cannot type arbitrary values into the control.

 

The benefit of using an Edit-combo control over a Dropdownbox control is that you can display multiple columns of data in the choice list and you can dynamically populate and filter the choices in the list with an Ajax callback every time the control is opened.

Watch Video

 

jQuery - Make Safe for Alpha Anywhere - a5_make_jQuery_safe() Function - Many jQuery Javascript files are written using the $ object as a proxy for the jQuery object. This makes it impossible to use these files in AlphaAnywhere without first editing the files and changing the $ object to the jQuery object. This can be a tedious process because a simple search and replace will not work as that would replace the $ string literal.

The a5_make_jQuery_safe() function converts all references to the $ object to 'jQuery' while leaving $ in variables names and strings unchanged.

NOTE: This function is built on top of the Node.JS GRASP module.

Syntax:

L flag =a5_make_jquery_safe(c filename [, flagCreateBackup = .t. ])

 

If fileCreateBackup is .t. a file with the extension of .old is created with the original text in the file.

 

 

HTML Reports - No Records in Report - If an HTML report has no records in it, it previously displayed a blank page. Now a 'No records in report' message is shown.

UX Component - A5.u.element.setContent() Function - Normally, you can set the content of an element in a component by simply getting a pointer to the element and then setting the element's .innerHTML property. However, if the element whose content you are setting has been configured to allow drag scrolling, setting the .innerHTML directly will destroy the drag scroll settings and the new content will no longer be scrollable.

The solution to this problem is to use the A5.u.element.setContent() function to set the element's content.

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

 

Syntax

A5.u.element.setContent(element,html [, options])

 

Where:

Example:

//get a pointer to the 'CONTAINER_1' container

var ele = {dialog.object}.getPointer('CONTAINER_1');
var string = 'define some long string of html here';
string = string + '<span id="span1">end of string</span>';
var settings = {animation: {allow: true}};

var settings: {
    fireEvent: false, //fire the scroll event
    mode: 'into-view', //mode can be 'into-view', 'top', 'bottom'
    axis: 'both', //which axes do you want to scroll on
    offset: {x: 0, y: 0}, //offset from the element that you are scrolling to
    animation: {allow: true, duration: 300} //animation
}
//scroll the element 'span1' into view
var obj = {element: 'span1', settings: settings};
A5.u.element.setContent(ele,string,obj);
 

//in this next example, instead of scrolling an element into view,

//we scroll to position 0,0 in the new content

//get a pointer to the 'CONTAINER_1' container

var ele = {dialog.object}.getPointer('CONTAINER_1');
var string = 'define some long string of html here';
string = string + '<span id="span1">end of string</span>';
var settings = {}
var obj = {x: 0, y:0, settings: settings};
A5.u.element.setContent(ele,string,obj);
 

 

 

Temp File Folder - Temporary Files - Code has been added to more aggressively clean up any temporary files that Alpha Anywhere created in the temp file folder. To turn on this feature for the development version go to the View/Settings/Preferences menu and set the value for the 'TEMP files' property.

To specify the setting in the Application Server (or the Development Server), go to the 'Advanced' tab in the server control panel.

 

 

Reports - Layout Table Reports - Suppress Blank Rows - A new property has been added for each row in a Layout Table report that makes it easy to suppress the entire row in the report if all of the columns in that row are blank.

Watch Video

To set the property, click in the vertical ruler to the left of the row whose property you want to set.

Then, in the property sheet, set the 'Suppress Blank' property.

 

 

 

A row is considered to be blank if the expression that defines the contents for each column in the row is a NULL value (i.e. equals the value returned by the null_value() function).

Note that:

 


 

 

 

UX Component - List Control - Show/Hide List Footer - .rowExpander() Method -  Each row in a tabular List layout can have an optional 'List Item Footer'. (Similar to a row expander in a Grid component). The initial state of the List Item Footer can be opened, or closed. The <listObject>.rowExpander() method can be used to show, hide, or toggle the show/hide state of the List Item Footer. The show/hide can optionally be done using animation.

Syntax:

<listObject>.rowExpander([rowNumber, [animationObject [,mode]]]);

 

Where:

 

Twitter - New functions have been added to make working with the Twitter API easier. Working with the Twitter API now requires that you use OAuth. The following two functions have been added:

 

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

 

twitter_getBearerToken() Function - Gets a 'bearer token' from Twitter.

Syntax:

c bearerToken = twitter_getBearerToken(C client_id, C client_secret)

 

The client_id and client_secret must be obtained from Twitter. Go to dev.twitter.com and create an application. Once you have created an application, you can get the keys.

The bearerToken that is returned will allow you to make Twitter API calls.

Typically you will only need to get the bearerToken once in your application. You can then save it in a session variable for use throughout your application.

The source code for the twitter_getBearerToken() function might be of interest to some developers, and is shown below:

 

 

function twitter_getBearerToken as c ( client_id as c , client_secret as c )
'DESCRIPTION:Uses OAuth 2.0 to get a bearer token from Twitter.
'LIMITATIONS:X
dim bl as b = client_id+":"+client_secret
dim cf_1 as extension::CurlFile
dim flag_1 as l
dim slist1[2] as c
slist1[1] = "Authorization: Basic "+base64encode(bl)
slist1[2] = "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
dim ce as extension::Curl
ce = extension::Curl.Init()
ce.setOpt("URL","https://api.twitter.com/oauth2/token?grant_type=client_credentials")
ce.setOpt("NOPROGRESS",1)
ce.setOpt("USERAGENT","curl/7.34.0")
ce.setOpt("HTTPHEADER",slist1)
ce.setOpt("MAXREDIRS",50)
ce.setOpt("CAINFO",a5.Get_Exe_Path()+"\caroot\ca-cert.pem")
ce.setOpt("CAPATH",a5.Get_Exe_Path()+"\caroot")
ce.setOpt("CUSTOMREQUEST","POST")
ce.setOpt("TCP_KEEPALIVE",1)
ce.SetOpt("FILE",cf_1)
flag_1 = ce.Exec()
if flag_1 then
dim result as p = json_parse(cf_1.GetContent())
twitter_getBearerToken = result.access_token
end if
ce.close()
end function

 

 

twitter_clientApiCall() Function - Allows you to call a REST API function in Twitter.

Syntax

C result = twitter_clientApiCall( c bearerToken, c request)

 

The bearerToken must have previously been obtained using the twitter_getBearerToken() function.

 

Example:

The following Interactive window session shows how you can get 10 tweets for 'London'

 

dim bt as c = getBearerToken("YourUserKeyHere","YourUserSecretHere")
dim url as c
url = "/search/tweets.json?q=london&count=10&lang=en&type=recent"
json = twitterClientApiCall(bt,url)
'make the JSON 'pretty'
json = json_reformat(json,.t.)
json = convert_utf8_to_acp(json)
showvar(json)
 

This example gets a user time line

 

 

dim bt as c = getBearerToken("YourUserKeyHere","YourUserSecretHere")
dim url as c
url = "/statuses/user_timeline.json?count=100&screen_name=twitterapi"
json = twitterClientApiCall(bt,url)
'make the JSON 'pretty'
json = json_reformat(json,.t.)
json = convert_utf8_to_acp(json)
showvar(json)
 

 

The source code for the twitter_clientApiCall() function might be of interest to some developers, and is shown below:

 

function twitter_clientApiCall as c ( bearerToken as c , request as c )
'DESCRIPTION:Make a REST call to the Twitter API using a bearerToken that was obtained using the twitter_getBearerToken() function
'LIMITATIONS:X
dim slist1[1] as c
slist1[1] = "Authorization: Bearer "+bearerToken
dim cf_1 as extension::CurlFile
ce = extension::Curl.Init()
ce.setOpt("URL","https://api.twitter.com/1.1"+request)
ce.setOpt("NOPROGRESS",1)
ce.setOpt("USERAGENT","curl/7.34.0")
ce.setOpt("HTTPHEADER",slist1)
ce.setOpt("MAXREDIRS",50)
ce.setOpt("CAINFO",a5.Get_Exe_Path()+"\caroot\ca-cert.pem")
ce.setOpt("CAPATH",a5.Get_Exe_Path()+"\caroot")
ce.setOpt("TCP_KEEPALIVE",1)
ce.SetOpt("FILE",cf_1)
flag_1 = ce.Exec()
if flag_1 then
twitter_clientApiCall = cf_1.GetContent()
end if
ce.close()
end function
 

 

UX and Grid Component - Tab/Accordion Control - onLeave and onBeforeLeave Events - Two new events have been added to the Tab and Accordion Control. The events can be defined at the control level or at the individual pane level.

Report Server - Logging - A new logging feature has been added for the Report Server. The report server log is turned on automatically when the logging is active on the server, which turns on the access and error logs. With these logs on, be sure to set the logging to rotate on size and daily to keep the files sizes under control and easier to manage.

The report Server log data will look like this

 



[Fri Jul 11 06:58:34 2014] StartRpt bb8f711ef8a8487f87a528b315827120 C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf


[Fri Jul 11 06:58:35 2014] Finished bb8f711ef8a8487f87a528b315827120 C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf
 

 

Value Description
[Fri Jul 11 06:58:34 2014] Date and time of the action
StartRpt The action, which will be "StartRpt", "Finished ", or "RptError" if no error was reported, but the report was not created.
bb8f711ef8a8487f87a528b315827120 A unique identifier that is assigned to each report at build time
C:\A5Webroot\AppServerDemoV12\NWEmployees.a5rpt The report definition requested
C:\Users\Jerry\AppData\Local\Temp\tmp983.pdf
 
The physical file created - often a temp file as shown here
 


 

By matching the identifier, the time to build a report can be calculated from the timestamp. This can help identify reports that are slow to build.

If a report has a start action, but no finished or error action, that would indicate the report server has not finished the report.

If the action is "RptError", this error may be noted in the Xbasic error log and a special mini-dump file created in the Xbasic log folder. This mini-dump file will have a name syntax similar to "A5ReportServer_20140710115412520.a5dmp" This file can be used by Alpha Software to evaluate the report properties of a failed report.

 

UX Component - List - Client-side Events - New events have been added.

 

 

Xbasic - MongoDB - NoSQL document databases are becoming popular for certain types of applications. A new MongoDB class has been added to Xbasic to make it easy to query, update and manage a MongoDB database from Xbasic.

Click here for information.

Technical Note: The Xbasic mongo class it built on top of the MongoDB node.js driver.

 

Xbasic - CouchDB - You can  now query, update and manage a CouchDB NoSQL database from Xbasic.

Click here for information.

 

 

Performance Improvements in Following Functions  and Methods - Major performance improvements in

Web Applications - Security Framework - Active Directory - The Security Framework for Web Applications now supports Active Directory. That means you can authenticate a user using an Active Directory server.

Click here for information.

 

UX, Grid, TabbedUI and PageLayout Components - Working Preview - Chrome - When you use Working Preview you now have the option of using either Internet Explorer, or Chrome. Previously, Working Preview automatically used Internet Explorer.

The benefits of using Chrome for Working Preview include:

 

Watch Video - Part 1
Watch Video - Part 2

 

 

The Working Preview window now has new hyperlinks at the bottom of the screen.

When Internet Explorer is being used, the menu looks like this:

 

Clicking on the Internet Explorer hyperlink will bring up a dialog that will allow you to change to Chrome. Your choice is stored as part of the component definition. You can choose to use Internet Explorer for some components and Chrome for others.

 

When Chrome is used for Working Preview, the menu has more options.

The 'Detach Working Preview Window' is particularly useful because it creates a separate, detached window for Working Preview. This window can be moved to a second monitor and be left open while you return to the Design pane to continue editing your component.

You can set the Detached Working Preview window to update immediately every time a property is changed.

NOTE: For very large components, setting the Detached Working Preview to automatically update is not recommended as the delay in updating the Working Preview window will make setting properties seem sluggish.

 

 

Debugging Javascript Using the Chrome Debugger

 

To use the Chrome Javascript debugger, you must insert the

debugger;

command into the Javascript that you want to debug.

You must also, click the 'Open Chrome Debugger' hyperlink before you execute the code you want to debug. This will open the Chrome Debugger in a background window.

You can then invoke the code that you want to debug. When the debugger; command is hit, the Javascript will pause and the Working Preview screen will show:

 

 

You can then click the 'Open Chrome Debugger' hyperlink again, and it will bring the Chrome Debugger window to the forefront:

 

 

 

 

UX Component - List Control - New Methods - New method have been added to the List control that fire when the data in the list are changed. The methods are:

 

The events fire when the .populate(), updateRow(), appendRows() and removeRows() methods are called.

If the 'before' events return false, the corresponding action does not occur.

 

 

UX Component - Mobile Simulator - Now includes iPhone5 option in dropdownbox to select simulator size.

UX Component - Action Javascript - Wait Message - Auto Close After Setting - You now have control over how long to wait before the wait message is closed. By default, the setting is 5000 milliseconds.

 

email_send_mandrill() function - Sender Name Alias - Support for specifying an alias for the sender name has been added. The dot variable that is passed into the email_send_mandrill() function can now have a .from_name property.

For example:

ms.from_name = "Sales at Alpha" 'friendly name - optional

 

Here is a complete example

'create a .dot variable to define the message

dim ms as p
ms.send_to = "john@acme.com:John Smith,sally@acme.com:Sally Jones"
ms.from_email = "sales@alpha.com"

ms.from_name = "Sales at Alpha" 'friendly name - optional

ms.subject = "Information You Requested"
ms.message_html = "Here is the <b>information</b> you requested."
dim pResult as p

pResult = email_send_mandrill("mysecretkey",ms)

 

UX Component - List Control - .scrollToClosestValue() Method - Scrolls to the closest record in the List.

Syntax:

<listObject}.scrollToClosestValue(value [, flagCaseInsensitive [, position [, animationObject]]])

 

Where

Example:

Scroll the List so that the first Customer with a Lastname starting with 'M' is shown at the top of the List

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

lObj.scrollToClosestValue('m',true,top,{allow: true, duration: 200})

 

 

UX Component - List Control - Tabular Layout - Sorting Columns - Custom Javascript - When a user clicks on a column heading in a List to sort the data on that column, you can specify if the sort should take place client-side or server-side (only appropriate if the List is based on a SQL or DBF data source). Now, a new option has been added to the list of choices. The 'Javascript' option allow you to specify your own Javascript code to execute.

 

UX Component - Repeating Sections - Set Active Row - setRepeatingSectionActiveLogicalRow() Method - A new method is now available for setting the active row in a Repeating Section.

{dialog.object}.setRepeatingSectionActiveLogicalRow(sectionName,logicalRowNumber)

 

The logical row number of a row in a Repeating Section and its physical row number are the same, unless rows have been deleted from the Repeating Section. When a row is deleted from a Repeating Section it is not really deleted, it is only hidden.

So, for example, assume that a Repeating Section had 5 rows to start with and then the first three rows were deleted. There would now be two visible rows, (logical row number 1 and 2), but the physical row numbers for these two rows would be 4 and 5. In order to set focus to the last visible row in the Repeating Section (logical row 2, but physical row 5) you can now use the new .setRepeatingSectionActiveLogicalRow() method.

This is more convenient than having to first call the ._repeatingSectionLogicalToPhysicalRow() to convert the logical row number to a physical row number, and then calling the .setRepeatingSectionActiveRow() method.

UX Component - List Control - .getVisible() Method - Returns an object with two properties 'start' and 'end' which contain the zero based row numbers of the rows in the List that are currently visible.

var lObj = {dialog.object}.getControl('list1');
var obj = lObj.getVisible();
alert(obj.start + ' to ' + obj.end);
 

 

UX Component - List Control - onNavigate Event - The onNavigate event fires when the List has been scrolled. The e object passed into the event handler has two properties:

UX Component - Hide/Show Controls - .setControlDisplay() Method -  A new method is exposed that can be used to show/hide controls. The method will hide/show the control and also its label (if the control has a label).

{dialog.object}.setControlDisplay(name, flag [, mode [, animatationJSON]])

 

The animJSON object has two properties:

 

NOTE: If you specify animation, you must load jQuery. To load jQuery, go to the Web Project Properties dialog and turn jQuery on.

Example:

{dialog.object}j.setControlDisplay('FRAME_1',false,'d',{type: 'fade',duration: 3000});

 

 

UX Component - Validation - Show/Hide Expressions - If a control has been hidden by a client-side show hide expression, the control is no longer validated.

 

 

AppLauncher Component - Browser Flags - A new option allows the query string that loads the target component to suppress the browser flags from showing in the query string. Instead, the browser flags are stored in a session variable called session.__browserFlags.

 

 

UX Component - List Control - .scrollToItem() method - This method now has new options that allow you to control where the target row will be in the List. Previously, the List was scrolled so that the target row became visible. But you could not control whether the target row was positioned at the top, or bottom of the List.

Now, you can pass in an optional object to the method with settings. For example:

 

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

listObj.scrollToItem(50,{mode: 'top' ,animation: {allow: true, duration: 200},offset: {x: 0,y: 0}});
 

 

Options for 'mode' are: top, bottom, in-view

The offset settings control the number of pixels at the top or bottom of the list between the List edge and the scrolled to row.

 

UX Component - ButtonList Control - Static JSON - A new option has been added to populate a ButtonList control. The Static JSON option allows you to enter some static data in JSON format as the data source for the ButtonList.

UX Component - List Control - Get List Row Number from Element Method  - A new method of the List control allows you to get the List row number (zero based) from an element in the row.

For example, assume that you have a List with a freeform layout and a button in the freeform Layout with this code:

 

<button onclick="getRow(this);">What Row Am I On</button>

 

The getRow() function would be defined as:

 

function getRow(ele) {

    //get a pointer to the list - assume list is called 'LIST1'

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

 

    //get the row index by calling the .indexFromElement() method.

    //'ele' is a pointer to the button in the List row.

    var index = lObj.indexFromElement(ele);

}

 

 

 

PhoneGap Builder - Now uses a token based authentication feature so that once you have successfully logged into the PhoneGap build service, all further interaction with the PhoneGap build service is done using the token (until the token expires - currently set for 24 hours after login). The benefit of this approach is that interacting with the PhoneGap build service is faster as we no longer need to authenticate each time.

UX Component - List Control - Javascript Function Datasource - If a List control specifies a Javascript function as its data source, when the .refreshListMethod() is called an Ajax callback is no longer fired (as it was meaningless). Instead, the function that populates the list is called and the List is repopulated with the function results.

UX and Grid Component - Edit-combo and Auto-suggest Control - The height property was not being honored if it was set to a value that included the 'max' keyword.

 

UX Component - Testing if the Alpha Anywhere Server is Available - The UX component now supports a new method, .serverIsAvailable() that tests if the Alpha Anywhere server is available. This is a more comprehensive test than simply testing if an Internet connection is available.

 

NOTE: Contrast this method with the UX component's ._getOnlineStatus() method. This method merely tests if there is an internet connection. It does not make an ajax callback to the Alpha Anywhere server. Is merely uses the HTML5 navigator.online property. The .serverIsAvailable() method, on the other hand, does a lightweight callback to the Alpha Anywhere server to test if the server is available.

 

The syntax for the .serverIsAvailable() method is:

{dialog.object}.serverIsAvailable( [timeOut [, successFunction [, errorFunction]]);

 

If you don't specify a timeOut, the default value is 300 milliseconds.

The 'successFunction' parameter allows you to pass in an Javascript function to be called once it is determined that the Alpha Anywhere server is available.

The 'errorFunction' parameter is called if the server is not available.

The function will set these variables in the global A5 Javascript object:

_serverAvailable - true/false

_serverCheckTime - the time the server availability was last checked.

 

Example:

Execute the 'refreshList' action is the server is available.

function success() {

    {dialog.object}.playAction('refreshList');

}

 

{dialog.object}.serverIsAvailable(300,success);

 

 

Grid and UX Component - Search - QBE Syntax - Combining Multiple Wildcard Searches with AND -  If your search style is set to 'Exact match' and you enter search criteria that use wildcards, and you have QBE syntax turned on, then you can enter search criteria in the following form:

%string1%,%string2%

This will be interpreted as a search for any record that contains either string1 or string2 in the field.

However, you may want to find records that contain string1 AND string2. You can now do this using the && operator in your search definition, rather than the comma.

 

Application Server - The Application Server now uses an updated default SSL cipher list to enhance the security of SSL-enabled servers. The new cipher list is based on https://wiki.mozilla.org/Security/Server_Side_TLS


 

Bugs

UX Component - List Control - Frame - Modern - Show/Hide - If a List control was in a Frame container and the frame was defined as a modern frame that could be shown/hidden and if the initial state of the frame was hidden, the List controls in the Frame did not render properly when the frame was shown.

UX and Grid Components - Pop-up Modal Windows - Resizing - In some cases, when resizing a modal pop-up window, the window content would not redisplay properly after you stopped resizing the window.

Application Server - SSL - Test Certificates - Firefox - Certificate extensions are no longer generated into self-signed certificates when using the Application or Development Server Settings dialog to generate a self-signed certificate or calling directly from INET::SSLContext::CreateTestCertificate(). Version 31 of Firefox no longer accepts deprecated certificate extensions and this change corrects that problem.

IMPORTANT: You will have to regenerate your self-signed certificate.

UX Component - Map Control - onZoom Event - This event was not firing.

UX and Grid Component - Working Preview - Chrome - Memory Leaks - When using Chrome for Working Preview while building UX and Grids components there is a small memory leak that forces you to have to restart Alpha Anywhere occasionally. A number of these memory leaks have been fixed.

NOTE: This comment does NOT apply to the Application Server - it is only for the Development version.

UX Component - Logical Checkbox - Client-side Show/Hide - If you have defined a text label for the control, the text label was not being hidden when the control itself was hidden.

HTML Layout Reports - A number of minor bugs have been fixed. For example, scrolling HTML Layout reports in a mobile application when the report was shown in a pop-up window did not work the second time the report was opened.

Grid Component - File Upload - User Defined Action - Working Preview - Using this action in Working Preview had previously been supported, but got broken in a recent update. This is now working again.

UX Component - Tab Controls - Embedded Components - Server-side Show/Hide or Security - If a server-side show/hide expression or security group setting removed an embedded component from a tab pane at run-time, a Javascript error would occur.

UX Component - Panel Header/Footer - Container Height - The container height property was honored for a Panel Header or Footer.

Grid Component - Edit Row on Demand - afterRowSwitchFromEditable Client-side event - This event was not firing if the row you were editing was implicitly set to not-editable mode because the user clicked to edit another row and the Grid was set to edit one row at a time.

UX and Grid Component - Javascript Actions - Fixes a recently introduced bug where a Javascript Action that used Action Javascript to open a child component in a div on the parent component failed.

Report Editor - Layout Table Reports - Static HTML Cells - Now honor the font and alignment properties applied at the cell level.

Report Editor - Layout Table Reports - Row size to fit - Now works when row contains static HTML content.

UX Component - List Control - Client Side Summary - Client Side Filtering - Fixed an issue where the client-side summary values were not recalculated if a client-side filter was applied to the List.

UX Component - List Control - Client Side Summary - Fixed an issue where the items in the csSummary object were not upper case, as documented. Also, the count summary value was only being computed if the data in the field was numeric.

UX Component - Lookup Columns - Columnar Layout -  If there was no matching row in the lookup List, the data in the List would be misaligned in the List columns.

Grid and UX Component - Lookup Grids - Dynamic Filter - If a Lookup Grid had a dynamic filter, the filter was being applied as a 'user filter' rather than as a 'base filter'. This meant that if the user clicked the 'Clear Search' button on the Lookup Grid, the dynamic filter was removed.

Grid and UX Component - Javascript Actions - Fixed an issue that could have resulted in the .playAction() method invoking the wrong action.

UX Component - Slider - Date Values - Two Value Mode - When a two value slider was configured to show date values, the dates were off by when when you set the value on the date start/end.

Reports - Named Datasources - Fixed a recently introduced issue with reports that use named data sources (not to be confused with named connection strings which do not have any issues).

UX and Grid Components - Client-side Expressions - Date Fields - Client side expressions (for example, show/hide, enable and calculated fields) that are based on controls whose data type is set to 'Date' or 'Time' now treat the controls as true Javascript date objected.

For example, say you had a UX with two input controls (called say 'DATE1' and 'DATE2') and a button. Say you defined as show/hide expression for the button as follows:

DATE1 > DATE2

Assume that the client side date format was set to MM/dd/yyyy and that the values in the two controls were '04/20/2000' and '02/01/2000'.

Previously, this expression was evaluated as as string expression. So the string '04/20/2000' was compared to the string '02/01/2000'.

This might have led to the correct result in some circumstances, but would not have been correct in other circumstances. For example, say that the client side date format was set to dd/MM/yyyy. Now the two values for the date controls would be '20/04/2000' and '01/02/2000' and comparing these two values as strings would lead to a different result.

Now, the input controls are converted to real Javascript data objects (in other words, the date string values are automatically parsed using the setting for the client side date format) and the client-side expression is evaluated using true date values.

Previously, some uses might have implemented their own solution to this problem by defining a custom Javascript function to use in the show/hide expression. For example, the show/hide expression might have been specified as:

compareDates(DATE1,DATE2)

 

And the compareDates function would have been defined as:

 

function compareDates(d1,d2) {
    var _d1 = new Date();
    var _d2 = new Date();
    _d1.fromFormat(d1,'MM/dd/yyyy');
    _d2.fromFormat(d2,'MM/dd/yyyy');
    if(_d1 > _d2) return true;
    else return false;
}

 

If you had previously implemented this pattern, you will now get an error because the inputs to the compareDates() function (d1 and d2) are not date objects and not strings.

 

 

UX Component - List Control - Cascading Lists - DBF Tables - Allow Null Selection - If you had defined cascading List controls (i.e. a child List whose data depends on the selection in its parent List) and the List data source was .dbf tables, and the parent List was set to not allow a null selection, then when the UX initially rendered, the child List was not populated, as it should have been. The child List was only populated after the user clicked on a row in the parent List.

 

 

Tips

Edit-Combo, Auto-Suggest and List Controls - Web Applications - Touch Enabled Computers - Windows 8.* - If you are running a web application on a touch enabled computer under Windows 8.*, Edit-combo, Auto-suggest and List controls will not display a vertical scroll bar because the assumption is that the user will use touch gestures on the list to scroll the data.

This assumption is valid for a mobile application that does not support mouse interaction, but in a web application on a machine that does support mouse interaction, you would want to see a vertical scroll bar.

You can turn off drag scrolling (and thus cause the vertical scroll bar to appear), by executing the following Javascript code:

A5.u.drag.useDragScrolling = 'never';

 

If your application is running in a Tabbed UI, a good place to inject this code is in the Tabbed UI's 'Javascript to run on startup' property.

 

 

In the case of a Grid, you can use the onGridRenderComplete client-side event.

 

UX Component - Define Custom Watch Events - The client-side 'calculated fields', 'enable expression' and 'show/hide' expressions all generate watch expressions that automatically fire when the 'watched' variables change.

You can completely bypass these properties and instead define your own watch expressions.

For example, the following code can be placed on the client-side beforePrepare event to define a custom watch event that updates the value in 'TEXTBOX1' whenever the value in 'TEXTBOX2' changes.

 

 

{Dialog.Object}.dialogWatches['MY_WATCH_EVENT'] = {
    watch: ['TEXTBOX2'],
    variables: [],
    updateColumn: 'TEXTBOX1',
    onChange: function(data) {
        var dialog = {};
        var summary = {};
        {Dialog.Object}._getDialogVariables(dialog,summary,data);
        var txt2 = {dialog.object}.getValue('textbox2');
        {Dialog.Object}.setValue('TEXTBOX1',

            {dialog.object}._functions.myFunc2(txt2) );
    }
}
 

Using CSS Icon Images and Bitmap Images - A5.u.icon.html() Function - The Alpha Anywhere Javascript library contains a useful utility function that makes working with CSS Icon images and regular bitmap images easier.

The issue is somewhat complicated because the HTML markup to display a bitmap image uses the <img> tag, whereas the HTML markup for a CSS Icon image uses a <i> tag with special class names.

The A5.u.icon.html() function takes the name of the image you want to display and generates the appropriate HTML markup. It is also able to interpret the special syntax Alpha Anywhere uses to assign an in-line style to CSS Icons.

For example:

var icon1 = A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: blue;}');

will return the following HTML markup:

<i class="fa fa-align-center fa-2x " style=";color: blue;"></i>

and:

var icon2 = A5.u.icon.html('images/$$application.chrome.png.a5image');

will return this HTML markup:

<img src="images/$$application.chrome.png.a5image" />

 

UX Component - List Control - Using the Client-side Computed Columns Feature to Display Dynamic Images in a List - The Computed Columns property allows you to define computed (virtual) columns to display in a List. The computed columns can display dynamic images (i.e. images that are based on data in the current row). For example, you could define the following Computed Column:

 

data.DYNAMICIMAGE = function(data,index) {
    if(data.State == 'MA') {
        return A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: #f6b5b5;}');
    }
    else if(data.State == 'CA') {
        return A5.u.icon.html('cssIcon=fa fa-align-center fa-2x {color: blue;}');
    }
    else if(data.State == 'NY') {
        return A5.u.icon.html('images/$$application.chrome.png.a5image');
    }
    else return 'Not Defined';
    }(data,index);

 

 

 

UX and Grid Component - Sending E-mail From the Client Using Mandrill - Alpha Anywhere has well documented methods for sending email from a web component. These method are all server-side method. An Ajax callback is made to the server and the e-mail is sent from the server. However, it is possible to send an e-mail directly from the client without involving the Alpha Anywhere server at all using the Mandrill Mail service.

The technique discussed here uses the XMLHttpRequest object to make a REST call to Mandrill.

 

function sendMailData() {
    //data for the message
    var url = "https://mandrillapp.com/api/1.0/messages/send.json"
    var json = {
    "key": "Your Mandrill key here",
    "message": {
    "to": [
        {
            "email": "test@gmail.com"
        }
    ],
    "from_email": "customerservice@gmail.com.com",
    "subject": "Message Subject",
    "html": "Message text here",
    "text": "Text form of message",
    "preserve_recipients": false
    },
    "asynch": false,
    "ip_pool": null,
    "send_at": null
    }
    var obj = {};
    obj.url = url;
    obj.json = json;
    return obj;
}

function sendMail() {
    var obj = sendMailData();
    var _url = obj.url
    var params = JSON.stringify(obj.json);
    var _xhr = new XMLHttpRequest();
    _xhr.open('POST',_url,true);
    _xhr.timeout = 5000;
    _xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    _xhr.setRequestHeader("Connection", "close");

    _xhr.ontimeout = function(e) {

        alert('error - timeout');
    }

    _xhr.onload = function(e) {

        if(this.status == 200) {

            alert('sent');

        } else {

            alert('failed')

        }
    }
    _xhr.send(params);

}
 

UX Component - Drag Scrollable Elements (including Lists) - Dynamically Turning Scrolling On/Off - You can dynamically turn scrolling on/off on certain elements, including List controls.

The basic steps are:

1. Get a pointer to the element

2. Call this code:

A5.u.drag.setDisabled(element,dragType,value)

 

 

For example:

//get a pointer to the List obj

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

//get a pointer to the scrollable part of the List

var ele = $(lObj.contId+ '.CONTENTWRAPPER');

//disable scrolling

A5.u.drag.setDisabled(ele,'scroll',true);

//now enable scrolling

A5.u.drag.setDisabled(ele,'scroll',false);

 

The dragType parameter can be 'scroll' or 'custom'. 'Custom' is used for 'drag' actions that are not 'scroll' actions. For example, a Carousel uses a custom drag, not a 'scrolling' drag.

 

 

Basic Authentication - How to Create an .A5W Page that Requires Basic Authentication - Basic Authentication is a simple HTTP form of authentication.

As defined in Wikipedia:

HTTP Basic authentication (BA) implementation is the simplest technique for enforcing access controls to web resources because it doesn't require cookies, session identifier and login pages. Rather, HTTP Basic authentication uses static, standard HTTP headers which means that no handshakes have to be done in anticipation.

If you create simple web services in Alpha Anywhere, you might want to use basic authentication on the .a5w page that implements your web service.

In the example page below, basic authentication is used. In this trivial example, the only user Id/password combination that is valid is Alpha/Anywhere. However, the example could easily be extended to do a database lookup to authenticate the user.

When this page is called (by some other program that is trying to consume the web service implemented by this page), it is assumed that the headers will have been set to supply the user id and password.

If you try to call this page from a browser, the browser will prompt for a user id and password

 

<%a5
if ("Authorization: Basic " $ Request.Headers)

    'extract the 'Authorization' from the request header
    dim EncodedUserAndPass as c = filter_string(Request.Headers,"Authorization: Basic ", crlf())
    EncodedUserAndPass = word(EncodedUserAndPass,2,": Basic")
    EncodedUserAndPass = alltrim(EncodedUserAndPass)
 

    'the authorization is base64 encoded. decode it.

    dim DecodedUserAndPass as b = base64decode(EncodedUserAndPass)
 

    'extract the username and password

    dim Username as c = word(DecodedUserAndPass, 1,":")
    dim Password as c = word(DecodedUserAndPass, 2, ":")
 

   

    'here is where you could do a database lookup to authorize the user

    if (Username = "Alpha" .and. Password = "Anywhere")
        ? "Authorized as " + Username

        'this is where you would implement the web service.

        'at this point, the user has been authorized.

        'for example, you might respond with some JSON data

        'e.g. data = "{name: 'alpha', city: 'Boston'}"

        '?data

       
    else
        ?"Bad username or password"

        'if you want to present the user with another change to log in, uncomment this

        'Response.StatusCode = "401"
        'Response.StatusDescription = "Not Authorized"
        'Response.Headers.Add("WWW-Authenticate", "Basic")
    end if
else
    Response.StatusCode = "401"
    Response.StatusDescription = "Not Authorized"
    Response.Headers.Add("WWW-Authenticate", "Basic")
end if
%>

 

 

UX and Grid Component - Edit-Combo - Dynamically Repopulate Choices - When you define an Edit-Combo control, the builder allows you to specify that the choices shown in the edit-combo should be computed at render time, or dynamically, by making an Ajax callback every time you open the edit-combo.

If you choose the option to populate the edit combo at render time, you might still want to programmatically change the choices in the edit combo.

Here is the Javascript showing how it can be done:

 

//get a pointer to the edit-combo for 'TEXTBOX1'

obj = DLG1_DlgObj.fieldHelpers['TEXTBOX1'];

//define the new date for the edit-combo
var _d = ['Red','Green','Blue','Orange'];

//call the .setData() method to repopulate the edit-combo
obj.setData(_d);
 

If you want to generate the new choices for the edit-combo by making an Ajax callback to the server, here is how the Xbasic function that handles the callback might be written:

 

 

This example is where the edit-combo shows a single column of data.

function xb_refreshData as c (e as p)
    dim cn as sql::Connection

    cn.open("::Name::northwind")

    sql = "select customerid from customers where country = 'uk'"

    cn.Execute(sql)

    rs = cn.ResultSet

    dim txt as c

    txt = rs.ToString()

    dim data as c

    data = js_list_to_array(txt)

    dim js as c

    js = "var obj = {dialog.object}.fieldHelpers['TEXTBOX1']; "

    js = js + "var _d = " + data + ";"

    js = js + "obj.setData(_d);"

    xb_refreshData = js

end function

 

 

 

This example is where the edit-combo shows a multiple columns of data.

 

 

function xb_refreshData as c (e as p)
    dim cn as sql::Connection

    cn.open("::Name::northwind")

    'note that we alias the columns in the SQL statement with field names

    'that are capitalized. this is because Javascript is case-sensitive and the

    'property names in the JSON data that is used to populate the edit-combo

    'are all capitalized. the column aliases will be uses for the property names

    'when the .ToJSONObjectSyntax() method is called.

    sql = "select customerid as [CUSTOMERID], contactname as [CONTACTNAME] from customers where country =  'uk'"

    cn.Execute(sql)

    rs = cn.ResultSet

    dim txt as c

    txt = rs.ToJSONObjectSyntax()

    dim data as c

    data = "[" + stritran(alltrim(txt),crlf(),"," + crlf()) + "]"

    dim js as c

    js = "var obj = {dialog.object}.fieldHelpers['TEXTBOX1']; "

    js = js + "var _d = " + data + ";"

    js = js + "obj.setData(_d);"

    xb_refreshData = js

end function


 

 

 

 

 

UX and Grid Controls - Button Icons and Text - Setting Dynamically - In the case of 'advanced' buttons (all buttons in a UX are, by default 'advanced' buttons and 'Action Buttons' in a Grid are 'advanced' buttons), you can dynamically set the button icon, or button text by setting properties in the underlying button object, then refreshing the button object.

For example:

var bc = {dialog.object}.getControl('MYBUTTON1');
bc.icon = 'cssIcon=FontAwsomeIconHere'; 

// optionally you can also set 'hoverIcon', 'pressedIcon', and 'disabledIcon'
bc.refresh();



 

 

UX Component - List Control - Cascading Lists - Delay Render - The UX component makes it very easy to create cascading Lists. For example, say you have 3 Lists:

You can easily configure the orders List to specify that the customer List is its parent List and the orderDetails List to specify that the orders List is its parent.

If you specify that a List has a parent, then when you click on a row in the parent List, ajax callbacks are automatically made to refresh the child Lists.

Now, assume that each List is placed in its own PanelCard and the PanelCards are wrapped in a PanelNavigtor. Further assume that for each List you have checked the 'Delay render till visible' property.

The desired behavior is that when the UX is initially rendered, ONLY the customer List is rendered. Then when the user clicks on a row in the customer List, a single ajax callback is made to populate the order List and the PanelCard that contains the orders List gets focus.

Next, when the user clicks on a row in the orders list, again a single ajax callback is made to populate the orderDetails list and the PanelCard containing OrderDetails gets focus.

However, if you set up your UX as described above, when you click on a row in the customer List, you will notice that there are two ajax callbacks and that the orders List is refreshed twice - not once as desired. The first ajax callback occurs because the customer List automatically refreshes all of its child Lists when the user selects a row in the List. The second callback occurs because the PanelCard that contains the orders List gets focus and the orders List was configured to render when it becomes visible.

To solve this problem here is how the setup of the UX component must be changed.

So, for example, in the onSelect event for List1 (the customer List), the following code is executed:


var l = {dialog.object}.getControl('list2');
l._hasBeenRendered = false;
var l = {dialog.object}.getControl('list3');
l._hasBeenRendered = false;
{dialog.object}.panelSetActive('PANELCARD_2');

 

This event sets the ._hasBeenRendered property for list2 and list3 to false, and then gives focus to PANELCARD_2. When PANELCARD_2 gets focus, list2 is rendered (an ajax callback is made). This is the only callback that is made. Because the orders List (list2) no longer has its 'Has Parent List' property set, no callback triggered by simply clicking on a row in the customer list.

 

Similarly, the onSelect event for List2 (the orders List), the following code is executed:

var l = {dialog.object}.getControl('list3');
l._hasBeenRendered = false;
{dialog.object}.panelSetActive('PANELCARD_3');

 

 

 

The sample component which uses Northwind demonstrates the concepts discussed in this topic.

 

 

UX Component - List Control - Sort Icon Position - By default, when you sort the data in a List column, the sort icon shows to the right of the Column heading. If you are working with a RTL language, such as Arabic or Hebrew, you might want the sort icon on the left of the column heading (as shown below):

 

Download Component

 

 

This is easily done by customizing the component style. You can either make a change to the style sheet (which will affect all of your components). Or you can make a local change to affect just the UX that you are designing.

To define the changes so that they are local to the current component, edit the 'Local sub-theme definition' as shown below:

 

 

Edit the Javascript as shown below.

You can start by clicking the 'Show style.js file for current style' hyperlink. The search for 'listbox'. Copy the JSON to the clipboard and paste into the editor. You will need to wrap the pasted text in opening and closing curly brackets as shown in the image. The make the edit shown in yellow highlight below.

 

You will also need to make this change to the CSS:

 

Of course, if you are not using iOS7, but some other style, you will need to use the appropriate style names.

 

 

 

 

UX Component - Tree Control - How to Save and Restore the Open/Close State of Tree Nodes - Consider a UX that has a tree control with multiple levels of nested branches. Assume that the user has carefully navigated in the tree, opening some branches, while leaving others closed. The user would then like to save the 'state' of the tree so that at a future time, they can easily restore the state of the tree to its current state.

This is easily done with some simple Javascript that captures and restores the state. Below are two function. The first captures the tree state and stores it in a variable in the Dialog object. The second restores the tree state.

 

function getstate() {

    //get a pointer to the tree control
    var t = {dialog.object}.getControl('tree1');

   

    //get the tree data and stringify it.
    var js = JSON.stringify(t.data);

 

    //store in a variable in a dialog object
    {dialog.object}.treeData = js;

}

function setstate() {
 

    //get a pointer to the tree
    var t = {dialog.object}.getControl('tree1');
 

    //get the stored data. parse it into an object

    var d = JSON.parse({dialog.object}.treeData);
 

    //reopulate the tree
    t.populate(d);

}

 

 

UX Component - Map Control - List Control - Add Markers to Map Using Data From List - Assume you have a List control with multiple records. Each record has a lat/lng value. You would like to add a marker to the map for each row in the List. You can certainly do this by using a built-in action in Action Javascript to 'Add multiple markers to a map'. However, the Action Javascript action involves making an Ajax callback.

Since the List already has lat/lng data for all of the markers you want to add to the map, it would be nice to be able to add the markers to the map without having to do an Ajax callback.

 

Here is a working example.

 

To do this, add a button to the List that calls the addMarkers() function.

Here is the definition of the addMarkers() function

 

function addMarkers()  { 

    //get a pointer to the list
    var lObj = {dialog.object}.getControl('list');

    //get the list data
    var _d = lObj._data;

 

    //get a pointer to the map control
    var m1Obj = {dialog.object}.getControl('map1');
    m1Obj.removeMarkerGroup('GROUP1');
    var _dr = '';

 

    //loop through all of the rows in the list

    //reading the 'name', 'city', 'state', 'latitude' and 'longitude'

    //columns in the list.


    for (var i = 0; i < _d.length; i++) { 
        _dr = _d[i];
        delete _s;
        _s = {};
        _s.group = 'GROUP1'
        _s.title = _dr.name ;
        _s.detail = {};
        _s.detail.has = true;
        _s.detail.data = _dr.city + ' - ' + _dr.state;
        m1Obj.addMarker('MARKER_' + i,[Number(_dr.latitude),Number(_dr.longitude)],_s);
    }
    m1Obj.viewMarkerGroups('GROUP1');;
}
 

 

 

UX Component - Tabular Lists - Showing and Hiding Lists - When a columnar List is shown after initially having been hidden, the List will not render correctly until is has been explicitly refreshed. Here is how you can refresh a columnar List so that it displays correctly after having been shown:

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

lObj.refresh();

 

 

NOTE: This comment does not apply to free-form Lists. Free-form Lists do not need to be explicitly refreshed.

PhoneGap Application - iOS StatusBar - In iOS, it is common to have the status bar at the top of the screen (with time, Wifi, and battery information) display as an overlay of the app. For many designs this can be a problem. You might rather have the "old" style of having a separate status bar above the active area of the screen. You might also want to specify the color of the background of that bar (for example, to match or complement the top of your app) and text. PhoneGap gives you an optional "Status Bar" 3rd Party plug-in to customize the status bar on iOS.

See example code in next topic.


 

Android Back Button - In Android, users often expect the device's "Back" button to control the app. By default, in PhoneGap, this will just exit the app and go back to the previous app. If you have popup windows, or detail views, the users will expect (and their fingers will be trained) to dismiss pop-ups or go back up the view list. See "Navigation with Back and Up" on the Android Developers web site: http://developer.android.com/design/patterns/navigation.html


Here is some code that can be placed in your app (such as in the Javascript functions or the onRenderComplete Client-Side Event:
 

// PhoneGap start up and initialization

document.addEventListener('deviceready', function() { // PhoneGap started
    var platform = device.platform;
    switch (platform) {
        case "Android":

            // back    button support
            document.addEventListener('backbutton', handleBackButton, false);
            break;
        case "iOS":
            if (typeof StatusBar === 'undefined') break;

            // configure statusbar in iOS 7+
            StatusBar.overlaysWebView(false);

            // Light statusbar text color. Use StatusBar.styleDefault() for dark text.
            StatusBar.styleLightContent();
            StatusBar.backgroundColorByHexString("#3355AA"); // Hex RGB value, similar to CSS
            break;
    }

    }

);


function handleBackButton(e) { // Android back button event handler
    // Go through UI items in priority order to do "back" operation
    var winobj = {dialog.Object}.getWindow('INTROWINDOW'); // Is this window popped up?
    if (!winobj.hidden) {
        winobj.hide(); // no - hide and finish
    return;
    }

    winobj = {dialog.Object}.getWindow('SETTINGSPOPUP'); // another potential window
    if (!winobj.hidden) {
        winobj.hide();
        return;
    }

. . .

    var panel = {dialog.object}.panelGet('OVERALLLAYOUT'); // is a docked panel being shown?
    if (panel.state.dockPanelShown) {
        panel.hideDock(); // yes - hide it and finish
        return;
    }

    if (canGoBack()) { // do normal user-initiated "back" operation in app (like a browser)
        doBackForward(+1);
        return;
    }

    // nothing left - exit app
    e.preventDefault();
    navigator.app.exitApp();

}

 


Note that the "back" handling seems to work in Android 4.3, but may not work in earlier versions.

 

 

Xbasic Classes - Property Getter and Setter Functions - You can create special .get() and .set() functions to read and write property values in a class. For example, in the class below the 'foo' property of the class has a .get() and .set() function. These functions are automatically invoked when you try to set or get the value of the classes' .foo property.

 

 

define class mynamespace::mySampleClass
 

    dim _foo as c = "hello"
    function sampleMethod1 as v()
        ui_msg_box("sampleVar1",sampleVar1)
    end function

    function foo.get as c ()
        foo.get = _foo
    end function

    function foo.set as v (value as c )
        _foo = upper(value)
    end function
end class

 

 

Using this class:

 

dim x as mynamespace::mySampleClass

?x.foo

= "hello"

x.foo = "Goodbye"

?x.foo

= "GOODBYE"

 

 

Calling SOAP Web Services From Xbasic - This topic shows 'real world' examples of Xbasic code that call SOAP web services.


Examples are provided here for WorldPay (a credit card processing company), Kareo (a medical billing software company) and Norman G Jensen, Inc (a provider of freight brokerage services).


The source code is extensively commented and is intended as a learning vehicle to help you write code to call these and other similar SOAP web services.

 

WorldPay


WorldPay provides credit card processing as a web service. For more information go to http://www.worldpay.com/us.

The function below encapsulates the process of charging a credit card using the world pay service.

This example was provided by Max Hammond, who has extensive experience using Alpha Anywhere with SOAP web services.


FUNCTION WorldPay_ProcessCC AS CallResult (acctid AS C, ccname AS C, ccnum AS N, amount AS N, expmon AS N, expyear AS N )

dim Result as CallResult

on error goto errorWp_ProcessCC

dim webLink as c = "https://trans.worldpay.us/Web/services/TransactionService?wsdl"
dim assemblyFile as C = "C:\Program Files (x86)\a5V12\WorldPayService.DLL"
dim webEndpoint as c = "https://trans.worldpay.us/Web/services/TransactionService"

dim sv as DOTNET::Services
dim ay as DOTNET::AssemblyReference
ay.FileName = assemblyFile


' This extra call does the heavy lifting and registers the assembly DLL.
' If the assembly does not exist, create one.
if .not. File.Exists(ay.FileName)
    if .not. sv.GenerateWCFWebServiceClientFromURL(webLink, ay.FileName)
        Result = sv.CallResult
    end if
end if

' Load the assembly into the Alpha Anywhere type system.
if Result.Success
    if .not. sv.RegisterAssembly("WorldPay", ay)
        Result = sv.CallResult
    end if
end if

if Result.Error
    goto doneWp_ProcessCC
end if

' Set up HTTP Binding
' The binding object determines how we will communicate with the web service.
' This includes the underlying network transport, credentials
dim b as System::ServiceModel::BasicHttpBinding
b.MessageEncoding = System::ServiceModel::WSMessageEncoding::Text

' The settings below will depend on the service.
' We want sufficient capacity to retrieve very large nested structures.
' If you get an error that you have exceeded a size, make the adjustment here.
b.MaxReceivedMessageSize = 10485760
b.maxBufferSize = 10485760
b.MaxBufferPoolSize = 10485760
b.ReaderQuotas.maxDepth = 32
b.ReaderQuotas.MaxStringContentLength = 10485760
b.ReaderQuotas.MaxArrayLength = 16384
b.ReaderQuotas.MaxBytesPerRead = 4096
b.ReaderQuotas.maxNameTableCharCount = 16384

' Set up the security.
' In this case, we are using transport level security a UserName credential over SSL and will provide a user name credential.
b.Security.Mode = System::ServiceModel::SecurityMode::Transport
b.Security.transport.ClientCredentialType = System::ServiceModel::HttpClientCredentialType::None
b.Security.Transport.ProxyCredentialType = System::ServiceModel::HttpProxyCredentialType::None
b.Security.Transport.Realm = ""
b.Security.Message.ClientCredentialType = System::ServiceModel::BasicHttpMessageCredentialType::UserName
b.Security.Message.AlgorithmSuite = System::ServiceModel::Security::SecurityAlgorithmSuite::Default

' Create an endpoint. This is the address information needed to find the service on the web.
dim endpoint as system::ServiceModel::EndPointAddress = new System::ServiceModel::EndPointAddress(webEndpoint)

' Create Client for WorldPay Service using endpoint and bindings
dim Client as WorldPay::TransactionSOAPBindingImplClient = new WorldPay::TransactionSoapBindingImplClient(b, endpoint)

' Create Web Request using WorldPay Client
dim WebRequest as WorldPay::processCCSaleRequest
WebRequest.ccinfo = new WorldPay::CreditCardInfo()
WebRequest.ccinfo.acctid = acctid
WebRequest.ccinfo.ccname = ccname
WebRequest.ccinfo.ccnum = ccnum
WebRequest.ccinfo.amount = amount
WebRequest.ccinfo.expmon = expmon
WebRequest.ccinfo.expyear = expyear

' Make Web Service Call to WorldPay
dim WPResponse as p
WPResponse = Client.ProcessCCSale(WebRequest)


' End process in error or success
goto doneWp_ProcessCC

errorWp_ProcessCC:
on error goto 0
Result.Code = error_code_get()

doneWp_ProcessCC:
WorldPay_ProcessCC = Result

END FUNCTION

 

Kareo
Kareo Medical Billing Software provides a comprehensive web service to manage practices. For more information go to http://www.kareo.com.

The sample code below was provided by Max Hammond, who has implemented a product using Alpha Anywhere and Kareo.

The following functions are included:

 

 


FUNCTION GetAppointments as CallResult (WSDLWebLink as C, ServiceWebLink as C, AssemblyFile as C, CustomerKey as C, User as C, Password as C, ConnectionString as C, PracticeName as C)

on error goto errorGetAppointments ' To catch the dim of service objects
dim Result as CallResult

' This extra call does the heavy lifting and registers the assembly DLL
CreateService(WSDLWebLink, ServicePointWebLink, AssemblyFile)

dim RequestHeader as Kareo::www::Kareo::com::api::Schemas::RequestHeader

RequestHeader.CustomerKey = CustomerKey
RequestHeader.User = User
RequestHeader.Password = Password

dim AppointmentsRequest as kareo::www::kareo::com::api::schemas::GetAppointmentsReq
dim GetAppointmentsRequest as Kareo::GetAppointmentsRequest

AppointmentsRequest.RequestHeader = RequestHeader
GetAppointmentsRequest.request = AppointmentsRequest

dim Service as Kareo::KareoServicesClient = CreateService(WebLink, EndPointWebLink, AssemblyFile)

' Create the filter for the GetAppointments call
dim filter as Kareo::www::kareo::com::api::schemas::AppointmentFilter
filter.FromLastModifiedDate = date()-30
filter.ToLastModifiedDate = date() + 10
filter.PracticeName = PracticeName
AppointmentsRequest.Filter = filter

' Set the fields you want populated in the return by marking them as true
dim fields as Kareo::www::kareo::com::api::schemas::AppointmentFieldsToReturn
fields.AllDay = .t.
fields.AppointmentReason1 = .t.
fields.AppointmentReason10 = .t.
fields.AppointmentReason2 = .t.
fields.AppointmentReason3 = .t.
fields.AppointmentReason4 = .t.
fields.AppointmentReason5 = .t.
fields.AppointmentReason6 = .t.
fields.AppointmentReason7 = .t.
fields.AppointmentReason8 = .t.
fields.AppointmentReason9 = .t.
fields.AuthorizationEndDate = .t.
fields.AuthorizationID = .t.
fields.AuthorizationInsurancePlan = .t.
fields.AuthorizationNumber = .t.
fields.AuthorizationStartDate = .t.
fields.ConfirmationStatus = .t.
fields.CreatedDate = .t.
fields.EndDate = .t.
fields.ID = .t.
fields.LastModifiedDate = .t.
fields.Notes = .t.
fields.PatientCaseID = .t.
fields.PatientCaseName = .t.
fields.PatientCasePayerScenario = .t.
fields.PatientFullName = .t.
fields.PatientID = .t.
fields.PracticeID = .t.
fields.PracticeName = .t.
fields.Recurring = .t.
fields.ResourceName1 = .t.
fields.ResourceName10 = .t.
fields.ResourceName2 = .t.
fields.ResourceName3 = .t.
fields.ResourceName4 = .t.
fields.ResourceName5 = .t.
fields.ResourceName6 = .t.
fields.ResourceName7 = .t.
fields.ResourceName8 = .t.
fields.ResourceName9 = .t.
fields.ServiceLocationName = .t.
fields.StartDate = .t.
fields.Type = .t.

' Create the GetAppointmentsRequest object with the request information
dim Response as p

' Make the service call
Response = Service.GetAppointments(GetAppointmentsRequest)

' Get the appointment information out of the response.
AppointmentsResponse = Response.GetAppointmentsResult

if AppointmentsResponse.ErrorResponse.IsError
    Result.Code = -1
    Result.Text = AppointmentsResponse.ErrorResponse.ErrorMessage
elseif .not. AppointmentsResponse.SecurityResponse.SecurityResultSuccess
    Result.Code = -2
    Result.Text = AppointmentsResponse.SecurityResponse.SecurityResult.ToString()
else
    Result = LoadAppointments(AppointmentsResponse.Appointments, ConnectionString)
end if

Result.Code = error_code_get()
goto doneGetAppointments

errorGetAppointments:
on error goto 0

doneGetAppointments:
on error goto 0

GetAppointments = Result

END FUNCTION
 



The functions below make it easier to populate service requests.

 

 

FUNCTION CreateService as Kareo::KareoServicesClient(DefinitionWebLink as C, EndPointWebLink as C, AssemblyFile as C)
' Make sure the client proxy DLL is created and loaded and create a client proxy (an object we can make service calls on).

dim Result as CallResult = RegisterServiceDLL(DefinitionWebLink, AssemblyFile)

if .not. Result.Success
    error_generate(Result.Code)
end if

' Set up HTTP Binding
' The binding object determines how we will communicate with the web service.
' This includes the underlying network transport, credentials
dim b as system::ServiceModel::BasicHttpBinding

b.MessageEncoding = System::ServiceModel::WSMessageEncoding::Text

' The settings below will depend on the service.
' We want sufficient capacity to retrieve very large nested structures.
' If you get an error that you have exceeded a size, make the adjustment here.
b.MaxReceivedMessageSize = 20485760
b.maxBufferSize = 20485760
b.MaxBufferPoolSize = 10485760
b.ReaderQuotas.maxDepth = 32
b.ReaderQuotas.MaxStringContentLength = 10485760
b.ReaderQuotas.MaxArrayLength = 16384
b.ReaderQuotas.MaxBytesPerRead = 4096
b.ReaderQuotas.maxNameTableCharCount = 16384

' Set up the security.
' In this case, we are using transport level security a UserName credential over SSL and will provide a user name credential.
b.Security.Mode = System::ServiceModel::SecurityMode::Transport
b.Security.transport.ClientCredentialType = System::ServiceModel::HttpClientCredentialType::None
b.Security.Transport.proxyCredentialType = System::ServiceModel::HttpProxyCredentialType::None
b.Security.Transport.Realm = ""
b.Security.Message.ClientCredentialType = System::ServiceModel::BasicHttpMessageCredentialType::UserName
b.Security.Message.AlgorithmSuite = System::ServiceModel::Security::SecurityAlgorithmSuite::Default

' Create an end point object to represent the address of the server.
dim e as system::ServiceModel::EndPointAddress = new System::ServiceModel::EndPointAddress(EndPointWebLink)

' Create the service object using the binding and the endpoint
dim MyService as Kareo::KareoServicesClient = new Kareo::KareoServicesClient(b, e)

' There are some quotas that are harder to set.
' This utility function will take care of this in one place.
SetSvcGraphObjectQuota(MyService)

CreateService = MyService
END FUNCTION


FUNCTION RegisterServiceDLL as CallResult (WebLink as C, AssemblyFile as C)
' This function retrieves the Web Service Definition Language (WSDL) XML file and generates a local .NET proxy.
' The proxy assembly is registered in Alpha Anywhere as a namespace (set of types) and can be used
' as any other .NET type to make web service calls.

on error goto errorRegisterServiceDLL
dim Result as CallResult
dim sv as dotnet::Services
dim Assembly as dotnet::AssemblyReference

'Create Web Service Client and Register
Assembly.FileName = AssemblyFile

if .not. File.Exists(AssemblyFile)
    if .not. sv.GenerateWCFWebServiceClientFromURL(WebLink, AssemblyFile)
        Result = sv.CallResult
    end if
end if

if Result.Success
    if .not. sv.RegisterAssembly("Kareo", Assembly)
        Result = sv.CallResult
    end if
end if

goto doneRegisterServiceDLL

errorRegisterServiceDLL:
on error goto 0
Result.Code = error_code_get()

doneRegisterServiceDLL:
on error goto 0

RegisterServiceDLL = Result

END FUNCTION



FUNCTION SetSvcGraphObjectQuota as CallResult (Service as P)
' This utility function sets the maximum number of objects in the serializer.
' The serializer packages and unpackages the request as it is send over the Web.
' You should only need to do this for services that return large amounts of data.

dim Result as CallResult

on error goto errorQuota
Operations = Service.Endpoint.Contract.Operations

for i = 1 to Operations.Count
    Operation = Operations[i]
    Behaviors = Operation.Behaviors
    Enumerator = Behaviors.GetEnumerator()
    while Enumerator.MoveNext()
        Current = Enumerator.Current
        if Current.gettype().FullName = "System.ServiceModel.Description.DataContractSerializerOperationBehavior"
            Current.MaxItemsInObjectGraph = 2147483647
        end if
    end while
next

goto doneQuota

errorQuota:
Result.Code = error_code_get()

doneQuota:

SetSvcGraphObjectQuota = Result

END FUNCTION
 

 

Norman G. Jensen

Norman G. Jensen, Inc (JGJ) provides US and Canadian customers brokerage, freight forwarding, warehousing,
distribution and consulting services to North American importers and exporters. For more information about the
company see http://www.ngjensen.com.

This script example downloads the service definition, generates and loads a client proxy assembly and then calls a service
function that accepts raw XML requests.


dim WebLink as C = "https://forms.ngjensen.com/library/aes_jt_service.php?wsdl"
dim DLLName as C = "c:\temp\aesV12.dll"
dim EndPointWebLink as C = "https://forms.ngjensen.com/library/aes_jt_service.php"

dim Result as CallResult

' Test Values - See Jensen documentation for actual values.
Authorization = 12345
IPAddress = "127.0.0.1"
XML = "<?xml version='1.0'?><NGJDocument><DocInfo ... >"

Result = CreateDLL(WebLink, DLLName)
if Result.Sucess
    Result = RegisterNamespace(DLLName, "submit_xml")
end if

if Result.Success
    Result = SubmitXML(EndPointWebLink, Authorization, IPAddress, XML)
end if



FUNCTION CreateDLL as P (WebLink as C, AssyFile as C)

CreateDLL = new CallResult()

if File.Exists(AssyFile)
    end function
end if

dim Service as DotNet::Services
if .not. Service.GenerateWebServiceClientFromURL(WebLink, AssyFile)
    CreateDLL = Service.CallResult
end if

end function



FUNCTION RegisterNameSpace as P (AssyFile as C, NameSpace as C)
' Load the assembly and register the types in Alpha Anywhere

RegisterNameSpace = new CallResult()

dim Service as DotNet::Services
dim AssyRef as DotNet::AssemblyReference
AssyRef.FileName = AssyFile
Dim Result as CallResult

if .not. Service.RegisterAssembly(NameSpace, AssyRef)
    RegisterNameSpace = Service.CallResult
end if

end function


function SubmitXML as C (EndPointWebLink as C, Authorization as C, IPAddress as C, XML as C)
dim AES as submit_xml::AES_Methods
dim cc as c
cc = AES.js_submit_xml(Authorization, IPAddress, XML)
SubmitXML = cc
end function

 

 

 

 

UX Component - List of Switches - A common design pattern in mobile applications is to have a series of switch controls to set logical values. The screenshot below shows how this might look.

Download component

 

 

 

 

 

Here are some of the important settings for each switch control:

 

 

 

Notice that the 'Control Container Classname' property property has been set to a custom class name. The definition is shown below.

In the CSS, we first set the control container to have a relative position - which means all absolutely positioned child elements will be positioned relative to the parent - allowing parent width and position to be honored be the child.

We then set the first level of child DIVs (of which there is only one - the switch itself - the label is a LABEL element) to have an absolute position, a specific width, and a right location of 0px - which means it will stick to the right of the parent.


.switchCtrlGroup {
    position: relative;
}
.switchCtrlGroup > div {
    position: absolute;
    right: 0px;
    width: .75in;
}

 


 

 

Build 2128-4292 29-Apr-2014 - Alpha Anywhere Version 2

Features

Web Application - PhoneGap - If you have a lot of applications in PhoneGap build, retrieving the app icon for each app can be slow because the PhoneGap build API does not have a call to retrieve all icons at once. You have to call the API once for each app. Therefore, a new property has been added to the Get Icon Timeout Threshold property. If you set this property to <disable>, a default icon will be used.

 

Features

Grid Component - <RowNumber> and <LogicalRecNo> Columns - Using these virtual columns in a tabular Grid caused an error.

AlphaDAO - MySQL - Numeric Fields with 7 or More Decimals - Fixed an issue with MySQL where you could not enter numbers with more than 6 decimal places.

Grid Component - Setting State Variables - Fixed an issue where setting state variables using the e._state pattern was not working in the AfterInsert, AfterUpdate and AfterDelete server-side events.

Build 2118-4290 24-Apr-2014 - Alpha Anywhere Version 2

Videos

 

UX Component Multi-select List Control - Icon to Indicate Selected Rows The Button List control (and the Checkbox control - configured to render as a Button List) can show an icon on selected items. The List control can also be configured to allow multiple selections (like a Button List or Checkbox), but it does not show an icon on the selected rows to indicate the row has been selected (it shows selected rows using a different row color).

In this video we show how you can easily display an icon on the selected rows. The technique uses a custom CSS class.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Making a TextArea Fill a PanelCard Controls such as Lists and Maps have a 'Fill container' property that allow you to automatically cause the List or Map to fill the Panel Card in which the control is contained. Other controls, such as Text Areas, do not have this property.

In this video we show how you can configure the UX so that the Text Area control automatically fills the Panel Card in which it is contained.

Watch Video
Download Component

 

 

Bugs

UX and Grid Component - Image Upload Action - Image Scaling - Fixed issue with scaling image after it was uploaded.

 

Calendar Component - Editing Events  - Fixed an issue editing an event the second and subsequent time. This issue was introduced in build 2089.

UX Component - Phone Gap - Fixed an issue with PhoneGap where Ajax callbacks were failing and images that were loaded from the server were failing.

Features

AlphaDAO - SQL::TableInfo - ParseTableName() Method - A new static method has been added to the SQL::TableInfo object. The .ParseTableName() method takes a fully qualified tablename and returns the base table name, owner, schema and catalog for the table.

For example

 

dim CatalogName as C
dim SchemaName as C
dim OwnerName as C
dim BaseTableName as C
dim FullName as C = "dbo.[hello.world]"
dim ti as sql::tableinfo
?ti.ParseTableName(CatalogName, SchemaName, OwnerName, BaseTableName, FullName)
= .T.

?CatalogName
= ""

?SchemaName
= ""

?OwnerName
= "dbo"

?BaseTableName
= "dAgency.06"

?fullname
= "[dAgency.06]"

 

 

UX Component - Action Javascript - Panel Actions - Navigate Action - History - The 'Navigate' action now has new options. The options with the 'History' prefix allow you to navigate through the Panel Navigator's history (much list the way a browser's history button works).

Code Editors - Xbasic and Javascript - Bookmarks - You can now get quick access to any bookmarks you insert into the script or function you are editing by clicking the 'Bookmark' icon on the status bar.

A bookmark is any comment that starts with //.

For example:

'//bookmark1  (Xbasic)

//''Bookmark1 (Javascript)

 

 

AlphaDAO - Listing Tables in a Database - When you use the <connection>.listTables() or <connection>.listTablesWithTypes() methods to list the tables in a database, by default, only the first 1,000 objects are listed.

As a result of this, many of the builders you use in AlphaAnywhere that require you to select a table only present a list showing the first 1000 tables in the database. Now, a new setting in the Settings dialog box allows you to set the maximum number of tables returned in a table listing.

To open the Settings dialog box, select the top-level View menu, then select Settings.

 

 

 

If you are using AlphaDAO to get your own listing of tables in an object, the SQL::TableFilter object which is passed into the .listTables() and .listTablesWithTypes() method now allows you to set the .MaximumTablesInList property on the SQL::TableFilter object. Set this property to -1 for no limit.

For example:

 

 

 

dim sqlFilter as sql::TableFilter

sqlFilter.IncludeAliases= .t.

sqlFilter.IncludeAllCatalogs= .F.

sqlFilter.IncludeAllOwners= .F.

sqlFilter.IncludeAllSchemas= .T.

sqlFilter.IncludeLinkedTables= .f.

sqlFilter.IncludeSynonyms= .t.

sqlFilter.IncludeSystemTables= .f.

sqlFilter.IncludeTables= .t.

sqlFilter.IncludeViews= .t.

sqlfilter.MaximumTablesInList = 2000

dim cn as sql::connection

cn.open("::name::myconnection")

dim list as c

list = cn.listTables(sqlFilter)

 

Tip: You can use the Xbasic helper function to list tables and automatically honor the setting you have defined in the Settings dialog. The helper functions are a5_list_tables() and a5_list_tables_with_types(). The functions take the connection object as the first parameter and the sql::tableFilter object as the second parameter.

 

 

Tips

AlphaDAO - Connection Strings - Postgres - Specifying the Default Schema - When working with a Postgres database that contains multiple schemas, you can specify the default schema in the connection string. Unfortunately, at this point, the connection string dialog does not let you specify the default schema, but you can easily edit the generated schema to add the necessary directive to set the schema.

For example:

{A5API='PostgreSQL',A5Syntax='PostgreSQL',A5UseServerSidePrepare=Y,A5InitialCommand='SET SCHEMA ''TestSchema''', Database='Alphasports', Password='alpha',Port='5432',Server='localhost',UserName='postgres'}

 

In this example, the following directive has been added to the connection string:

A5InitialCommand='SET SCHEMA ''TestSchema'''

 

Notice that the entire argument to the A5SetInitialCommand is enclosed in single quotes. Therefore the schema name, which must also be enclosed in single quotes uses escaped single quotes (a double single quote).

 


 

 

Build 2091-4284 11-Apr-2014 - Alpha Anywhere Version 2

Bugs

UX Component - List Control - Multi-Select - If the List control was configured to allow multiple rows to be selected, when the UX was submitted, the selections in the List were not being returned as an array, as they should have been. Instead, they were being returned as a '\n' delimited string. This bug was introduced in the last update.

 

Videos

Grid Component Opening a UX from a Button on a Grid and Passing Information Into the UX You can open a UX component from a button on a Grid using several different actions in Action Javascript. For example, there are built-in actions to edit the data in the current row of a Grid using a UX.

But sometimes you want to simply open a UX and pass information from the current row in the Grid to the UX.

In this video we show how this is easily done by defining arguments in the UX component and then automatically setting the value of these arguments when the UX is opened.

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

Build 2089-4283 10-Apr-2014 - Alpha Anywhere Version 2

 

Security

 

Application Server - OpenSSL - 'HeartBeat' Bug - The Application server now uses Version 1.0.1g of the 3rd party OpenSSL library which Alpha Anywhere uses. This updated library patches the so called 'HeartBeat' vulnerability in the OpenSSL library.

 

 

Breaking Changes

UX Component - List Control - Group Summaries - If you are using the {dialog.object}.groupSummary() method in a Group header or footer, you will need to edit the component and change the method to

this.groupSmmary()

The .groupSummary() function is now a method of the List object. Previously is was a method of the UX object.

Application Server - Warning. A change has been made to the web security system to load the security much faster. This change alters one of the published security files. If a project is published from the latest pre-release to an older application server, the older application server will report a 500 internal server error as it won't be able to read the new file. The application server should be the same build as the development program.
 

 

Videos

UX and Grid Component E-mailing a Report A common pattern in both the UX and Grid component is to place a button on the component to print a Report and display the Report in a window, div or TabbedUI pane. However, instead of displaying the Report, you might want to send it as an email.

The Action Javascript action to Print a Report has an option to call an Xbasic function when the Report has printed.

In this video we show how you can use this option to e-mail the report using the Mandrill e-mail service.

(Note: The sample function prototype shown in the video is only available in build 4241 or above.)

Watch Video - Part 1
Watch Video - Part 2
UX Component Cross-domain Ajax Callback A cross-domain Ajax callback is a callback that takes places to a server that is in a different domain than the domain from which the component was loaded.

In this video we show how a callback is made to the Apple iTunes store and we contrast the difference between making the callback directly to the Apple site versus making a callback to the Alpha server first and then having the Alpha server make the call to the Apple site.

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

Download component
 
UX and Grid Component Using CSS Icons from the Font-Awesome Icon Font Library The Font-Awesome CSS Icon library (http://fontawesome.io) is bundled with Alpha Anywhere and can be used in the UX, Grid and TabbedUI components.

In this video we show how to use the Font-Awesome font library and CSS icons in general.

Watch Videos - Part 1
Watch Videos - Part 2
Watch Videos - Part 3

 

UX and Grid Component Using 3rd Party Icon Font Libraries (CSS Icons) There are many 3rd party Icon Font (CSS Icons) libraries that can be used with Alpha Anywhere. In this video we show how you can go to a source of icon fonts  (http://www.fontello.com/)and download a font library that can then be installed into Alpha Anywhere.

Watch Video
UX Component Using CSS Icons in a List - List Menus A common pattern in mobile applications is to use a List control as the menu. This list control is then displayed in a Panel Window that animates in from the left side of the screen. Icons are typically displayed for each menu choice. CSS Icons are ideal for these types of icons. In this video we show how a List can be easily configured to display a menu. Each item in the List has a CSS Icon in it.

Watch Video
UX Component - Mobile Applications Creating a 'Split-View' using the Pre-Defined 'Split-View' Template A common pattern in mobile application is the 'split-view' which shows a menu on the left and a work area on the right. On a phone, were space is limited, the menu is hidden and only shown on demand, but on a tablet, the menu is always shown. In this video we show how you can quickly create a UX component that implements a split-view by selecting one of the pre-defined 'split-view' templates. We then explain some of the concepts behind the component.
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3

 
UX Component Split Buttons A split button is displayed as a regular button and a smaller button with a dropdown icon. You can have different event handlers for the dropdown button portion of the button and the regular portion of the button. When space is constrained, you can use a single split button to perform many tasks, while still giving the user single click access to the last selected task.

In this video we show how you can use split buttons in your applications.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download components
UX Component List Control - Lookup Columns The List control allows you to define 'lookup columns' where the data in the column is 'looked up' either by calling a Javascript function (that you define), or by looking up the value in some other List.

A typical use case for this is a List that shows Order Details. Each row in the list has a 'productId' field. You would like to display the product name for each product id.

In this video we show how to define Lookup Columns in a List.

Watch Video
Download Component (You will need to change the connection string for both lists to point to the sample Northwind database).
UX Component List Control - Client-side Grouping and List Navigator Group breaks can be inserted into the List control. The group breaks can be 'server-side' group breaks, or 'client-side' group breaks. The advantage of 'client-side' group breaks is that they can be dynamically applied to the data in the List. That means you can easily switch from grouping the data by 'Lastname' to grouping by 'City', etc. You can also display summary values in the group headers and footer.

For lists that have group breaks (regardless of whether the group breaks were computed server-side or client-side), you can also display a List Navigator, which allows the user to easily scroll a long List.

In this video we give an overview of client-side group breaks and the List Navigator. Then, we go into depth on setting up client-side grouping using Action Javascript (to apply the group breaks after the List is initially rendered) and in the List definition itself (so that when the List is initially rendered, the group breaks are shown).

We also show how summary data can be inserted into a List header or footer.

Watch Video - Overview
Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Download components
UX Component List Control - Using Native SQL For List Data When you create a List control that is based on SQL data, you must use Alpha Anywhere 'portable' SQL. If you want to base you List on 'native' SQL (which includes stored procedures), you must define a 'custom' data source for the List and then in the Xbasic function that returns the data, you can use your native SQL.

In this video we show how this can be done.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Drag and Drop - Dragging Rows from a Source List to a Target List A common design pattern in applications is to allows users to drag items from one List to another.

The Alpha Anywhere Javascript library contains powerful drag and drop functions that allow you to easily enable this type of functionality. In this video we show how you can create a UX with two List controls and drag rows from one List to the other.

Watch Video

In this video we explain the Javascript code that enables this functionality:

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

Download component

Addendum. The previous videos show drag/drop on a List using a mouse. However, the previous examples do not work on some mobile devices because on iOS (for example), the 'up' event fires on the element that initiated the 'down' event (and not on the element on which the up event took place, as you might have expected). The next video explains how the component shown in the previous videos can be slightly rewritten so that it works on a mobile device (and as a bonus, also allows re-ordering of the rows within a List).

Watch Video
Download component
 
UX Component List Control - Range Searches The List control has a built-in action in Action Javascript to filter the List. An Ajax callback to the server is made and the query that populates the List is executed with a filter that is computed based on values in the search control on the UX. Now, you can easily perform 'range' searches, as shown in this video.

NOTE: Another way to perform a 'range' search is to use a single search control, turn on the 'Allow QBF' option and then enter the search value as a range using the .. (two dots) synax. For example, to search for quantity between 10 and 20, you would enter 10..20 in the search control.

Watch Video
UX Component Absolute Layout Container - Save as PDF The Absolute Layout container in a UX allows you to place controls at absolute locations, typically using a bitmap image of a form as a background. You can use an action in Action Javascript to save the contents of the Absolute Layout container as PDF file and then download the PDF to the client, or call some Xbasic function to process the PDF file.

This video shows how this is done using Action Javascript.

Watch Video
UX Component Internationalization - Language and Text Dictionary Tags Language or Text Dictionary tags are typically used to internationalize the strings in a UX component. However, adding the tags to a large component can be tedious. This video shows how the Internationalization Helper can be used to automate this task.

Watch Video
UX Component Client-side Formatting for Numeric Data and Templates You can use format directives in the Templates that the UX component List control uses to display data. This allows you to easily format numbers (for example show thousands separated by commas with 2 decimal places) and apply templates to strings (for example, show '5551234567' as (555) 123-4567)

The video shows how you can insert a format directive into a List template using the Number Format Genie.

Watch Video
UX Component Using a List Control to Display Detail Information (in Field/Value Pairs) for a Record A common pattern in mobile applications is to display a List of records and then when the user clicks on a row in the List to display a list of fields and corresponding values for the row the user clicked on, with one field/value pair per line.

In this video we show how a second List can be used to display the field/value pairs and how this List can be dynamically populated when the user clicks on a row in the main List of records

Watch Video - Part 1
Watch Video - Part 2
Download component

Addendum: In this video we show how you can enhance the UX by showing a message in the Detail List when no record is active in the primary List.
Watch Video
 
UX Component Dynamically Populating a List with Data from a SQL Database Populating a List dynamically with data from a SQL database is a very common pattern in application development. In this video we show how this is easily done.

In the video we show how a List control on a UX can be populated with customers in a country. The country is selected from a dropdown control.

Watch Video - Part 1
Watch Video - Part 2
Download component
UX Component Transform Data Type of List Data By default, the data type for each field in a List is a Javascript string. In some cases you might want the data type for a column to be a Javascript date or number object.

A benefit of transforming dates into true Javascript date objects is that you can then use date formatting in the template for the List. For example, when displaying a field called OrderDate in the the List, instead of specifying {OrderDate} in the template, you might specify {OrderDate:date('yyyy-MM-dd')}

Watch Video
Download component
 
UX Component List Virtualization - Optimizing the List for Large Number of Rows When you are working with List controls that contain a large number of rows (say several thousand rows), it is advisable to turn on the List's 'virtualization' feature. With virtualization turned on, the List will only render a small number of rows at a time (the visible rows and some additional rows above and below the visible rows).

Turning on List Virtualization will dramatically reduce both the time taken to load the List and the amount of memory consumed by the List.

Watch Video
Download component
UX Component List Control - Modeless Preview Window in List Builder When you are designing a List control in a UX component, the List Builder is a modal dialog. This means that you need to first close the List Builder before you can preview the UX component to see how your List control looks.

However, while you have the List Builder open, you can click the Preview button to open a modeless preview window which you can keep open whiel you are working in the List Builder. Simply clicking on the Preview button will quickly refresh the preview shown in the window.

Watch Video
UX Component Action Javascript - Merge Data into Template Alpha Anywhere has a very powerful client-side template engine that allows you to merge Javascript data into templates to produce HTML output that can then be displayed on your component.

This functionality is exposed in the 'Merge data into client-side template' action in Action Javascript.

NOTE: Other videos explain the template syntax in more detail.

Watch Video
Download Component
UX Component Using the Template Tester to Help Design Templates - Tutorial on Template Syntax The client-side template engine in the UX component is very powerful, but to be able to take full advantage of its power it is necessary to understand the syntax used in the templates.

In this video we demonstrate how to use the Template Tester and we walk through the various examples that are built into the Template Tester.
The video gives an extensive overview of the template syntax.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
Watch Video - Part 6
Watch Video - Part 7
Watch Video - Part 8
UX Component List Control - Column Resizing The List control allows you to specify that columns in the list are resizable.

This video shows how you can set the resizable property at the individual column level.

Watch Video
Download Component
UX Component Destroy Child UX Component A common pattern when building large mobile applications is to break the app into multiple sub-component which are called from a master component.

Once the child component is no longer needed, it is useful to be able to delete the component from memory in order to conserve the limited memory available in the browser.

The {dialog.object}.destroyChildComponent() method can be used to delete child UX components from memory, as shown in this video.

Watch Video
Download Components
UX Component Generate a component at run-time using Xbasic In most cases, the UX components that your application uses will be built at design-time. However, there may be use cases for UX components that are generated dynamically at run-time using Xbasic.

The a5wcb_createDialogUsingXbasic() allows you to generate a UX component using Xbasic.

In this video we show how a button on a UX makes an Ajax callback to generate a UX on the fly. Another button then opens this dynamically generated UX component.

Watch Video
Download Component
Code Editor Highlighting Opening and Closing 'Pair' Delimiters When editing Xbasic or Javascript code, html, JSON etc. it is often helpful to be able to see the start and end of different 'pairs'. For example in an Xbasic function call, highlighting the opening an closing parentheses. Or in a Javascript function, highlighting the opening and closing curly braces. In some HTML text, the opening and closing tags (e.g. <div>, <body>, <p> , etc.)

In addition, once a 'pair' has been identified, keyboard shortcuts (Control  ] and Control-Shift ] )  allow you to quickly move focus from the start of the 'pair' to the end of the 'pair' or to select all of the text inside the 'pair'.

Watch Video
UX Component Using the List Scroller to Move Through the Rows in a List When working with virtualized Lists, it is possible to have Lists that have a very large number of rows. Navigating a very large List by drag scrolling on the List body could be cumbersome. To facilitate navigating large Lists, a 'List scroller' can be added to the List. The scroller shows a message while you are dragging on it showing which row in the List will be shown if you were to stop dragging on the scroller.

Using the scroller, you can very quickly navigate to any row in the List.

The List Scroller is not limited to virtualized Lists. It can also be used with non-virtualized Lists.

In this video we show how to add a List Scroller to a List and we show how you can quickly navigate to the last row in a virtualized List that contains 100,000 row of data.

Watch Video
Download component

 

 

 

 

 

 

Notice

Application Server - OpenSSL - 'HeartBeat' Bug - The Application server now uses Version 1.0.1g of the 3rd party OpenSSL library which Alpha Anywhere uses. This updated library patches the so called 'HeartBeat' vulnerability in the OpenSSL library.

 

 

Postgres ODBC Driver - Version 9.03.01.00 - Bugs - Postgres has introduced a bug in the latest version of their ODBC driver that affects the Grid component. The only solution is to roll back to a previous version of the ODBC driver, or turn off write conflict checking for all updateable fields in the Grid.

Specifically, the driver fails when an expression is included in the WHERE clause that tests a bound variable for NULL-ness.
Here is a summary of the bug:

Consider the following sample Interactive window session:


dim args as sql::arguments
args.add("tags", "rain, snow")
?cn.execute("select * from test_table where :tags is null", args)

 

This will fail and the error reported is:

The PostgreSQL ANSI ODBC driver reports 42P18 - ERROR: could not determine data type of parameter $<n>; when preparing SQL with an expression of the form:

<bound parameter> IS NULL.
 

Update: A work around has been added in the SQL generated by the Grid Component so that Grids will work with the 9.03.01.00 ODBC driver.

 

 

AlphaDAO - Postgres - Connection String - Changes In Default Values Set By the Alpha Anywhere PostgreSQL Extension Driver

The Alpha Anywhere PostgreSQL extension driver now defaults the following connection string attributes:

Protocol=7.4-1
UseServerSidePrepare=1

Previously only the following were set:

B8=1 // B8 = UnknownsAsLongVarchar (rather than varchar)
B9=0 // B9 = Bools as Char
ByteaAsLongVarBinary=1

If these defaults do not work for your installation for some reason, you will need to create and ODBC DSN and use the Alpha Anywhere ODBC driver.

Setting Protocol=7.4-1 has been demonstrated by one customer to dramatically improve performance with PostgreSQL 9.3 on large batches of inserts (about 25%).
 

Change in Behavior

Bugs

Reports - HTML Reports - Export to PDF, Excel, Word - International Dates - If your date format was set to dd/mm/yyyy then if you printed an HTML report that used dates in its filter expression and then you clicked a toolbar icon to export the report to PDF, Excel, or Word, the date filter was not applied correctly.

Reports - Quick Report Genie - Summary Fields - Fixed a bug where the Genie would crash if you edited a field that had summary values.

UX Component - Responsive Design Genie - Absolute Layout Containers - Textbox Controls with In-Place Buttons - Fixed an issue that caused the textboxes to not display.

TabbedUI Component - HTML Reports - Reports with Parameters that are Set to Prompt at Runtime - If you had an HTML report that was set to prompt for parameters at runtime, the first time you ran the report, the report would render correctly. But if you tried to run the report a second time (by entering new parameter values, but NOT first closing the Tab Pane), the report did not render.

UX Component - AbsoluteLayout Container - Text Control - Fixed a bug with text controls in an AbsoluteLayout container which caused controls that followed the text control to render in the wrong position.

Reports - Export to Word - In some cases, numeric fields in a report would not export correctly to Word.

UX Component - Absolute Layout Container - PanelOverlay Container - Content in an AbsoluteLayout container that was inside a PanelOverlay container did not render correctly.

Web Applications - Security Framework - MySQL - Under certain circumstances using MySQL tables for web security, deleting a user could fail.  This has now been fixed.

Web Security Framework - CSS Icon Fonts - The new iOS7 and Android style sheets use icon fonts. The images were not displaying if the security framework was enabled because the font files did not have the appropriate security settings.

The web security framework will now recognize the the new font files for CSS icon fonts. The page security must be opened from the web security menu to add the new types to the page security.  Then publish any page to add the new settings to security.  If the Security cache lifetime is set to 0, the application server must be stopped and restarted to apply the changes.
 

UX and Grid Component - Edit-Compo - Populate using Ajax Callback - If an edit-combo is dynamically populated using an Ajax callback, previously, the Order By property was ignored and the list was automatically ordered by the columns in the display list. Now, the order by clause is honored. Many SQL databases do not allow an order by clause on columns that are not in the select list. Therefore, you may need to ensure that the columns in your order by clause are also in the list of fields to display.

Grid Component - Font-Awesome - Live Preview - When you did a Live Preview from a Grid component that used Font-Awesome CSS Icons, the Font-Awesome files were not getting published to the Live Preview folder.

 

Layout Table Reports - Absolute Position Cell - Calculated Fields - If you created a cell in a Layout Table report that used Absolute Positioning and placed calculated fields in the absolute layout, the calculated fields were not shown in the Absolute Layout editor when you opened the editor a second time to make edits to the cell.

Web Applications - Report Server - SQL Reports - Under some circumstances, a report based on a SQL database would fail to print when using the Report Server. The error message was reporting that the connection string could not be resolved.

UX Component - Signature Capture Control - Tab Control - If a signature capture control was placed in a tab pane that was not initially visible, when the tab pane was made visible the control did not work.

Desktop Applications - Security - If you set permission on a .dbf table to disallow edits, changes or deletes, the permissions were not being honored.

 

UX Component - Server-side Save Records to Table(s) Action - User Defined Events - Aborting the Action - The help in the function prototype for the various events (such as beforeRecordInsert, beforeRecordUpdate, etc.) describe that you can abort the action by setting

 

rtc.abort = .t.

 

The help is wrong. It should have read:

e.rtc.abort = .t.

e.rtc.abortReason = "Reason"

 

 

Desktop Applications - Forms - Embedded Browses - Entering New Records - There was a cosmetic issue during data entry into a one-to-one child table in an embedded browser. Consider the following set:

TableMaster===>TableChild1---->TableChild2

If you were entering a new record into the embedded browse and you entered a value in the field in TableChild1 that links TableChild1 to TableChild2 and there was no matching record in TableChild2 (in other words, you were creating a new record in both TableChild1 and TableChild2, rather than the more common case of a new record in TableChild1 that links to an existing record in TableChild2), then as soon as you tabbed out of a field in TableChild2, the data you entered would disappear. When you saved the record, the data you entered would then show up. This is fixed.

 

UX and Grid Component - Edit-Combo - Static Choices - The 'Filter method for required selection' property was not shown if the choices were set to 'Static'. (This property was shown for 'Dynamic' choices).

On Firefox, if you do not set this property to 'Progressive' and you have set the 'User must select from list' property to true, then you will not be able to hit the tab key to tab out of the control to the next control in the form.

 

 

Xbasic - Passing Function Arguments By Referencing - Array Indexers - If a numeric value was passed into a function and then that value was as an array indexer, it failed. For example:

 

function myFunc as c (arr as p, byRef myIndex as n)

    dim result as c

    result = arr[myIndex].name

    myFunc = result

end function

 

However, if you did this, it would have worked:

function myFunc as c (arr as p, byRef myIndex as n)

    dim result as c

    result = arr[myIndex.value].name

    myFunc = result

end function

 

Desktop Applications - Forms and Browse - Lookup Field Rules - Display a Dropdown - Fixed an issue when you could not edit entries in a control that was defined as a lookup.

Calendar Component - TabbedUI - If you had a TabbedUI component that opened multiple calendar components, then buttons in the popup UX component would only render in the last calendar component that was opened.

UX Component - Signature Capture Control - Data Binding to .DBF Tables - Fixed an issue in the signature control if the UX was bound to .dbf tables.

Grid Component - Tree Control Navigator - Session Variables in Custom SQL Statement - If you specified a custom SQL statement for any level of the tree and used session variables in the WHERE clause, the query would fail.

Grid Component - Search Part - Cascading Dropdown Boxes - 'Explicit' Option - If the 'Explicit' option was used for defining the filter for the child Dropdown box, the child Dropdown was not populated correctly when its parent's value was changed. This bug only happened for controls in the Search part.

Grid Component - Radiobutton and Checkbox Controls - 'Not in List' Rule - Numeric Fields - The 'Not in List' property was not exposed for Numeric fields.

 

UX Component - Map Control - Bulk Add Marker - If the latitude sub-series name in the Data Series was not called 'latitude' and the longitude sub-series name was not called 'longitude' the action would throw an error.

 

UX Component - RadioButton and CheckBox Controls - Render as ButtonList Option - Events - When you check the property to render a RadioButton or CheckBox control as a ButtonList, the standard Javascript events that can be defined for a RadioButton or CheckBox are meaningless. ButtonsLists expose two Javascript properties:

Therefore, when you check the 'Render as ButtonList' property all of the standard Javascript properties in the Property Sheet are hidden and the onClick and onSelect events, which are standard for ButtonLists are now exposed.

 

UX Component - Panels - Internet Explorer V11 - Fixed some issues with Panels not working correctly under IE11.

 

Security Framework - Security Log in - The security log in process no longer checks user id and password values to see if they meet validation rules. The process will now attempt to log in with any non-blank value. This check is now only performed when user credentials are created or edited.
 

Features

Xdialog - UpperCase Only Input Control - A new directive, ^, allows you to specify that an input control will only accept uppercase characters. If the user types in a lowercase character, it will convert to uppercase. Previously you could have created a template to only accept uppercase, but that would have prevented the user from entering non-alphabetic characters.

 

For example:

ui_dlg_box("Convert to Upper","[%^%.10name]")

 

Using a template:

ui_dlg_box("Convert to Upper","[%X=LLLLLLLLLL%.10name]")

 

 

UX Component - Additional Resource Files Property - A new property has been added to the UX builder that allows you to specify the names of any additional resource files. These are files in the Web Project folder that you want to ensure get published every time you publish the UX component.

This property is in the 'Other' section of the UX Properties pane in the UX builder.

Additionally, if this component has been specified as the 'initial' component in a PhoneGap project then these files are automatically copied into the PhoneGap project that is submitted to PhoneGap build.

The files entered into this list must be in the form of a cr-lf list of relative filenames (relative to the Web Project folder).

 

UX Component - List Control - Scrollers - List scrollers allow you to quickly navigate to a particular record in a List. You can drag on the scroller in much the same way that you drag on the 'thumb' portion of a scrollbar in a desktop application. When you stop dragging on the scroller, the corresponding row in the List is brought into view.

Watch Video
Download component

 

While you are dragging on the scroller, a message is displayed showing what record would be shown if you were to stop dragging. The contents of the message is completely customizable. It is actually a standard HTML List template and it supports all of the template features for List controls. The message can display fields from the data in the List.

The List scroller is particularly useful for virtualized Lists because a virtualized List can contain a very large number of rows. Using the scroller you can quickly navigate to any row in the List without having to drag scroll one screen at a time.

However, List scrollers are not limited to virtualized Lists. They can also be used with non-virtualized Lists.

(See below for information on Virtualized Lists).

 

 

To turn on the List scroller, check the 'Has scroller' property on the List Properties pane in the List builder.

You can use placeholders for any field in the List in the template.

 

 

UX Component  - Customizing the Scroll Indicator - When you are drag scrolling on a List (or any container that supports drag scrolling), scroll indicators are displayed. You can now customize the appearance of these scroll indicators (or even turn them off).

To customize the scroll indicator settings, click the smart field for the 'Custom scroll indicator settings' property.

 

 

 

UX Component - List Control - Fixed Headers and Footers - List controls have always supported 'data' headers and footers. Data headers appear before the first row of data (below the List titles) and after the last row of data. When the List is scrolled, the data header and footer can scroll out of view.

Fixed headers and footers, on the other hand, appear above and below the List and are always visible regardless of how the List has been scrolled.

To turn on fixed headers and footers, check the appropriate property in the List Properties pane in the List builder.

TIP: To insert controls in the header or footer (e.g. input controls, buttons, etc), add the control to the UX and wrap then in an 'Injectible' container. The inject the contents into the header or footer as shown in the image below. When you open the header or footer editor you will see a hyperlink that generates the required code.

 

 

 

Code Editor - Highlighting - The code editor now highlights opening and closing parentheses, curly braces html tags (when editing HTML text) and long string delimiter (e.g. <<%txt% .... %txt%).

 

Watch Video

 

 

In the image below, the long string has curly braces (it is a JSON object). Because the long string uses the special

%html% delimiter, the curly braces are highlighted.

 

 

When the braces are highlighted, the right click menu has a new option - Select Pair... - which selects all of the text between the opening and closing brace.

 

 

The following keyboard shortcuts can be use when a 'pair' has been identified (i.e. the editor is highlighting the start and end of a pair.

 

 

Grid Component - Action Scripting - Send e-mail Action - Mandrill - Now supports the Mandrill service as a method for sending the e-mail. 

Grid Component - Action Scripting - Send e-mail Action - Dynamically Computing Message Body -

The message body can now be dynamically generated using an Xbasic function.

UX Component - Action Scripting - Send e-mail Action - A new action is now available in Action Scripting to send an e-mail. This is the same action that is exposed in server-side Action Scripting in the After Dialog Validate server-side event handler.

 

CSS Editor - Source View - Quick Navigator - When you are editing CSS in the Source tab of the CSS editor, the toolbar now has a quick selector that allows you to quickly jump to any rule. For example in the screenshot below, clicking on the down arrow icon in the status bar has opened a menu showing all of the selectors in the code being edited.

 

JSON_standardize() function - Takes non-standard JSON and standardizes it. Also corrects for trailing commas in the JSON (which are illegal)

 

For example:

 

?json_standardize("{name: 'Fred', age: 21}")

 {
"name": "Fred",
"age": 21
}

 

?json_standardize("{name: 'Fred', age: 21,}")

 {
"name": "Fred",
"age": 21
}
 


 

UX Component - {dialog.object}.destroyChildComponent() Method - A common pattern when building large mobile applications is to break the app into multiple sub-component which are called from a master component.

Once the child component is no longer needed, it is useful to be able to delete the component from memory in order to conserve the limited memory available in the browser.

The {dialog.object}.destroyChildComponent() method can be used to delete child UX components from memory.

Watch Video

 

 

UX Component - List Control - Column Resizing - You can now specify that individual columns in the List can be resized by the user at run-time. To specify that a column can be resized, check the 'Resizable column' property.

 

 

Watch Video

UX Component - Customize Scroll Indicator - List, Panel and Containers - You can now customer the scroll indicator for List controls, Panels and Containers. By default the scroll indicator for vertical scrolled content is on the right edge and the for horizontally scrolled content, it is on the top. However, you can set the position to left or bottom, and you can control the class and various offsets.

In the image below, the scroll indicator is shown on the left edge with a 20px offset.

 

 

 

To open the scroll indicator customization dialog, click the smart field button:

 

 

 

 

Client-side Templates - Allows you to merge complex Javascript data in richly formatted templates to produce HTML that can be displayed in a UX or Grid component.

 

NOTE: A powerful tool is available when you working with templates. See section below: 'Using the Template Tester'

 

NOTE: Templates use the A5.u.template.expand() Javascript function in the Alpha Anywhere Javascript library. See section below 'The A5.u.template.expand() Function'

 

The basic idea of client-side templates is that you have some Javascript data - typically a Javascript object, or an array of Javascript objects, and a template (with placeholders for data) and you merge the data into the template.

For example, take the following trivial example. Say you have a Javascript object defined as follows:

var data = {Firstname: 'Fred', Lastname: 'Jones'};

 

And a template defined as follows:

var template = 'Hello {Firstname} {Lastname}';

 

When you merge the data into the template, you will get a string that looks like this:

Hello Fred Jones

 

Technical Note: The syntax for the template is identical to the syntax for free-form templates in the List control and for individual columns in a columnar List control.

Of course, in a real application the template will likely also include HTML markup. For example:

var template = 'Hello {Firstname} <span class="class1">{Lastname}</span>';

 

Array Data

The data for the template can be an array of objects, in which case the template will be expanded for each object in the array.

For example:

var data = [

    {Firstname: 'Fred',  Lastname: 'Jones'},

    {Firstname: 'John',  Lastname: 'Smith'},

    {Firstname: 'Sally', Lastname: 'Rome'}

];

 

Using the same template as above, this will produce this output:

Hello Fred Jones

Hello John Smith

Hello Sally Rome

 

Object Data

The data object can include sub-objects. For example

var data = {Firstname: 'Fred', Lastname: 'Jones', Address: { Street: '123 Main St', City: 'Boston', State: 'Ma' }};

 

The template to consume this data could then be defined as follows:

var template = 'Hello {Firstname} from {Address.Street} in {Address.City}';

 

Alternatively, the template could be defined as follows:

var template = 'Hello {Firstname} from {Address} {Street} in {City} {/Address}';

 

Notice that the template includes {Address} and {/Address}. Inside the {Address} block, the placeholders do not need to be fully qualified. You can use {Street}, rather than {Address.Street}

The {Address} placeholder is referred to as a 'scope' placeholder.

Both of these templates will produce the same output:

Hello Fred from 123 Main St in Boston

 

Array Data and Object Data Combined

In the Array Data example above, the data was in the form of a Javascript array. In many cases it will be preferable have the data as an object. So, instead of specifying the data for the template as:

var data = [

    {Firstname: 'Fred',  Lastname: 'Jones'},

    {Firstname: 'John',  Lastname: 'Smith'},

    {Firstname: 'Sally', Lastname: 'Rome'}

]

 

You could specify it as:

var data = {

    Customers: [

        {Firstname: 'Fred',  Lastname: 'Jones'},

        {Firstname: 'John',  Lastname: 'Smith'},

        {Firstname: 'Sally', Lastname: 'Rome'}

    ]

}

 

The template to consume this data could then be defined as:

   

var arr = [];

arr.push('{Customers}');

arr.push('Hello {Firstname} {Lastname}');

arr.push('{/Customers}');

var template = arr.join('\n');

 

NOTE: The template is created by pushing individual lines into a Javascript array and then joining the array. This is simply a convenient technique for creating long strings in Javascript.

 

This template will produce this output:

Hello Fred Jones

Hello John Smith

Hello Sally Rome

 

Notice that since the {Firstname} and {Lastname} placeholders are nested inside the {Customer}...{/Customer} scope placeholders, it is not necessary to use fully qualified placecholders (e.g. {Customer.Firstname}).

 

The benefit of placing your array as a property of an object, rather than at the top level, is that you can then use the {*header} and {*footer} constructs, and you can compute summary information (such as the number of items in the array, an average value of a field in the array, etc).

 

Client-side Template Syntax

There are a rich set of template directives that make templates both extremely powerful and also easy to use.

 

 

{scope} Placeholders

If the data passed to the template expand function contains nested objects, or arrays, you can use special {scope} placeholders, where scope is the name of nested object or array.

For example, consider the following simple data object:

{name: 'John Smith', address: {street: '1 Main', city: 'Boston'}}

The template to print this could be:

{name}

{address.street}

{address.city}

 

or more conveniently, a {scope} variable could be used:

{name}

{address}

{street}

{city}

{/address}

The {scope} variable acts like an 'with' statement in Xbasic.

Within the {scope}, it is not necessary to fully qualify the placeholder names.

In the case where the data contains a nested array, the {scope} variable indicates that the template should loop over the rows in the array.

For example, consider this data object:

[

    {name: 'John Smith', children: [{name: 'Griffin'}, {name: 'Callie'}]},

    {name: 'Toby Mohan, children: [{name: 'Kyle'}, {name: 'Katy', name: 'Luke'}]}

]

And the following template:

{name}<br>
<ul>
    {children}
        <li>{name}</li>
    {/children}<br>
</ul>
 

  Which will produce this output:

 

John Smith
Toby Mohan

 

{[value]} Placeholder

The {[value]} Placeholder is a special placeholder to use when looping over arrays of values, rather than arrays of objects.

In the previous example, the data was specified as:

 

[

    {name: 'John Smith', children: [{name: 'Griffin'}, {name: 'Callie'}]},

    {name: 'Toby Mohan, children: [{name: 'Kyle'}, {name: 'Katy', name: 'Luke'}]}

]

 

The nested array is an array of objects.

However, the data could have been specified as:

 

[

    {name: 'John Smith', children: 'Griffin','Callie']  },

    {name: 'Toby Mohan, children: ['Kyle', 'Katy','Luke']}

]

In this case, the nested array is an array of values, not of objects.

To emit the data in the array, the template must use the special {[value]} placeholder. For example:

{name}<br>
<ul>
    {children}
        <li>{[value]}</li>
    {/children}<br>
</ul>
 

 

NOTE: The [value] field can be followed by formatting directives, just like any other field. For example:
{[value]:number('$#,###.00')}

 

Missing Data - Alternative Text - The || Directive

In some cases the data you pass in to the template expander will have missing data. For example, consider the following data object:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', city: 'Boston'},
        {firstname: 'Laura', lastname: 'Linneker'}
    ]
}

 

The 'city' property has been specified for the first object in the 'employees' array, but not the second.

 

{employees}
    Employee name: <b>{firstname} {lastname}</b> City: {city||Not available}<br>
{/employees}

 

The text to display for a missing value is specified in the placeholder after a || delimiter. In the template shown above, the missing text for the {City} property has been specified as 'Not available'.

The above template will render as follows

Employee name: Fred Smith City: Boston

Employee name: Laura Linneker City: Not available

 

NOTE: The missing data directive can be combined with formatting directives. For example:  {price:number('#.00')||N/A}

 


 

 

Headers and Footer - {*header} / {*footer}

Headers and Footer can be used if the data object you pass into to the template expander contains array data.

For example, assume the data object looks like this:

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith'},
        {firstname: 'Laura', lastname: 'Linneker'}
    ]
}

 

And the template looks like this:

 

{employees}
    {*header}
        This is the header - it prints before the first item in the array.<br>
    {/*header}
    Employee name: <b>{firstname} {lastname}</b><br>
    {*footer}
        This is the footer - it prints after the last item in the array
    {/*footer}
{/employees}
 

The merged data will look like this:

 

This is the header - it prints before the first item in the array.
Employee name: Fred Smith
Employee name: Laura Linneker
This is the footer - it prints after the last item in the array

 

Empty Arrays - Alternative Text - {*empty}

If an array does not contain any entries you can specify alternative text to display.

 

For example, consider the following sample data:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', skills: [ {name: 'Javascript'},{name: 'CSS'}]},
        {firstname: 'Laura', lastname: 'Linneker', skills: [{name: 'Xbasic'}]},
        {firstname: 'Junior', lastname: 'Programmer', skills: [] }
    ]
}

 

Notice that only the last array instances does not have any rows in the skills array.

The template might be defined as follows:

 

{employees}
    Employee name: <b>{firstname} {lastname}</b><br>
    <div style="border:solid 1px green; margin-left:50px;">
        {skills}
            {*empty}
                No skills yet
            {/*empty}
            Skill Name: {name}<br>
            {*footer}
                <i>Count of skills: {@countSkills}</i>
            {/*footer}
        {/skills}
    </div>
{/employees}
 

The Javascript function for the countSkills function (called by the {@countSkills} directive) is:

 

function countSkills(data,context) {
    return data[context].length;
}
 

 

The merged data looks like this:

 

Employee name: Fred Smith
Skill Name: Javascript
Skill Name: CSS
Count of skills: 2
Employee name: Laura Linneker
Skill Name: Xbasic
Count of skills: 1
Employee name: Junior Programmer
No skills yet

 

Conditional Sections - {*if logicalExpression}, (*endif}

Templates can include conditional sections. Conditional sections are defined using the following template commands:

where logicalExpression is any Javascript expression that evaluates to a true/false value.

The logicalExpression can refer to data in the current 'row' of data.

For example, consider the following data:

 

{
    employees: [
        {firstname: 'Fred', lastname: 'Smith', state: 'MA'},
        {firstname: 'Laura', lastname: 'Linneker', state: 'CA'},
        {firstname: 'Junior', lastname: 'Programmer', state: 'MA'},
        {firstname: 'Bill', lastname: 'Lindsey', state: 'NY'}
    ]
}
 

And the following template:

 

{employees}
    Employee name: {[countOneBased]} <b>{firstname} {lastname}</b><br>
    <div style="border: solid 1px blue; margin-left:20px; margin-bottom: 10px;">
        {*if state=='MA'}
            Employee is based in MA
        {*elseif state=='CA'}
            Employee is based in CA
        {*else}
            Employee is not based in MA or CA
        {*endif}<br>
    </div>
{/employees}

 

The merged data looks like this:

 

Employee name: 1 Fred Smith
Employee is based in MA
Employee name: 2 Laura Linneker
Employee is based in CA
Employee name: 3 Junior Programmer
Employee is based in MA
Employee name: 4 Bill Lindsey
Employee is not based in MA or CA

 

Formatting Directives

You can include formatting directives in the template placeholder to format numeric values and strings, and to format date values.

To format a numeric value, use the :number(formattingDefinition) directive in your placeholder.

For example, assume you have a field called Price, which contains this value: 123456.345.

You might define the template to emit this field as follows:

{Price:number('$#,###.00')}

 

This will result in the following output:

$123,456.35

 

You can also use the :number() directive to merge strings into templates. For example,, assume that you have a field called Phone, which contains 6715551234.

The placeholder for this field in your template could be defined as:

{Phone:number('=(###) ###-####')}

 

This will result in the following output:

(617) 555-1234

 

 

To format a date value, use the :date(formattingDefinition) directive in your placeholder.

You can use the following symbols in the formattingDirective.

You can also use the :uppercase and :lowercase directives to force string values to upper or lower case.

For example:

{name:uppercase}

{name:lowercase}

 

 

NOTE: The missing data directive can be combined with formatting directives. For example:  {price:number('#.00')||N/A}

 

 

Expressions - {expression}

The placeholders in a template can be arbitrary Javascript expressions.

For example, assume that you have the following data and template:

{product: 'Book', qty: 4, price: 23}

 

Template:

Product: {product.toUpperCase()} - Price: {price}, Quantity: {qty} - Total: {price * total:number('$#,###.00')}

 

Result:

BOOK - Price 23, Quantity: 4 - Total $92.00

 

Functions - {@JavascriptFunctionName}

Your template can include calls to Javascript functions that compute values based on data in the current 'row'. To call a function you use the {@JavascriptFunctionName} placeholder in your template, where JavascriptFunctionName is the name of the Javascript function that you want to call.

The value returned by the function is emitted for the placeholder.

The Javascript function takes a single parameter, data, which allows you to reference data from the current row.

Consider the following simple data object:

{firstname: 'John', lastname: 'Smith'}

And the following template:

Hello {@fullname}

 

The fullname Javascript function might be defined as:

function fullname(data) {

    return data.firstname + ' ' + data.lastname.toUpperCase();

}

 

The template result for the above data, template and Javascript function will be:

Hello John SMITH

 

Functions can also be used to compute summary data. For example, assume that the data object you define includes an array of data. You might want to output summary data that includes (say) the count of the number of rows in the array and the total of one of the fields in the array.

Consider the following sample data object:

{

    customer: [

        {name: 'Smith', amountDue: 345.34},

        {name: 'Jones', amountDue: 35.43},

        {name: 'King', amountDue: 45.14}

    ]

}

 

And the following template:

{customer}

    {name} - {amountDue}<br>

    {*footer}

        Total amount due: {@amountDue} from {@count} customers.

    {/*footer}

{/customer}

 

And the following definition for the 'amountDue' and 'count'  javascript function:

 

function amountDue(data,scope) {
    var arr = data[scope]
    var tot = 0;
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amountDue;
    }
    return $u.n.round(tot,2);
}

 

function count(data,scope) {

    return data[scope].length;

}
 

 

 

The above will produce this output:

Smith - 345.34

Jones - 35.43

King - 45.14

Total amount due: 425.91 from 3 customers.

 

In the above example, notice that the 'amountDue' and 'count' functions are in the {*footer}..{/*footer} block inside the {customer}..{/customer} scope. When the Javascript functions are called from inside a {*header} or {*footer} block the scope ('customer') is passed into the function along with the data. ('data' is the first argument, and 'scope' is the second argument).

What's in the 'data' object passed into a Javascript function depends on where the Javascript function is called from.

If a Javascript function is called from within a {*header} or {*footer} placeholder the data in the data object will be the same as if the function had been called from outside the scope. In other words, if the template has {@myfunction} after the closing {/customer} placeholder, the data passed to the 'myfunction' Javascript function will be the same as the data that would be passed to the function had it been called from inside a {*header} or {*footer} block inside the scope (e.g. {customer}...{/customer}.

On the other had, if the {@myfunction} placeholder is used anywhere within the scope (e.g. inside the {customer} ..{/customer} block), but not inside a {*header} or {*footer} block, the data object only contains data for the current array instance and the 'scope' value is blank.

The following example will help make this clear:

 

Data:

{
    customer: [
        {name: 'Smith', amountDue: 345.34},
        {name: 'Jones', amountDue: 35.43},
        {name: 'King', amountDue: 45.14}
    ]
}
 

 

Template:

{customer}
    {name} - {amountDue} - {@data}<br>
    {*footer}
        In footer:<br>{@data}
    {/*footer}
{/customer}
<br>
Outside the 'Customer' scope: {@data}

 

 

Javascript function:


function data(data,scope) {
    if(scope == '') scope = 'BLANK';
    var json = JSON.stringify(data,'\t');
    var msg = '<div style="border: solid 1px red;"><b>scope</b>: ' + scope +       

                '<br><b>data</b>: ' + json + '</div>';
    return msg;
}

 

The above produces this output:

 

Smith - 345.34 -
scope: BLANK
data: {"name":"Smith","amountDue":345.34}

Jones - 35.43 -
scope: BLANK
data: {"name":"Jones","amountDue":35.43}

King - 45.14 -
scope: BLANK
data: {"name":"King","amountDue":45.14}

In footer:
scope: customer
data: {"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

Outside the 'Customer' scope:
scope: BLANK
data: {"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

 

Note that the 'data' Javascript function simply shows the data that is passed into the function (as a JSON string) and also shows the value of the 'scope' argument

 

The 'data' function is called in 3 different places:

As show, inside the {customer} scope, the data passed into the function is just the data for the current array instance and the 'scope' passed into the function is blank.

However, when the Javascript function is called from inside the {*footer} block, the data and scope passed into the function are the same as if the function had been called from outside the {customer} scope. In this case the data passed into the function includes all of the data in the scope.

 

With the above understanding of the what's passed into the Javascript function, let's re-examine the 'amountDue' and 'count' functions from the previous example. Here is the function definition again:

 

function amountDue(data,scope) {

    var arr = data[scope]
    var tot = 0;
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amountDue;
    }
    return $u.n.round(tot,2);
}

 

The amountDue function has been called from inside a {*footer} construct. Therefore the data passed into the function looks like this (in JSON format)

{"customer":[{"name":"Smith","amountDue":345.34},{"name":"Jones","amountDue":35.43},{"name":"King","amountDue":45.14}]}

 

Therefore we can get the array of data shown in the {customer} scope by using this Javascript statement:

data['customer']

 

However, the 'scope' variable that was also passed into the function contains 'customer', so we can get the array of data as follows:

data[scope]

 

Once we have the array of data, it is a simple matter of writing a Javascript loop to sum up the value in the 'amountDue' property for each row in the array.

Note that before we return the number we use the $u.n.round() function from the Alpha Anywhere Javascript library to round the result to 2 decimal places.

The 'count' function is even simpler. We simply return the length of the array.

 

function count(data,scope) {

    return data[scope].length;

}
 

 

 

Here is a more complex example that shows an object with two arrays of data - 'charges' and 'payments'. Our template shows the total charges, total payments, and the net amount due (total charges - total payments)

 

Here is the data:

 

{
    charges: [
        {name: 'Smith', amount: 345.34},
        {name: 'Jones', amount: 35.43},
        {name: 'King', amount: 45.14}
      ],
    payments: [
        {name: 'Smith', amount: 123.34},
        {name: 'Jones', amount: 45.45}
        ]
}
 

 

Here is the template:

 

<b>Charges</b><br>
{charges}
    {name}<br>
    {*footer}
        Total charges: {@totaldue}
    {/*footer}
{/charges}<br>
 

<br>
<b>Payments</b><br>
{payments}
    {name}<br>
    {*footer}
        Total payments: {@totaldue}
    {/*footer}
{/payments}<br>
<br>
Net amount due: {@netdue}

 

Here is the Javascript:

function totaldue(data,context) {
    var tot = 0;
    var arr = data[context];
    for(var i = 0; i < arr.length; i++) {
        tot = tot + arr[i].amount;
    }
    return tot.toFormat('$#,###.00');
}

function netdue(data,context) {
    var arr = data['charges'];
    var totDue = 0;
    for(var i = 0; i < arr.length; i++) {
        totDue = totDue + arr[i].amount;
    }

    arr = data['payments'];
    var totPay = 0;
    for(var i = 0; i < arr.length; i++) {
        totPay = totPay + arr[i].amount;
    }

    var netDue = totDue - totPay;
    return netDue.toFormat('$#,###.00');

}

 

 

And here is output produced by this template:

 

Charges
Smith
Jones
King
Total charges: $425.91

Payments
Smith
Jones
Total charges: $168.79

Net amount due: $257.12

 

Notice in the above example that the same 'totalDue' function can be used to return both the total charges and the total payments (because in the first case the 'scope' passed into the function will be 'charges' and in the second case, the 'scope' passed into the function will be 'payments'.

The 'netDue' function that called from outside both the 'charges' and 'payments' scope gets called with the data for both arrays. This function gets the charges array using this syntax:

data['charges']

and then computes the total charges.

Then it gets the payments array, using this syntax:

data['payments']

and then computes the total payments.

Once the total charges and total payments are computed, the net amount due can be computed.

 

Using the [] directive to emit array instance data

 

When you are outside a scope that references array data, you can use a special syntax in the scope placeholder to display values from the scoped array.

For example, consider the following output from a template:

 

 

Showing employees from: 'Smith' to 'Programmer'
Employees

Employee name: 1 Fred Smith
skillName: 1 Javascript
skillName: 2 CSS
Count of skills: 2
Employee name: 2 Laura Linneker
skillName: 1 Xbasic
Count of skills: 1
Employee name: 3 Junior Programmer
No skills yet

 

Notice that before the Employees are shown, the template shows:

Showing employees from: 'Smith' to 'Programmer'
 

Where 'Smith' is a value from the first row in the array, and 'Programmer' is a value from the last row in the array.

In the above example, the following template was defined:

 

Showing employees from: '{employees[0].lastname}' to '{employees[-1].lastname}' <br>

{employees}

    {*header}
        <b>Employees</b><br>
    {/*header}
    Employee name: {[countOneBased]} <b>{firstname} {lastname}</b><br>
    <div style="border:solid 1px green; margin-left:50px;">
        {skills}
            {*empty}
                No skills yet
            {/*empty}
            skillName: {[countOneBased]} {name}<br>
            {*footer}
                <i>Count of skills: {@countSkills}</i>
            {/*footer}
        {/skills}
    </div>
{/employees}
 

 

Notice that outside the {employees} scope, the following template directives can be used to emit data from the employees array:

{employees[0].lastname} - 'lastname' property from the 1st array instance.

{employees[-1].lastname} - 'lastname' property from the last array instance.

 

Partial Templates - {*partial partialName}

Partial templates are named sub-templates. A template can reference these partial templates using the {*partial partialName} command. This is useful if a template has text that is repeated. For example, consider the following Javascript code:

 

//define the data

var _d = {firstname: 'Fred', lastname: 'Smith'}

 

//define the template

var arr = [];

arr.push('Welcome<br>');

arr.push('Hello {firstname} {lastname}<br>');

arr.push('{*partial partial1}');

 

var _t = arr.join('\n');

                        

 

//define the settings object (template and partials)

var settings = {
    template: _t,
    partials: {
        partial1: 'from partial1: {firstname} {lastname}<br>'
    }
}

 

//merge the data into the template

var html = A5.u.template.expand(_d,settings);

 

 

This will produce the following output:

Welcome

Hello Fred Smith

from partial1: Fred Smith

 

 

 

NOTE: Several powerful new features for templates have been added in Alpha Anywhere V3. Please consult the Release Notes for additional information.

 

 

Using the Template Tester - The Template Tester is a powerful tool to help you design and test templates.

To open the Template Tester select the Tools menu when the Web Control Panel has focus and then select the 'JSON Data Template tester' command.

This will open a modeless window where you can enter test JSON data, template definitions and Javascript functions and then see the results in real-time.

 

NOTE: The Template Tester can also be opened from within the List control builder when you are defining a template for a column in a columnar list or you are defining a free-form template.

 

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

 

 

 

You can also click the 'Load Example' button to open a menu showing several different examples that illustrate different concepts.

 

 

 

 

Whenever you open the Template Tester, the text that you had last entered is automatically restored.

 

The A5.u.template.expand() Javascript Function - Templates are expanded using the A5.u.template.expand() Javascript function, which is part of the Alpha Anywhere Javascript library.

The syntax is

var html = A5.u.template.expand(data,settings);

 

Where data is a the data array or object to be merged into the template and settings defines the template (and any partial templates).

For example:

 

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var settings = {

    template: template,

    partials: ''

}

var html = A5.u.template.expand(data,settings)

 

 

NOTE: For an example that uses partials, see 'Partial Templates - {*partial partialName}' above.

 

A5.u.template.parse() Function - If a template is used multiple times in a component, you can pre-parse the template so that when the template needs to be expanded you can use the pre-parsed template for improved performance.

For example, take the following Javascript:

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var settings = {

    template: template,

    partials: ''

}

var html = A5.u.template.expand(data,settings)

 

The could be re-factored as follows:

 

var data = {firstname: 'Fred', lastname: 'Smith'};

var template = 'Hello {firstname} {lastname}';

var parsedTemplate = A5.u.template.parse(template);

var settings = {

    template: parsedTemplate,

    partials: ''

}

 

var html = A5.u.template.expand(data,settings)

 

 

 

 

Action Javascript - Templates - Merge data into client-side template' Action - This action allows you to define a data and a template, merge the data into the template and then set the innerHTML of a div, placeholder control, or Panel with the resulting HTML.

 


Watch Video
Download Component

 

 

When you open the builder, the genie shows this screen:

 

 

You can either specify static data to merge into the template, or you can specify the name of a Javascript function that will return the data to merge into the template.

Similarly, you can specify a static template, or the name of a Javascript function that will dynamically create the template.

 

Using Client-side Templates on the Server-side - a5_merge_JSON_into_template() Function -  Because Alpha Anywhere has the ability to execute Javascript from an Xbasic script, you can actually use client-side templates in Xbasic using the a5_merge_JSON_into_template() function.

The syntax for the function is:

c Result = a5_merge_JSON_into_template(C jsonData ,C template [,C javascriptFunctions [,C partialTemplatesJSON [,C localCSS ]]])
 

For example:

 

dim data as c
data = <<%txt%
{firstname: 'Fred', lastname: 'Jones'}
%txt%

template = <<%html%
Name: {firstname} {lastname}
%html%

htmlOut = a5_merge_JSON_into_template(data,template)

showvar(htmlOut)
 

 

 

 

{grid.object}.getRowsInGrid() Method - Returns the number of rows in the current page of the grid. This is not the same as the number of rows in the Grid query.

Previously, users were using the internal ._rowsInGrid property to get the number of rows in the current page, but this value includes rows that have been deleted.

For example, say that the Grid is set to show 10 rows per page and that the refresh method is set to 'Auto' and that a minimal refresh is done after update, insert and delete operations.

If the user deletes a row from the Grid, the ._rowsInGrid property will still be 10, because the deleted row is not really deleted from the current page - it is just hidden and marked as deleted.

On the other hand, the {grid.object}.getRowsInGrid() method will return 9.

 

 

{grid.object}.getSelectedRow() Method - Returns the selected row number, or null if no row is selected.

Previously, users were using the internal ._selectedRow property to get the row number of the currently selected row. However, under some circumstances this property can return a confusing (but technically correct) value.

For example, if the refresh method on the Grid is set to 'Auto' and a minimal refresh is done after an update, insert or delete operation and the user deletes a row, the ._selectedRow property will return the row number of the row that was just deleted (which is actually correct internally, because the row that was deleted has simply been hidden in the page and it is still marked as selected).

On the other hand. the {grid.object}.getSelectedRow() method will return null, indicating that no row is currently selected.

 

 

 

UX Component - List Control - List Preview - Modeless - The List Builder has a 'Preview' button to do a quick preview of the List control while you are in the List builder. The Preview window is now modeless - which means you can keep it open while you are working in the List builder (and perhaps move it to a second screen if your computer has two monitors). This makes it very convenient to preview the List after every change you make.

Watch Video

 

UX Component - List Virtualization - Normally, when a List control is populated, the HTML for all of the rows in the List is rendered. If the list only has a few rows (say 200 rows), then there is no noticeable delay while the List is populated.

However, if the List has a lot of rows (say several thousand rows), then there will be a noticeable delay while the List is populated and also, a large amount of memory will be consumed by the List. On a mobile device where memory is more limited, the amount of memory consumed by the List could be a problem.

List virtualization allows you to only create HTML elements for a portion of the List - the portion that is currently visible and some additional rows above and below the currently visible portion. The number of rows that are rendered in the List is called the 'page' size.

When the user is scrolling the List and they hit a page boundary, the user can tap on a Next or Previous button (or optionally use a pull/release gesture) to populate the List with the next or previous page of data. It is important to recognize that tapping the Next or Previous button does not trigger an Ajax callback. It is simply rendering the next or previous page of data using the data that has already been loaded into the List and is in memory. Therefore, the time take to populate the next or previous page is practically instantaneous.

The advantage of virtualizing the List is that you can dramatically reduce the time taken to load large Lists and you can reduce the memory footprint of the List.

To turn on List Virtualization, set the Virtualization type property shown below to 'Dynamic'.

 

Watch Video
Download component

 

Once you do this, several additional properties will be shown

 

 

Virtualization type - Set to 'None' to turn virtualization off. Set to 'Dynamic' to turn virtualization on.

Size - The size property defines the 'page' size - the number of rows of data that should be rendered. This should typically be a multiple of the number of rows in the viewport. For example, say that your List can display 20 rows of data at a time, you might set the size to (say) 100 so that the user can scroll a fair amount before hitting the page boundary.

When you reach a page boundary (either on top or bottom of the page), there are 'Next' and 'Previous' buttons to get the next logical 'page' of data. The user can either tap on the Next/Previous button, or use a pull/release action to fetch the next page of data.

Max size - This is an advanced optional setting that can be used to specify a type of 'hybrid' virtualization. By default, this property is set to 0, which means that the number of rows that the List renders is always equal to the 'page' size. When you hit a page boundary, the current page is memory is replaced by the next page that is loaded.

However, if you set the Max size to -1 (which indicates that the max size is equal to the number of rows in the List), or some positive number that is greater than the size property, then when you are navigating forward and you hit a page boundary, the next page of data is automatically rendered (without requiring the user to tap the Next button). The number of rows in memory continues to grow as the user scrolls down in the List. In other words, the memory consumed by the List is initially very small (as only a single page of data are rendered) and the time taken to render the List is optimized (again, because only a single page of data are rendered), but as the user scrolls, the number of rendered rows in the List continue to grow and more memory is consumed. When the 'max size' is reached, then the user will then have to use the 'Next' button to continue to viewing additional records.

Offset - When you hit a page boundary, and click the Next/Previous button, the 'offset' indicates the number of rows from the page that is being discarded that should be included in the new view. If this number is less than the number of rows in the viewport, the List will appear to 'jump' when you navigate to a new page. It is recommended that this value be set to a minimum of the number or records that can be seen in the viewport at one time so that when the user taps the Next/Previous button, the scroll position of the List does not change. It is recommended that this number be no more than half of the 'page size'. The larger the number, the more rows the user can scroll backwards before hitting the Next/Previous buttons.


Navigate on pull - Allows the user to pull/release to navigate (in addition to tapping on the Next/Previous buttons).

Pull size - Number of pixels before the 'pull/release' gesture is recognized as a 'navigate' action.

 

 

UX Component - List Control - onBeforePopulate and onPopulate Client-side events - Two new client-side events have been added to the List control.

onBeforePopulate - fires before the List is populated. Allows you to transform the data that will be used to populate the List. The event handler gets passed in 'data' - an array with all of the data for the List.

onPopulate - fires after the List has been populated.

UX Component - List Control - Transform Data Type - Unless the List data source is a Javascript function (in which case you have complete control over the data types for each field in the List), all data in the List are string values.

 

Watch Video
Download component
 

The 'Transform data type' property allows you to transform the data type of the data in a List column to a Date, Numeric, or Logical data type.

To transform the data type, set the option in the 'Transform data type' property on the Fields pane in the List builder (as shown below).

 

 

The benefit of transforming dates into true date objects and numbers into true number objects is that you can then use the template formatting options to format date or numeric values.

For example, the template for a date field might be specfied as:

{DateOfBirth:date('MM-dd-yyyy')}

or a numeric field, the template might be specified as:

{Price:number('$# ###.00')}
 

NOTE: It is not strictly necessary to transform a string to a number in order to use the number format directive in the template. The sample template shown above ( {Price:number('$# ###.00')} would actually also work on a string value that contained a valid number.

 

 

Property Grids - Font Size - Property Grids are ubiquitous in the Alpha Anywhere builders. You can now change the default font size by selecting the View, Settings... menu item. Select the 'System Font's pane and then the 'Property Grid' category.

 

 

 

The image below shows a Property Grid with a 12 point font size:

 

 

 

word_i() function - A case-insensitive version of the word() function

Example

?word_i("alpha software corp",2,"SOFTWARE")

= "corp"

 

Web Applications - Session Object - .SaveSessionFileToFile() - A new method on the session object allows you to save a file that as previously stored as a session file to a permanent location.

The syntax is

session.saveSessionFileToFile(c Key, C DestinationFile)

 

Note: The session file might have been created in the first place using either of these methods:

 

session.saveFileToSessionFile( c fileName, c key)

 

session.saveDataAsFile( b data, c key)

 

 

Storage - Storage is an Alpha Anywhere abstraction for dealing with different types of storage using a standard interface. Currently, 3 type of storage are supported - Amazon S3, Azure and Disk storage.

Storage is used for storing files.

To work with Storage you will need a storage connection string to 'connect' to the storage object.

Named connection strings are typically used (in much the same way that named AlphaDAO connection strings are used when you connect to a SQL database).

To create a named storage connection string, select the Tools, Storage Connection strings menu item from the Tools menu when the Web Control Panel has focus.

 

 

This will open a dialog where you can create as many named storage connection strings as you want.

 

When you create or edit a named storage connection string, the Connection String dialog is shown:

 

 

Named storage connection strings are published in the a5_application.a5i file when you publish your application.

 

Summary of Helper Functions for Working with Storage - Several Xbasic helper functions make it easy to work with the storage. These helper functions are written on top of the low level storage objects that are documented here.

 

 

The helper functions are:

Examples for each of these functions is shown below.

 

 

a5Storage_saveFile() - Saves a file to storage

Syntax:

L a5Storage_saveFile(C connectionString ,C filename ,C itemName [,C mimeType [,* pResult ]] )
 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

filename - name of the local file to save in storage.

itemName - name of the object in storage. You can can specify a logical folder by using forward slashes in the name. For example: image/image1.jpg

mimeType - the mime type of the object. If you don't specify this property, the value can be inferred from the extension you assign to the itemName property.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

Example:


dim pr as p
flag = a5Storage_saveFile("::storage::Amazon_East","c:\images\4290.jpg","movies/4290.jpg","",pr)

?flag

= .T.
 

If you examine the pr dot variable that was passed into the function you will see the following properties:

hasError = .f.
timeTakenMilliseconds  = 239
AbsolutePath  = "https://<bucketName>.s3.amazonaws.com/movies/4290.jpg"
ContentType  = "image/jpeg"
ModifiedTime  = CTODT('03/15/2014 01:53:13 00 pm')
Name  = "movies/4290.jpg"
size  = 5880

 

The AbsolutePath property gives you a URL to the object. Note that in order for this URL to work you need to make sure that you have set the appropriate permissions on the storage container ('bucket' in S3 terminology).

 

 

a5Storage_saveData() - Saves data to storage

Syntax:

L a5Storage_saveData(C connectionString ,b blob ,C itemName [,C mimeType [,* pResult ]])

 

Same as a5Storage_saveFile(), except takes a blob as input rather than a filename.

 

A5Storage_getItemProperties() - Gets properties of an item in storage

Syntax:

P itemProperties = a5Storage_getItemProperties(C connectionString , C itemName)

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

 

 

Returns a dot variable with these properties

 

 

a5Storage_getItem_as_blob() - Retries data from an item in storage and put the data in a blob variable

Syntax:

b blob = a5Storage_getItem_as_blob(C connectionString ,C itemName [,* pResult ])

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 


 

Example:

dim p3 as p
b3 = a5Storage_getItem_as_blob("::storage::Amazon_East","movies/4290.jpg",p3)
?b3.size()
?p3
'= contentType = "image/jpeg"
timeTakenMilliseconds = 297
 

 

a5Storage_getItem_as_file() - Retries data from an item in storage and create a local file

Syntax

L flag = a5Storage_getItem_as_file(C connectionString ,C itemName,  C filename  [,* pResult ])

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 


 

a5Storage_listItems() - Lists items in storage

Syntax:

c List = a5Storage_listItems(C connectionString [, C searchPrefix [,* pResult ]])

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

a5Storage_deleteItem() - Delete an item from storage

Syntax:

L flag = a5Storage_deleteItem(C connectionString, C itemName [,* pResult ])

 

 

Where:

connectionString - Storage connection string with ::storage:: as a prefix.

itemName - name of item to delete

pResult - an optional dot variable that you can pass in that will be populated with information about the object.

 

Note: The flag value returned by this function is .f. if the connection failed, but is .t. if the item was not found in storage.

 

 

 

Web Applications - .A5W Pages - Debugging - You can now debug live running .A5w pages from within the HTML editor. The editor now has a new 'Live Preview' tab.

Simply insert a debug(1) statement in your Xbasic code and then switch to the 'Live Preview' tab pane.

 

 

UX Component - Pop-up Javascript Windows - Customize Title Direction - A new property has been added to set the default title direction for pop-up Javascript windows. By default, the direction is 'ltr' (left to right), but the direction can now also be set to 'rtl' (right to left - title on right and close button on left).

 

 

Grid Component and UX Component - Image and File Upload - Show Progress and Allow Cancel - The image and file upload features in the UX and Grid components have been enhanced.

The image below shows the File Upload window showing progress as a large file is uploaded.

 

You can now:

In order to enable this new functionality, edit your Image Upload, File Upload or File Upload - User Defined actions (defined using Action Javascript) and set the properties shown below.

 

 

 

In the case of the 'File Upload - User Defined' when the 'Allow multiple files' option is selected, the size check that takes place before the upload begins is the combined size of all selected files. You can set the maximum combined size property in the builder. The 'Maximum file size' property which applies to individual files will also be enforced after all of the files have been uploaded.

 

 

 

The Action Javascript builders allows you to specify the style for the progress bar. The 'A5' style blends in nicely with the component style, but for older styles, such as GrBlue, GrOlive, etc. the 'A5' style might be too subtle for your taste and you might prefer to use the 'Basic' style, wich uses a standard HTML progress element.

The image below shows how the slider is rendered using the 'A5' option (first slider - using the iOS style) and the 'Basic' option (second slider).

 

 

 

Grid and UX Component - HTML Editor - File and Image Upload - The File and Image upload features in the HTML editor have been enhanced.

You can now:

 

 

UX Componet - Slider Control - Displaying Progress - A new property on the slider control has been exposed that allows you to turn off the slider handle. This is useful for displaying 'progress'. In the image below the first Slider has its handle turned off.

When you want to use the slider to show progress, you should also disable it so that the user cannot change the value by clicking on the slider. For example, enter '1=2' as the client-side Enable expression for the slider.

 

 

UX Component - Tab Control - Genie Style - Genie Button Position - When defining  'Genie Style' tab controls (shows buttons to advance through the tabs), you can now specify the button position (Above or Below the Tab Panes). Previously, the buttons were always shown below the Tab Panes.

 

 

 

 

Xdialog - Edit Combo - Case-Insensitive - The edit combo in Xdialog is case-insensitive by default. You can now force it to be case sensitive using the new %CS% flag.

For example

 

dim selected as c = ""

dim colors as c

colors = a5.color_enum()

ui_dlg_box("Select Color",<<%dlg%

Color combo: [%CS%.50selected^+colors];

Color edit-combo: [%CS%.50selected^=colors];

 

%dlg%)

 

 


 

UX Component - Abstract Events - downHold Information - Click, Tab, Swipe, Etc. events now have additional information in the event's 'abstractData' object that tells you if a 'downHold' event occurred. The motivation for this additional information is to allow you to add code to Click, Tap and other abstract events to prevent them from executing their standard code when a downHold abstract event fires.

For example, if you examine the 'e' object that is available inside the event handler for a click abstract event, you will see the following information (screen shot taken from Visual Studio Javascript debugger). As the screen shows, the e.abstractData object has a property called 'downHold'. In this case the property is true, indicating that the click event has fired as a consequence of the downHold event firing.

 

 

You might then write your click event handler as follows

 

var flagRunCode = true;

if(typeof e.abstractData != 'undefined') {

    if(e.abstractData.downHold) flagRunCode = false;

}

if(flagRunCode) {

    //code you want to run in a pure click event

}

 

Code Editors - Search and Search and Replace - Regular Expressions - The Search and Search and Replace dialogs now support the ability to use regular expression. In addition, the history feature that shows previous search and replace values is now case-sensitive.

 

UX Component - Internationalization - List Controls - The UX component Internationalization genie (described later in this document), now allows you to add language and text dictionary tags to column headings for List controls.

 

 

Xbasic - Dot Variables - .data() Method - The .data() method can be used to read the value of a property in a dot variable. However, the .data() method trims trailing spaces. Now you can use an option to preserve trailing spaces by adding the '.raw' suffix to the property name.

 

delete p
dim p as p
p.name = " "

?"a" + p.name + "b"
= "a b"

?"a" + p.data("name") + "b"
= "ab"
?"a" + p.data("name.raw") + "b"
= "a b"


 

 

UX Component - List Control - Client-side Numeric Formats - You can now specify format directives in the template for the List control. For example, the image below the template for the 'longitude' column in the List.

Watch Video

 

Notice that the placeholder in the template shows:

 

{longitude:number('#.0'}

 

The numeric format is specified in the placeholder, separated from the field name by a colon.

The builder has a link labeled 'Insert format directive' that will open a genie to help you define formatting directives.

 

NOTE: In the screenshot shown below the List is a columnar List. Client-side format directives can also be inserted into the template for Freeform Layout Lists.

 

 

 

See 'UX and Grid Component - Client-side Calculated Fields - Builder' below for more information.

 

 

Xbasic - Image Metrics Class - The new Image Metrics class gets both the pixel size and the logical size of an image.
The logical size is expressed in twips, and reflects the DPI stored with the image.


Example usage:

dim isize as Helper::ImageMetrics

isize.LoadImage("jpg",file.to_blob("C:\imgage.jpg"))

? isize

..

pixel_height = 1200

pixel_width = 1920

twip_height = 18000

twip_width = 28800

 

? *unit_convert(isize.twip_width,"tw","in")

= 20

? *unit_convert(isize.twip_height,"tw","in")

= 12.5

 

 

UX and Grid Component - Action Javascript - Open Grid - The Action Javascript to "Open a grid component" now has an option to set Autorefresh on focus if the target is a TabbedUI Pane. When checked, the content in the tab pane will be refreshed automatically every time the pane gets focus.
 

UX and Grid Component - Masks - User Defined Formats - When you define a mask for an input control in either the UX or Grid you can select from a list of built-in masks, or you can define your own mask. Now, you can add your own entries to the list of built-in masks by creating a special text file in the executable folder. The text file must be called:

 

UserDefinedMasks.txt

 

The text in the file must be of this form:
 

{data=(000) 000-0000}US Phone number

{data=000-00-0000}Social Security Number

{data=00000}Zip code - 5 digit

{data=00000-0000}Zip code - 9 digit

{data=L0L 0L0}Postal Code - Canada

 

 

UX and Grid Builder - Live Preview - Caching - Previously if you made a change to CSS or linked Javascript files after previously having done a Live Preview in the builder, the changes were not always reflected because Internet Explorer was loading assets from its cache. Now, the builder is more aggressive about not caching assets during Live Preview.

UX Component - Internationalization - In order to design a UX component that adapts automatically to different languages, you typically wrap all labels in either language tags (e.g. <a5:r> ... </a5:r>) or Text Dictionary tags (<a5:t>..</a5:t>). Adding these tags to all of the text elements (such as labels, bubble help, frame labels, etc) in a large component can be quite tedious.

A new Internationalization Utility makes it easy to retrofit an existing UX component with language or text dictionary tags.

 

Watch Video

 

To access the utility, click the Menu button, shown below.

 

 

Then, select the Internationalization Helper Utilities... menu option.

 

 

This will open a dialog that allows you to select different options. Each option generates some Xbasic code that will set properties on your UX component.

 

 

 

 

TabbedUI - onTabbedUIInitialize Server-side Event - The TabbedUI Component now has a new server-side event that fires when the TabbedUI component is initialized.

TIP: You can use this event to simulate session variables when you are in Working Preview. For example:

 

if eval_valid("request.SERVER_PROTOCOL") then
    if request.SERVER_PROTOCOL = "A5RES" then
       session.var1 = "simulated value for var1"
    end if
end if

 

UX Component - Get Online Status -  {dialog.object}._getOnlineStatus() Method -  The

{dialog.object}._getOnlineStatus() method returns true if the device has an internet connection and false if there is no connection.

NOTE:   The onConnectionChange client-side event fires when the connection state changes.

NOTE: For testing how your application will behave when there is no connection, you can set your component to simulate a disconnected state by calling the {dialog.object}._setSimulatedOnlineStatus() method.

 

UX Component - Set {dialog.object}SimulatedOnlineStatus()  Method - Allows you to force the return value from the {dialog.object}._getOnlineStatus() method to be true or false, regardless of the true state of the connection. This is useful for testing purposes when you want to test how your component behaves when it is disconnected, even though you currently have a connection.

The syntax is

{dialog.Object}._setSimulatedOnlineStatus(mode);

 

Where the mode flag is


UX Component - Client-side Events - onAjaxCallbackNotAvailable Event - A new client-side event has been defined. The onAjaxCallbackNotAvailable event fires if the user tries to execute some Javascript that does an Ajax callback and the device is not currently connected to the internet.

 

UX Component - Client-side Events - onConnectionChange Event - The onConnectionChange event fires whenever the device's connection status changes. For example if the device was online and the connection was lost, the event will fire, and vice versa.

NOTE: If you set the simulated connection status using the {dialog.object}._setSimulatedOnlineStatus() method, the event will also fire (assuming that the _setSimulatedOnlineStatus() method changed the simulated online status.

 

 

UX Component - Ajax Callback Action - Offline Javascript - A new property can be set when defining an Ajax Callback. The 'Offline Javascript' property allows you to define Javascript to be called when the device is not connected. This differs from the 'Ajax failed Javascript' property in that if the device is not connected, the Ajax callback is not even attempted, and the Javascript specified in the 'Offline Javascript' property is executed immediately.

On the other hand, the 'Ajax failed Javascript' is only fired after the timeout period if a response is not obtained from an Ajax callback.

NOTE: You can also use the new client-side onAjaxCallbackNotAvailable event to specify Javascript to execute when a user tries to make an Ajax callback and there is no connection.

 

 

 

UX Component - List Control - Filter Records - Range Searches   - Using Action Javascript, you can create actions that filter the records shown in a List control. Now, you can easily make 'range' searches (similar to the Search Part in a Grid).

Watch Video

To define a 'range' search, select the control that has the 'range start' value first. Then, check the 'Range search' checkbox. A new prompt will be shown where you can specify the name of the control that has the 'range end' value.

Range searches can also be defined for actions that search embedded grids on a UX, retrieve primary keys for a data bound UK and print embedded reports.

 

 

UX Component - Absolute Layout Containers - Save as PDF - You can now create a button using Action Javascript to save the contents of the container to a PDF file.
Watch Video

To create a button to save an Absolute Layout container as a PDF, use the 'Absolute Layout Container - Create PDF' action in Action Javascript.

After the PDF is created you have the option of either:

 

 

 

 

UX Component - Control Containers - Class Name and Prevent Float - When a UX component is rendered, every control in the component is wrapped in a DIV control that has a class of 'A5CWLayout'.

NOTE: If you have set the UX 'Layout type' property to be 'ControlWidth', then the class is A5container.

The A5CWLayout (or A5container) class has two important functions:

Under some circumstances a developer might want more control over the styling of the container (a DIV) that is used to enclose each control. Two new properties have been added for most of the controls in a UX:

 

 

The 'Control container class name' property allows you to specify the CSS class name that will be used in the container DIV in addition to the standard 'A5CWLayout' (or 'A5container') class.

The 'Control container prevent float' property allows you to specify if the container DIV will use the 'A5CWLayout' (or 'A5Container') class at all.

With these two new properties you have complete control over the styling of all controls on the UX.

NOTE: For controls that are in a 'NoFloat' container, the 'Control container prevent float' property is implicitly true.

 

 

 

UX Component - Panels - .Refresh() Method - Panel Cards and Panel Navigators now have a .refresh() method. This means that if you change the contents in the header or footer of the Panel (which might change the height of a header or footer, for example), you can now call the .refresh() method to layout out the Panel again, showing the new footer or height.

 

For example:

 

var pObj = {dialog.object}.panelGet('PANELCARD_1');

//some code to change the HTML shown in the Panel header or footer

pObj.refresh();

 

 

Xbasic - CURL - Built-in Support For CURL - CURL is a popular library for calling URLs. A genie is available to convert a CURL command that you might read in some API documentation into Xbasic. To open the CURL command to Xbasic genie, right click on whitespace in the Xbasic code editor or Interactive window. The select the CURL command to Xbasic command.

 

 

 

The genie open up and you can paste in a CURL command, then click the Generate Xbasic button.

The generated Xbasic instantiates the Curl object in the extension namespace.

 

NOTE: When using the HTTPS protocol, you must have a certificate. In the sample shown below the certificate in the CARoot folder in the Alpha Anywhere executable folder is used.

 

Grid Component - SQL - Search Part - Grids Based on GROUP BY Statements - If you have defined a Grid that is based on a SQL statement that has a GROUP BY clause, interpreting what the user intends when they do a search using the the Grid's Search Part can be tricky. For example, does the user intend the submitted search criteria to be used in a WHERE clause, or a HAVING clause?

Previously, if the Grid based based on a GROUP BY statement, the SQL generated by the Search Part was added to the HAVING clause.

Now, a more flexible approach is implemented.

When you define the Search Part in a Grid, for each field you add to the Search Part, you can define the Search Expression. The Search Expression is used in the generated SQL when the user searches on this field. If the search expression uses a summary operator (for example Sum(AmountDue) ), then a search on this field will go into the HAVING clause. On the other hand, if the Search Expression does not use a summary operator (for example, AmountDue), then a search on this field will go into the WHERE clause.

As a result of this change, you can define a Search Part in the Grid that will generate SQL statements that have both WHERE and HAVING clauses.

 

Grid and UX Component - Image and File Upload - Window Position - You can now set an explicit position for the file select window in these actions:

 

Reports - HTML Content - Base64 Encoded Embedded Images - If you have HTML content in a report and the HTML content has base64 encoded embedded images, the images will now render correctly in the printed report.

UX Component - List Control - Action Javascript - List Control Actions - Client-Side Order Expression - The genie now allows you to perform multi column sorts.

Set the 'Client-side sort mode' to Advanced and then use the smart field to define the sort definition.

You can define ascending or descending sorts and you can specify whether you want to sort on the whole field, or a subset (for example, just the first character of the field).

 

This gene generates Javascript that uses the .setOrder() method of the List. For example, here is how a mult-level (Customer, Country) sort would be defined:

var listObj = {dialog.object}.getControl('LIST1');
var sortObj = {'Country' : 1 , 'City' : 1};
listObj.setOrder(sortObj);
 

UX Component - List Control - Group Breaks - Client-Side - The List control has always had a Group Break option, but this option is a server-side group break. This means that the data that is sent from the server to the browser has the group breaks physically embedded into the List data.

Now, you can define client-side group breaks. These group breaks are inserted into the List on the client-side (after the List has been populated). Client-side group breaks offer several advantages over server-side group breaks. Namely:

NOTE: One advantage of server-side group breaks over client-side group breaks is when the List data source is based on a SQL query and you have turned on the List pagination option. In this case, summary data shown in a List header will be for all of the data in that group, not just the records that are currently visible in the List.

 

In the image below, the List has two levels of grouping: Country and City. Notice that a custom style has been defined for the second level group headers (showing the city name in blue, with a left padding of 50px).

 

 

Here is the same List, but this time showing some summary data in the top level group header:

 

To turn on client-side grouping for a List, check the 'Has client-side group breaks' property for the List as shown in the image below:

 

 

You can then click the smart field to open the 'Client-side Grouping' genie.

The genie allows you to define multiple levels of grouping.

For each group you define:

 

When you define the HTML for the header or footer, you can click the smart field button to open a genie. This genie has an option that makes it easy to include summary data in the header or footer. For example, in the image below, which shows the editor for the header HTML expression, the user has clicked on the 'Insert summary field' hyperlink, and the Summary Field Genie is displayed.

 

 

When you use the Summary Field genie, the generated Javascript that is inserted into the expression calls a special helper method of the List object. For example, here is the code to compute the average of the Price column:

this.groupSummary(data,'Price:N','avg')

 

Note: The .groupSummary() method ignores NULL values in the data.

In the example below, the average is computed and then formatted using a format string

 

Number(this.groupSummary(data,'Price:N','avg')).toFormat('# ##0,00')

 

 

 

UX Component - List Navigator - When you have a lot of records in a List, scrolling the List to the bring a section of the List into view can be tedious - especially on mobile devices where there is no vertical scroll bar. The List Navigator makes it easy to scroll a List that has group breaks. In the image below a List is shown with group breaks on the first character of the Contactname field. A List Navigator is shown on the right side of the List.

NOTE: You can only display a Navigator if the List has group breaks.  It does not matter, however, if the group breaks are computed server-side or client-side.

 

 

The user can drag on the Navigator to quickly scroll the List.

The Navigator has an entry for each Group Heading.

The Navigator can be positioned on the left, right, top or bottom of the List. Positioning the Navigator on the top or bottom is generally done when the List is set to scroll horizontally.

You have complete control over the size of the Navigator (when it is not in use) and its position (relative to to the edge of the List). The size of the Navigator when it is in use (i.e. when the user is dragging on it), is automatically determined by its contents. If the size of the Navigator (when it is not in use) is not wide enough (for left/right position), or high enough (for top/bottom position) to show its full contents when the user starts to drag on it, it will dynamically resize while it is in use and then go back to the smaller size when the user stops dragging on it.

 

To define a Navigator for a List, check the 'Has List Navigator' property on the List Properties pane of the List Builder. Then click the smart field to open the genie.

 

 

 

The List Navigator builder (shown above) allows you to define a Javascript expression that determines what data are put into the Navigator. You expression can reference the special html field. The html field contains the HTML that is shown in the Group Header.

In the above screen show, the HTML expression is:

html

This means that if the Group Headers in the List contain:

A

B

C

D.....

 

The Navigator will also contain the exact same values.

But, if the HTML expression was:

html.toLowerCase()

The Navigator would contain:

a

b

c

d...

 

UX Component - List Control - Action Javascript - List Control Actions - Client-side Group Breaks - A new action has been added to the List Control Actions genie that allows you to apply client-side Group Breaks to a List. The user interface for the Genie is identical to the user interface for client-side group breaks in the List Builder. See the section 'UX Component - List Control - Group Breaks - Client-Side'  for more details.

 

UX Component - List Control - Action Javascript - List Control Actions - Show Navigator/Hide Navigator - New actions have been added to the List Control Actions genie that allow you to show a List Navigator for any list that has group breaks and to hide a previously shown List Navigator.

 

UX Component - List Control - Client Side Filter and Order Expressions - You can now define a client-side filter and order for any List. The client-side filter is applied to the data when it is loaded into the List. If you have defined a server-side filter/order, the client-side filter will be applied in addition to the server side filter/order.

 

UX Component - Lookup Columns - You can display columns in a List where the data in the column is 'looked' up in another List, or by calling a Javascript function.

Watch Video
Download Component (You will need to change the connection string for both lists to point to the sample Northwind database).

 

Consider the following example. The image shows a List based on the Order Details table in the sample Northwind database. Notice that the List shows the ProductId, but not the ProductName.

 

 

It would be nice to show the Product Description in the List, as shown in the image below:

 

Obviously this could be done by specifying a SQL join for the List data source where the Order Detail table was joined with the Products table. However, this would mean that much more data would have to be sent over the network as every row of data in the List would include the Product Description field.

A much better approach would be to 'look up' the data on the client-side as the List was being rendered. You might create a second List based on the Products table that has the ProductId and ProductDescription fields in it.

To define a Lookup, click the smart field for the 'Lookup columns' property on the 'List Properties' pane in the List Builder.

 

 

This will open the Lookup Columns genie. You can define as many lookups as you want.

Each lookup must have a unique name. The lookup type is either 'List' or 'Function'.

A 'List' lookup will lookup the value in another List. You can Link the list to the Lookup List on one or more fields.

IMPORTANT: The List that is used as the data source must appear in the UX builder before the List that references it. For example, if the OrderDetails List lookups up values in the Products List, the Products List must appear before the OrderDetails List in the UX builder.

 

A 'Function' lookup will call a Javascript function that you define and return either a single value, or an object (with multiple values). Data from the current row in the List is passed into the Javascript function. You specify what data from the current row is passed into the Javascript function by setting the 'Lookup field(s)' property in the Lookup Columns builder.

If you specify more than one lookup field (for example, 'Firstname' and 'Lastname'), the lookup fields are passed into the Javascript function in an array. If there is only one lookup field, the value is passed into the Javascript function as a string. Here is an example of a very simple Javascript function that takes an array of input values:

 

function myLookupFunction(idValues) {

    if(idValues[0] == 'John' && idValues[1] == 'Smith') return 'value1';

    if(idValues[0] == 'John' && idValues[1] == 'Jones') return 'value12;

    return 'Value not found'

}

 

 

 

Once you have defined the Lookup, the fields from the Lookup are available in the 'Available Fields' list in the List Builder.

Notice in the image above, the 'Lookup Name' was set to 'products'.

Notice in the image below the available fields include:

The 'products' prefix is derived from the 'Lookup Name'. The list of available fields includes all of the fields in the Lookup List.

 

 

 

 

 

UX Component - Buttons - Split Buttons - A new option on the Button control allows you to easily create 'split' buttons. A 'split' button has a 'button' part and a 'down' part. You can define different event handlers depending on which part of the button the user clicked on.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download components

 

To define a split button, set the 'Display as split button' property

 

 

In your Javascript event handler you can reference

arguments[1]

If the user clicked on the button, arguments[1] is set to 'normal'

If the user clicked on the dropdown arrow, arguments[1] is set to 'split'.

IMPORTANT: You can only reference the arguments[1] parameter if your code is in the button's 'onClick' event. If you use the abstract 'click' event, then arguments[1] is not set to 'normal' or 'split'.

 

 

A typical use case for a split button is to display a menu when the user clicks on the down arrow. The user makes a selection from the menu, the action is performed AND the button is updated to show the action the user selected. The next time the user wants to perform the same action, a single click on the button will perform the action (rather than clicking on the down arrow and having to select from the menu).

The relevant methods that the menu can use to update the text in the button are:

For example:

var btn = {dialog.object}.getControl('button1');

btn.setContent( { html : 'New Button Text', tip: 'Help for button', icon: 'mynewicon.jpg'});

 

In some case, when the down arrow has been pressed, you might want to open a modal window and while the window is open you might want to show the button in a 'depressed' state, For example, notice the difference in the image below compared with the image above:

 

To set the state of a button to depressed or normal, you can use the <buttonObject>.setState() method.

The syntax is:

<buttonObj>.setState( pointerToButtonElement, true/false);

where true indicates the button is depressed and false returns the button to its normal state.

For example, assume the button Id is 'BUTTON_1';

 

var bEle = {dialog.object}.getPointer('BUTTON_1');

var bObj = {dialog.object}.getControl('BUTTON_1');

bObj.setState(bEle,true);

 

 

Application Server - Security Framework - Large Applications - The time to load security framework information for large applications has been significantly improved. In a test of a large application with 5,000 pages, each of which had security settings, the the time improvement is 2 orders of magnitude. To take advantage of this change, you must republish something in your application.

If a project is published from the latest pre-release to an older application server, the older application server will report a 500 internal server error as it won't be able to read the new file. The application server should be the same build as the development program.

 

 

SQL Query Builder - Column Alias Naming - When you build a SQL query that involves multiple tables and you select a column with the same name from multiple tables, Alpha Anywhere automatically assigns an alias to the column so that it has a unique name. The alias is a numeric suffix (e.g. CustomerID1). Now, you can specify if you prefer to use a table alias in the generated column alias. To set you preference, click the Preferences hyperlink in the image shown below.

 

PhoneGap - Support for the PhoneGap Build service is now tightly integrated into Alpha Anywhere.

PhoneGap is an open source product that allows you to build native applications for mobile devices. PhoneGap Build is a web service offered by Adobe that allows you to create native applications that use PhoneGap without having to install the device SDK on your machine, or in the case of iPhone/iPad apps, without even having to use a Mac.

PhoneGap creates a native application with an embedded browser control. Your Alpha Anywhere mobile app runs in the embedded browser, but has access to all of the native features of the phone that are exposed by PhoneGap.

To bring up the PhoneGap genie, click the PhoneGap button on the Web Control Panel toolbar.

You can download the documentation for the PhoneGap Build genie here.

For more information on PhoneGap, go to http://phonegap.com/

 

Web Applications - Security Framework - SQL Databases - The Web Application Security framework allows you to store the account information for the users and groups in your security framework in either .dbf tables or a SQL database. Previously, configuring the Web Security Framework to use SQL tables was a manual process, described in the following document:

http://wiki.alphasoftware.com/Using+SQL+tables+in+Web+Security

Now, a new genie makes it easy to configure the Security Framework to use SQL tables for your user and groups list. The genie also make it easy for you switch a previously configured Security Framework from .dbf tables to SQL tables without loosing any data.

When you edit your Security Properties (by clicking the Web Security button when the Web Control Panel has focus), the dialog now has a new property called 'Security Table Type', as shown in the image below.

If you select the 'SQL' option, then when you close the Security Settings dialog, a genie is launched (see screens below) to walk you through the process. The genie will prompt for a connection string and then will create the necessary security tables in your target SQL database.

If you are switching from .dbf security tables to SQL security tables, the genie will transfer your existing data to the SQL database.

NOTE: Remember, the genie will only be started once you close the Security Settings dialog and only if you have not previously configured security settings, or you are changing from .dbf to SQL tables. If you have previously configured your Security Settings to use SQL tables and you edit your security settings, the genie will not be started when you cloe the Security Settings dialog.

 

NOTE: The genie creates new tables in your SQL database. Mapping to existing tables is not supported.

 

TIP: If you want to change the SQL database in which your account information is stored you should first convert to use .dbf tables. That will import all of your existing account information into .dbf tables. The convert back to SQL. This will then export the data in the temporary .dbf tables to the new target SQL database.

 

 

After you click the OK button to close the Security Settings dialog, the Web Security Tables Upsize Genie is started.

 

 

 

 

 

 

 

 

AlphaDAO - <connection>.ListTables() Method - Limit Tables - The .ListTables() method is now limited to 1,000 table names. This change was made because a user had a database that has over 1,000,000 tables and returning the names of all tables in the database in this case is obviously impractical.

 

AlphaDAO - ODBC Connection String - DSN Less Connections - You can now create ODBC connections that do not use a DSN.

At the Data Source Name prompt in the Connection String builder, select <None> from the list.

 

 

When bypassing the DSN, you must provide the driver name by adding Driver='' as an additional parameter:

Example:

Driver='{Microsoft Paradox Driver (*.db )}'

 

For the generic ODBC API Alpha Anywhere populates the following parameters in the ODBC connection string if the we encounter corresponding values in the Alpha Anywhere connection string:

 


Prompt            SQL_DRIVER_NOPROMPT
NoPrompt        SQL_DRIVER_PROMPT
Complete        SQL_DRIVER_COMPLETE
Required        SQL_DRIVER_COMPLETE_REQUIRED
 
See the Microsoft documentation for ODBC for a complete explanation of these options.

 

Here is an example of an Access connection string and the equivalent DSN-less connection string that Alpha Anywhere automatically creates behind the scenes when the first connection string is used.

 

Connection String using the built-in Access option in the Connection String builder:

{A5API=Access,FileName='C:\temp\Northwind.mdb',A5TraceSQL=Y}

 

DSN-less ODBC connection string:
 

{A5API='ODBC',A5Syntax='Access',A5TraceSQL=Y,Driver='{Microsoft Access Driver (*.mdb, *.accdb)}',DBQ='c:\temp\Northwind.mdb',ExtendedAnsiSQL=1,ImplicitCommitSync=Yes,UserCommitSync=Yes}

 

a5_show_htmlChrome() Function - Desktop Applications -  Opens an Xdialog window and display HTML content using the embedded Chrome browser. Contrast with the existing a5_show_html() function that uses the IE activex control.

For example, consider the following script in a desktop application

 

dim html as c

html = <<%html%

<b>Hello World</b>

%html%

a5_show_htmlChrome(html)

 

 

UX and Grid Component - Styles - iOS7 and Android - New styles are included for iOS7 and Android. For Android, two styles are included - AndroidDark and AndroidLight.

 

IMPORTANT: If you are converting an existing component that previously used the iOS style to iOS7, AndroidDark or AndroidLight you will notice that the 'disclosure icons' on the right edge of your List controls do not render properly. Also, if your component was built using the Demo Mobile App that ships with Alpha Anywhere, the Menu List control might not render properly. Here is how to fix these two issues.

To fix the List template, edit the template and replace the disclosure icon in the template with {images.dialog.listNavSubtle} or {images.dialog.listNav}. The fixed HTML will then look like this:
<img src="{images.dialog.listNavSubtle}" />

To fix the Menu List, edit the Window container that contains the Menu List and check the HTML template in the Header HTML property. This property is in the Optional Window Parts section. Edit this template and make sure that the following HTML markup exists at the end of the template HTML:
<br style="clear:both;">

 

 

   

 

A particularly attractive feature of these new styles is the way that the icons in the style are rendered. Instead of using bitmaps for the icons, the styles use CSS Icons (also called Font Icons because the icons are all included in a special font file that is included as part of the style).

See below for more information on CSS Fonts in general and on Font-Awesome in particular. Font-Awesome is an open-source Font Icon that is now bundled with Alpha Anywhere.

 

 

UX, Grid and TabbedUI Components - CSS Icons (Icon Fonts) - Support has been added for CSS Icons (also know as Icon Fonts) - Icon fonts have become very popular, especially for mobile applications because they scale smoothly, and are smaller than bitmaps. Also, there are many libraries of icon fonts that can be used with Alpha Anywhere.

In the image below, the two icons in the buttons are both CSS Icons rendered using the Icon Fonts that come with the iOS7 style.

 

An icon font is just a regular font, excepting that instead of displaying characters, such as 'a', 'b', 'c', etc., the font has icons at each character position. So, assuming that the font defines a 'save' icon for character 'a', then in order to display the 'save' icon on your component, you would display the character 'a', and set its style to use the Icon Font.

Remembering that the 'save' icon corresponds to the character 'a', would be tedious, so a corresponding CSS file is defined. This CSS file has two main purposes:

For example, the CSS might define a rule called 'icon-save' that indicates what character the 'save' icon is mapped to.

When defining an image for a control (for example a button), you would indicate that the image name is:

cssIcon=icon-save

 

When the component is rendered the HTML markup, might look like this:

<img src="cssIcon=icon-save" />

 

This HTML markup is then automatically translated by Alpha Anywhere to:

<i class="icon-save"></i>

which correctly renders the icon using the appropriate character in the Icon Font.

 

You can also define an inline style for the CSS Icon. For example, if you define the image name as:

cssIcon=icon-save {color: blue;}

then, when this is translated automatically, the HTML becomes:

<i class="icon-save" style="color: blue;"></i>

 

UX, Grid and TabbedUI Components - Font-Awesome Icon Font Library - Font-Awesome is a popular open-source icon font library. Alpha Anywhere now comes with Font-Awesome pre-installed. The Font-Awesome library is installed in the CSSIcons folder in the folder where the Alpha Anywhere executable is installed.

For more information on Font-Awesome, please go to:

http://fontawesome.io

 

Watch Videos - Part 1

Watch Videos - Part 2

Watch Videos - Part 3

 

In order to use any icons in the Font-Awesome library, (or in any 3rd party CSS Icon Library) you must set a property in the UX, Grid or Tabbed UI builder to indicate that the library should be loaded. Click the smart field button for the CSS (Font) Icons property to open the dialog that allows you to select which CSS Icon library you want to load.

 

 

NOTE: When you close the 'Select CSS Icon Libraries to Load' dialog shown in the above image, the library files are copied from the CSSIcons folder in your executable folder to the CSS folder in your Web Project. Because the CSS Icon library files are then part of your Web Project, they will be automatically published when you publish your application.

 

Once you have indicated the libraries that you want to load, any time you are prompted for the name of an icon, you can select a regular bitmap, or a CSS Icon. For example, note the 'CSS Icon' option on the Image selector:

 

 

If you select the CSS Icon option you can select the icon source. If you are using a style that uses icon fonts (for example the iOS7, AndroidLight, or AndroidDark styles), the ImageSource list will show <Style> as an option.

The Image source list will always include 'Font-Awesome' since this library is bundled as part of Alpha Anywhere. But the list will also include any other libraries that you have installed. See section below on installing 3rd party CSS Icon font libraries.

To select an icon, click the Select button to open the genie:

 

 

The genie allows you to easily filter the list to quickly find a particular icon. You can specify the size of the icon using the dropdown 'Size' selector. If you select 'Custom' , then you can use the slider to select any size you want.

As you can see in the image below the icons scale smoothly, even when displayed at a large size - 127px in the image below.

 

 

You can also specify the color, CSS classes or in-line style to apply visual effects to the icon. For example:

(In the example below, the style for the Icon has been set to:

border: solid 3px; border-radius: 20px; padding: 4px;

)

 

 

 

CSS Icon Libraries - Installing 3rd Party Libraries - There are many sites on the web that supply Icon fonts and the accompanying CSS file to load and select icons from the font.

You can generally use any of these third party libraries as long as the accompanying CSS file for the library uses the convention of displaying the icon use the HTML <i> tag.

For example, to display the 'heart' image from the Font-Awesome library, the HTML markup is:


<i class="fa fa-heart"></i>

 

If the library you want to install uses the same conventions, then it can be used in Alpha Anywhere.

To install a 3rd party CSS Icon library, simply copy the folder that contains the CSS and font files for the library into the CSSIcons folder in the Alpha Anywhere executable folder (development version, not Application Server), and then 'install' the font (so that it can be used in Working Preview). See below for information on 'installing' fonts.

A popular source of icon fonts is http://www.fontello.com/

This site allows you to select icons from a menu of available icons and it then builds a custom icon font which you can download. After you download the files, just copy the folder into the CSSIcons folder in your executable folder.

Watch Video - Installing a 3rd Party CSS Icon Library


Registering the Font For Use in Working Preview

Icon fonts are loaded dynamically by the CSS file when you are in Live Preview or running your published application. However, when you are in Working Preview, in order to see the icons in the icon font, you must have previously 'installed' the font. Installing a font is easy. Just open the folder for the CSS Icon library. Look for a file with a .ttf (true-type font) extension (it will often be in a sub-folder called 'Fonts') and double-click on the .ttf file.   Windows will bring up a dialog that has an Install Font button. Click this button. It will install the font so that it can be used when you are in Working Preview.

 

UX Component - List Control - Menu Lists - A common pattern in mobile applications is to use a List control as the menu. This list control is then displayed in a Panel Window that animates in from the Left side of the screen. Icons are typically displayed for each menu choice. The CSS Icons are ideal for these types of icons.

Watch Video

A new pre-defined control is available in the Defined Controls section of the toolbox.

 

 

TIP: If you are building a mobile application, rather than using the pre-defined List Menu, you might find the pre-defined SplitView examples more helpful. These are available by selecting 'QuickPanels' from the 'Panels' category in the UX Toolbox on the left of the UX builder. See  'New SplitView Examples' below for more information.

 

 

Selecting this option will produce a List control like this:

 

If you edit the List properties for the above List, you will notice that the control type for the icon field has been set to CSSIcon. See topic UX Component - List Control - Using CSS Icons below for more information.

 

 

UX Component - List Control - Using CSS Icons - You can now easily use CSS Icons in a List. A new Control type property is available on the Fields tab of the List Builder.

In the image below, the control type for the Image column has been set to CSSIcon.

The data in this List's Data Source could be something like this (using CSS Icons from the Font-Awesome library in this case):

MenuName|Image|Action
Menu One|cssIcon=fa fa-heart fa-2x|action1
Menu Two|cssIcon=fa fa-music fa-2x|action2

 

Notice that in the 'Image' column, the name of the CSS Icon is specified (including the cssIcon= prefix).

You can also use in-line styles or your own classes to style icons. For example, here is how the data could be represented using an in-line style for the icon in the first row and a custom class for data in the second row:

 

MenuName|Image|Action
Menu One|cssIcon=fa fa-heart fa-2x {color: red;}|action1
Menu Two|cssIcon=fa fa-music fa-2x myiconclass|action2

 

 

 

If your list uses a Free-form template, you can put a CSS Icon directly in the template using this HTML markup:

<i class="fa fa-heart fa-2x"></i>

 

Tip: You could just as easily add the following HTML markup to your template:
<img src="cssIcon=fa fa-heart fa-2x" />
and at run-time Alpha Anywhere will translate the <img> tag to the correct <i> tag (because the src attribute of the <img> tag starts with 'cssIcon')

 

 

UX Component - Mobile Applications - SplitView - Pre-Defined Quick Start Templates - A typical mobile application often includes a 'menu' panel that allows the user to navigate to different parts of the application. A common pattern is to use a 'split-view' with the menu in the left Panel and the main work area of the application in the right Panel. The menu is hidden on a phone (where screen space is limited), but shown on a tablet (where more screen space is available). If the menu is hidden, tapping on button in the PanelHeader, or swiping to the right, will reveal the menu.

In the images below, the UX is shown as it appears on a phone and a tablet. Notice that on the tablet, the menu is always visible and the button in the PanelHeader (shown when the UX is on a phone) is automatically hidden.

 

Watch Video - Part 1

Watch Video - Part 2

Watch Video - Part 3

 

 

 

 

If you want to use the pattern described here, you can select add a pre-defined set of controls to your UX component by selecting 'Quick Panels' from the UX toolbox.

 

Then select '{Predefined:SplitViewWithIconsAndPanels}'

 

 

UX and Grid Component - Client-side Calculated Fields - Builder - When you open the Builder to define a client-side calculated field, a new hyperlink appears on the dialog - 'Format String'. This hyperlink opens a genie that can be used to define the format string for the new FormatNumber() function which can be used in your client-side calculated fields to format numeric values.

 

When you click the Format String hyperlink, a genie opens to help you define your format string:

 

 

UX and Grid Component - Client-side Calculated field - FormatNumer() function - Client side calculated fields can now use a new psuedo function, formatNumber() to format a numeric field.

For example:

formatNumber(num1,"#,###.00");

The format string is very similar to the syntax used by Excel. For information on the syntax for format strings, see the section 'Number Format Strings' below.

NOTE: When you use the formatNumber() pseudo function in a client-side expression, the function gets converted to the following Javascript:
            number.toFormat('formatString')

where 'number' is any Javascript numeric variable. The Alpha Anywhere Javascript library adds a .toFormat() method to the prototype for numeric objects.
 

 

UX and Grid Component - Number Format Strings

 

Number format strings are used in the .toFormat() method of numeric variables and in the formatNumber() function when defining a client-side expression in a Grid or UX component.


A number format string can have multiple formats in them by using a ";" to separate multiple formats. The way a given format in the format string is selected is based on either its location in the string, or by an optional condition.

If the format string doesn't contain any conditions then the first format will be used for a positive value, the second for a negative, and the third for a zero value.

Conditions can be put into the format by making the first part of the format string contain if(expression) where n equals the value of the number. For example:


if(n>999999999)=(###) ###-####;=###-####
 

is a multi-format string that the will return numbers greater than 999999999 as a 10 digit phone number mask and number less than 999999999 as a 7 digit phone number mask.

You can also optionally process a number before it is formatted by adding =(expression) onto the end of a format string where n equals the value of the number. For example:

##0.00 %=(n*100)
 

is a format string that will first multiply the number by 100 before outputting it with the format. A value of '.254' would be returned as '25.40 %'

A number format can be either of two types: a "number" or a "mask" format.

A mask format is indicated by the first character in the format being an = sign. The # character in the mask will be replaced with the first available digit from the number. An example of a number format for a 10 digit phone number is:


=(###) ###-####
 


Using the above mask, the number

8004511018

would be formatted as:

(800) 451-1018



While 'masks' are simple, 'number' formatting can be more complex. Below is a list of the special characters that can be used in a 'number' format string:

 

Character Description
# an optional digit
0 a required digit (will be output as "0" if no value in the number for the given location)
_     (an underscore character) an optional digit (will be output as  " "  if no value in the number for the given location)
* after the decimal character will cause there to be no rounding (number if output with its full precision)
] at end of a number format (before any suffix) means round to zero (there will be no decimal value)
[ with "]" means force "0" for integer places in the number (e.g. 123 formatted with #[00] would be 100)
< at end of a number format (before any suffix) means round decimal up, before "]" is the round up equivalent of "["
> at end of a number format (before any suffix) means round decimal down, before "]" is the round down equivalent of "["
-/- display decimals as fractions


After optional conditions and number processing expressions have been removed from the format string, any non-special characters at the beginning and end of the format string are placed into the prefix or suffix. If a format string does not contain multiple formats for positive and negative values, a '-' (minus sign) will be appended to the start of the result if the number is negative.

Examples

 

Number Format String Result Description
1256.2 # ##0,00 1 256.20 use a " " to separate thousands and a "," for the decimal, round to two decimal places and force "0" for those two decimal places
.257 0.00> 0.25 pad the integer part with a "0" and use a "." for the decimal, round down to two decimal places.
1256.2 #,#[00] 1,300 clip to two integer places and use a "," as thousands separator.
1256.2 #,#>00] 1,200 clip to two integer places, round down, and use a "," as thousands separator.
1256.2256 #,##0.* 1,256.2256 use a "." for the decimal and a "," for the thousands separator, don't round the decimal.
1.256 0.##> and -/- 1 and 1/4 round down to two decimal places and render the decimal as a fraction in the suffix
1256.2 $#,##0.00;$ (#,##0.00);------ $1,256.20 multiple format strings for positive, negative and zero value. The thousands separator is "," and the decimal character is ".". Number if rounded to 2 places. Negative value is enclosed in parentheses. Zero value is output as "------"
4
3
1
if(n>=4)# (Good);if(n>=2) # (Average);# (Bad) (Good)
(Average)
(Bad)
render the number with a custom suffix based on a condition. For example, if the number if 4, the output value is (Good). If the number if 1, the output value is (Bad)
 
1256.2 #[0] 1260 round to 10, integer only
1256.2 #[00] 1300 round to 100
1256.2 #[000] 1000 round to 1000


 

 

 

UX Component - Ajax Callback - Timeout Setting - You can now specify an explicit value for the Ajax callback timeout. This is the amount of time to wait (in milliseconds) for the response from the Ajax callback. If the response is not received within the specified the, the callback is considered to have failed and the 'onAjaxCallbackFailed' event is fired and any code defined in the optional 'Ajax failed Javascript' property is executed.

Previously, the timeout setting used the default value set by the browser.

If you set the property value in the dialog shown below to <Default>, then a default value for the component is used. This default can be defined by adding code like this to the UX component's 'onRenderComplete' client-side event:

{dialog.object}.ajaxCallbackTimeout = 1000;

 

If you set the property value to 0, the default value as defined by the browser is used.

 

 

 

 

 

UX Component - Action Javascript - Ajax Callbacks - Cross-Domain - Because of security issues, browsers typically enforce a policy that requires that the page that responds to an Ajax callback must be loaded from the same domain that the original page was loaded. This does not represent a problem for typical Ajax callbacks that are handled by Xbasic code on the server.

However in cases where you want to call a web service directly from the client (without first going to the Alpha server), it does represent a problem.

Consider for example the following scenario:

Say you have a button on the UX and you want to make a call to the Apple iTunes store to retrieve information about a book.

The URL for this web service (including the query string for the particular book you are interested in) is as follows:

http://itunes.apple.com/lookup?isbn=9780316069359

 

The domain for this URL is obviously not the same as the domain from which the UX component was loaded in the first place.

There are two ways in which you could call this web service:

Clearly, the second approach is more desirable as it avoids hitting the Alpha server at all.

However, in order to implement the second approach you need to perform a cross-domain Ajax callback.

The new 'Ajax Callback - Cross Domain' action in Action Javascript allows you to perform cross-domain Ajax callbacks.

TECHNICAL NOTE: The Ajax Callback - Cross Domain action is built on top of jQuery. You must load jQuery core for this method to work. See the Web Project Properties dialog to enable jQuery.

 

When you define this action you specify the URL of the callback page. Any parameters that you want to pass in to the web service are in the query string. When you specify the URL, you can specify an explicit value, or any Javascript expression that evaluates to the URL. This allows you to dynamically construct the URL for the callback.

You also specify the name of a Javascript function that will be called when the Ajax callback completes successfully. The function gets passed an argument that contains the data retuned by the callback.

NOTE: Unfortunately, if the callback fails, there is no way to specify an 'onFailure' function. This is a limitation of the technique used for making cross-domain callbacks.

A useful technique for seeing what data in passed to the success function is to define  the following success function for your action:

 

function mySuccessFunction(data){
    alert(JSON.stringify(data,'','\t'));
}

 

This function will convert the data returned by the callback into a JSON string and display it.

 

 

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

 

 

UX and Grid Component - Client-side Expressions - New Round() functions - In build 1788-4225 new options were added to the $u.n.round() function in the Alpha Anywhere Javascript library. These options allowed you to specify if the rounding was:

However, when using the client-side expression builder, there was no way to specify which option you wanted to use when you used the round() function.

Now, these new functions can be used in your client-size expressions:

 

 

HTML Reports - Export to Excel, Word or PDF - beforeHTMLReportExport event - A new client-side event has been added to the UX, Grid and Tabbed UI components. This event is fired when an HTML report is displayed and the user clicks one of the buttons on the report toolbar to export the HTML report to PDF, Word, Excel or Text mode. The main motivation for this event is to allow the developer to put up a custom wait dialog. The afterAjaxComplete event can be used to dismiss the custom wait dialog.

 

 

UX Component -  List Control - Buttons and Hyperlinks - Set Focus Property - Buttons and Hyperlink controls now have a new property called 'Set Focus'. By default, when you click on a button or hyperlink in a List row, the row that contains the button or hyperlink does not automatically get selected. Now, if you check the 'Set Focus' property, when you click the button or hyperlink, the corresponding row is also selected.

 

Grid Component - Edit-Combo and Auto-Suggest Controls - NotInList Event - Added support for the NotInList event for edit-combo and auto-suggest controls in Grids. This event fires when the user enters a value that is not in the list of choices. The typical use case for this event is to write code to add the value that the user entered to the table that contains the choices so that in future, the value that was entered can be presented in the pick list.

UX Component - Javascript Controls - 'Initialized' property - All Javascript controls on a UX (for example, List, SpinList, ButtonList, Switch, etc.) now have a new 'initialized' property. Consider the following example that explains why this property is useful:

Assume you have a List control and you have unchecked the 'Allow Null selection' property. This means that when the List is rendered, the first row in the List will be automatically selected and the onSelect event of the List will fire.

Assume that in the onSelect event you reference some property of the List that does not yet exists because the List has not yet been fully initialized. Your code will generate a Javascript error. Using the new 'initialized' property, you can write your onSelect event as:

 

if(this.initialized) {

        //your onSelect event code goes here

}

 

hmac_hash() Function - The hmac_hash() function is primarily for internal use in situations where OAuth authentication is used. The function is exposed to Xbasic as it might be useful to developers.

?hmac_hash("alpha anywhere","secret","HMACSHA1",.F.)

 

Grid and UX Component - .runAction() Method - Javascript Actions - Passing in an Object Reference - The .runAction() method now takes an optional second argument which is a pointer to an element on the page. The use case for the parameter is described below.

Assume you used Action Javascript for a button to open a window that was positioned relative to the button. If you examine the generated Javascript code, you will see that the Javascript in the button's onClick event passes in 'this' - a reference to the button. Therefore the windows can be positioned relative to the button.

However, if you define the exact same action as a Javascript Action, and then try to invoke the Javascript Action from a button (using the .runAction() method in the button's onClick event), you will get a Javascript error because the code that tries to position the window does not have any reference to the button.

Now, by passing in a reference to the button when the .runAction() method is called, the window can be positioned.

For example

{dialog.object}.runAction('myaction',this)

 

 

*property_filter() Function - Takes a .dot variable and filters out certain properties. The 'filter' specification is a cr-lf delimited string of directives that can include wildcard characters and a leading - sign to indicate that a property should be removed.

For example consider the following .dot variable:

 

 

dim prop.firstname as c
dim prop.lastname as c
dim prop.company as c
dim prop.age as n

 

'this filter selects the properties 'firstname' and 'age'

dim filter as c

filter = <<%str%
firstname
age
%str%

 


prop =  *property_filter(prop,filter)

?prop
= age = 0
firstname = ""

'this filter removes the 'firstname' property, selects all properties

'that end in 'name' and all properties that start with 'comp'

filter = <<%str%
-firstname
*name
comp*
%str%


prop = *property_filter(prop,filter

?prop
= company = ""
lastname = ""

 

 

 

property_from_url() Function - Parses a URL query string into an Xbasic .dot variable.

Syntax:


property_from_url(prop as p,url as c)

 

 

Example:

dim p2 as p
property_from_url(p2,"firstname=john&lastname=smith&company=ACME%20Industries")
? p2
= company = "ACME Industries"
firstname = "john"
lastname = "smith"

 

 

 

property_to_url() Function - Converts a .dot variable to a URL.

Syntax:

c Url = property_to_url(prop as p[,options as c])

 

options - 'S' - sorts the parameters so that they conform to the oauth specification for a normalized request. See http://oauth.net/core/1.0/#anchor14 

 

Example:

 

dim prop.firstname as c = "john"
dim prop.lastname as c = "smith"
dim prop.company as c = "ACME Industries"
? property_to_url(prop)
= "firstname=john&lastname=smith&company=ACME%20Industries"


? property_to_url(prop,"S")
= "company=ACME%20Industries&firstname=john&lastname=smith"
 

Tips

AlphaDAO - Oracle - Executing SQL Commands - CRLF Characters - If you have an Xbasic script that executes some SQL commands against an Oracle backend, be sure that your SQL commands do not have cr-lf characters in the command string. You should replace all cr-lf characters with lf charactrs.

 

For example, consider the following Oracle SQL code to be executed

 

 

dim cmd as c

cmd = <<%str%
DECLARE
prdcode gm_test_t.prd_code%type;
method gm_test_t.method%type;
histid gm_test_t.history_id%type;


BEGIN
prdcode := :prdcode;
method := :method;
histid := :historyid;

insert into gm_test_t (prd_code,method,descr, history_id)
select prdcode, method,descr, gm_test_s.nextval from gm_test_t a where a.prd_code = prdcode and a.method=method and a.history_id = histid;

COMMIT;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20000,sqlerrm);
END;

%str%

dim cn as sql::connetion

cn.open("::name::myoracleconnection")

dim args as sql::arguments

'set argument values

cn.execute(cmd,args)

 

The above will fail because the SQL commands have cr-lf characters in the code.

Instead, change the code to this:

 

dim cn as sql::connetion

cn.open("::name::myoracleconnection")

dim args as sql::arguments

'set argument values

cmd = stritran(cmd,crlf(),chr(10))

cn.execute(cmd,args)

 


 

UX Component - List Control - Toggle Display of List or Map - A common pattern when designing a UX component is to wrap certain controls in a container, set the inline style of the container to display: none; and then have some button or event that will display the container when necessary - using the Toggle Display action in Action Javascript.

If the container has a List control that uses Columnar layout, or a Map control, then when the container is shown, the List or Map will not be rendered properly. This is because when the UX is initially rendered, the Map or List control is not shown and so these controls do not know how to size themselves correctly.

This issue is easily solved by using the onShowComplete Javascript event in the Toggle Display Action Script builder. You can use this event to refresh the List or Map.

 

For example, assume that the Id of a List control in the container is 'LIST1' and a Map control is 'MAP1'. Here is the Javascript to refresh the controls:

 

{dialog.object}.getControl('LIST1').refresh();

{dialog.object}.getControl('MAP1').refresh();

 

 

Xdialog - Chrome Control - Loading HTML in Chrome OnReady Event - Consider the following simple Xdialog that displays some HTML in Chrome control:

dim cr as helper::Chrome
cr.html = "HTML to show"
dim dlg_title as c
dlg_title = "Chrome Xdialog"
ui_dlg_box(dlg_title,<<%dlg%
{chrome=100,20cr}
%dlg%,<<%code%
%code%)

This Xdialog will render as follows:

 

 

In some cases, however, because of timing problems, the Xdialog window will open, but the Chrome control will not be properly populated.

The Xdialog can be restructured so that the HTML is only loaded into the Chrome control when its OnReady event fires:

 

dim html as c
html = <<%html%
<p>HTML - loaded in the Chrome onReady event</p>
%html%
dim cr as helper::Chrome
cr.html = "Dummy Content"
dim dlg_title as c
dlg_title = "Chrome Xdialog"
cr.OnReady = "ui_dlg_event("+quote(dlg_title)+",\"chromeReady\")"
ui_dlg_box(dlg_title,<<%dlg%
{chrome=100,20cr}
%dlg%,<<%code%
if a_dlg_button = "chromeReady"
    a_dlg_button = ""
    cr.html = html
end if
%code%)

 

 

 

 

UX Component - SpinList Control - Getting the value for the 'Display Value' - When you define the choices with which to populate a SpinList control, you can specify a 'display value' and a 'stored value' for each value. When you read the current value in the control (using the {dialog.object}.getValue() method, or the .value property on the SpinList object itesel), you well be reading the stored value. In this tip we show you how to get the current display value:

Assume that the SpinList control id is 'spin1'

 

//get a pointer to the SpinList control

var s = {dialog.object}.getControl('spin1');

var v = s.value; //get the current value

var _d = s._data; //get the array of data in the SpinList

//find the index in the array where the array's 'value' property

//matches the the current value in the SpinList

var indx = {dialog.object}._findArrayProp(_d,'value',v);

var html = _d[indx].html;

alert(html);

 

 

SQL Server - Date or Date/Time Fields - Errors - Installing correct Native Client - Occasionally we received a bug report from a user reporting that they are getting an error while doing some type of SQL query involving a SQl Server date or datetime field. Invariably, the error is caused because they do not have the correct drivers for the SQL server Native Client installed.

Here are the links to the download on the Microsoft web site:

X86 Package(sqlncli.msi) - 4549 KB
X64 Package(sqlncli.msi) - 7963 KB
IA64 Package (sqlncli.msi) - 11112 KB

 


 

Reports - PDF - Acrobat Viewer - Crash - In some instances, when doing a Live Preview of a component that prints a PDF report, the Adobe Acrobat viewer might report a crash, with a dialog similar to this:


Alpha Anywhere will then display a message like this:



Research on the Adobe site indicates that this has been a somewhat random problem in Acrobat in IE since Acrobat X.  One common suggestion from Adobe was to open Reader and go to Edit -> Preferences -> Security (enhanced) and disable protected mode  by unchecking "Enable Protected Mode at startup"  

http://www.brain-cluster.com/adobe-2/acrobat-reader/there-problem-adobe-acrobatreader-if-it-running-please-exit-and-try-again/

 

HTTP and FTP Functions Not Working on Certain Machines - Some users have reported problems with the built-in FTP and HTTP functions in Xbasic. They assume that the issue is a port conflict.

In fact, the client functions are not hard-coded to a specific outbound port. They use the standard Windows API for accessing a random available port. If outbound access is being blocked, it is likely being done so by a firewall, not by a conflict with another running program. Most Windows installations have Windows Firewall configured to block outbound access by default for all applications. See http://windows.microsoft.com/en-us/windows/communicate-through-windows-firewall#1TC=windows-7 for details on allowing the outbound access.
 




Grid Component - Search Part - Customizing the Search Part Toolbar - The Search Part does not allow you to customize the toolbar, as you can for the Grid Part and Detail View Part. A user wanted to put an Action Button next to the 'Search' button. Here is how you can do this.

 

 

First, define your Action Button and place it anywhere on the Grid (it does not matter where you place it because we are going to move it using Javascript).

Then add this code to the Grid's onGridRenderComplete event:

 

//set this to the ID of your action button

var actionButtonId = 'MYBUTTON';
 

//get a pointer to the 'Search Button'
var ele = $( '{Grid.ComponentName}.SEARCHBTN' );
ele = ele.parentNode;
var ele2 = ele.parentNode;
var sele = $('{Grid.ComponentName}.ACTIONBUTTON.'+actionButtonId+'.G0');
ele2.appendChild(sele);
 

UX and Grid Components - Javascript Date Values - Parsing Strings into Date Values - The Alpha Anywhere Javascript library has added a very useful method to the Javascript Date object to help parse strings (that represent date values) into real date objects.

The Date.formFormat() method takes two arguments - a date string and a date format string. For example

var d1 = new Date().fromFormat('01/01/2014','MM-dd-yyyy')

You can also use the Date object's .fromFormat() method to format a date object as a sting.

var dString = d1.toFormat('dd-MM-yyyy');

 

 

 

Tab Direction on UX For Right-to-Left Languages - For languages that go from right-to-left, it is desirable to also have the tab direction go from right-to-left so that when the user hits the tab key, the control to the right of the current control is selected. This is easily done by adding this CSS to the UX component's local CSS definition.

IMPORTANT: Be sure that the Layout Mode property on your UX is set to 'ContainerWidth'

body { direction:rtl; }
.A5CWLayout { float:right; }
 

TIP: If you have List controls on a UX component for which the body direction has been set to 'rtl', you will need to wrap each List control in its own container and set the direction property of the container to 'ltr', or else the titles on the List will not display correctly.

 

Generating an UX Component Using Xbasic - a5wcb_createDialogUsingXbasic() Function - The a5wcb_createDialogUsingXbasic() function can be used to generate an UX component programmatically.

Note that for each control, a minimal set of properties is defined. You can add additional properties for each control if necessary. The Xbasic tab in the UX builder shows the available properties for each control type.

 

dim wp as p
DIM wp.page_fields[0] as P
with wp.page_fields[]
    .controltype = "layout_directive_statictext"
    .v.StaticText = "Created by Xdialog"
end with

with wp.page_fields[]
    .v.variableName = "c"
    .v.breakType = "None"
end with

with wp.page_fields[]
    .v.variableName = "d"
    .v.label = "Field D"
    .v.hasWaterMark = .t.
    .v.waterMark.text = "Enter name"
end with

with wp.page_fields[]
    .controltype = "layout_directive_button"
    .v.buttonText = "click me"
    .v.javascript.onclick = "alert('click');"
end with

with wp.page_fields[]
    .controltype = "layout_directive_FrameBegin"
    .v.FrameTitle = "frame"
    .v.Frame.ID = "FRAME_1"
    .v.Frame.type = "Simple"
end with

with wp.page_fields[]
    .controltype = "layout_directive_hyperlink"
    .v.hyperlinkText = "this is my hyperlink"
    .v.javascript.onclick = "alert('you clicked a hyperlink');"
end with
 

with wp.page_fields[]
    .controltype = "layout_directive_image"
    .v.ImageMode = "Static"
    .v.javascript.onclick = "alert('click on image');"
    .v.Imagename = "images/$$application.alpha.png.a5image"
end with


with wp.page_fields[] ' initialize tmpl.page_fields[8]
    .controltype = "layout_directive_FrameEnd"
end with



'create the UX and call it 'genByXbasic'
a5wcb_createDialogUsingXbasic(wp,"genByXbasic",.t.)
 

 

 

Generating a UX Dynamically in a Web Application - In the previous tip we discuss how to generate a UX component using Xbasic. The generated component is a permanent component that appears in the Web Control Panel.

Watch Video
Download Component

However, you might have a use case that requires the dynamically created UX component at run-time. The UX component, in this case, should be created as a temporary session file. This is done by specifying a name with '__sessionFile__' as a prefix when calling the a5wcb_createDialogUsingXbasic() function.

 

The following sample .A5W page shows how this can be done

 

<%a5

'define the UX component

dim wp as p
DIM wp.page_fields[0] as P
with wp.page_fields[]
.controltype = "layout_directive_statictext"
.v.StaticText = "Created by Xdialog"
end with

with wp.page_fields[]
.v.variableName = "c"
.v.breakType = "None"
end with

with wp.page_fields[]
.v.variableName = "d"
.v.label = "Field D"
.v.hasWaterMark = .t.
.v.waterMark.text = "Enter name"
end with

with wp.page_fields[]
.controltype = "layout_directive_button"
.v.buttonText = "click me"
.v.javascript.onclick = "alert('click');"
end with

with wp.page_fields[]
.controltype = "layout_directive_FrameBegin"
.v.FrameTitle = "frame"
.v.Frame.ID = "FRAME_1"
.v.Frame.type = "Simple"
end with

with wp.page_fields[]
.controltype = "layout_directive_hyperlink"
.v.hyperlinkText = "this is my hyperlink"
.v.javascript.onclick = "alert('you clicked a hyperlink');"
end with

with wp.page_fields[]
.controltype = "layout_directive_image"
.v.ImageMode = "Static"
.v.javascript.onclick = "{grid.Object}.ajaxCallback('G','{Grid.RowNumber}:all','xb','','',{deviceOfflineFunction: function() { }});"
.v.Imagename = "images/$$application.alpha.png.a5image"
end with


with wp.page_fields[] ' initialize tmpl.page_fields[8]
.controltype = "layout_directive_FrameEnd"
end with

DIM wp.XbasicFunctionDeclarations as C = <<%code%
function xb as c (e as p)
xb = "alert('callback');"
end function
%code%
 

'give the component name a special name that starts with __sessionFile__
dim componentName as c
componentName = "__sessionFile__mydynamicUx"
a5wcb_createDialogUsingXbasic(wp,componentName,.f.)


Delete tmpl
DIM tmpl as P
tmpl = a5w_load_component(componentName)
 

'set the following to properties in tmpl
tmpl.alias = "MYALIAS"
tmpl._dialogFilename = file.filename_parse(componentName,"N")

 

 

'now run the dynamically generated component

delete x_ux1
dim x_ux1 as p
x_ux1 = a5w_run_Component(tmpx)

?x_ux1.Output.Head.JavaScript
?x_ux1.Output.Head.CSS_Link
?x_ux1.Output.Head.Title
%>

</head>
    <body>
        <%a5 ?x_ux1.Output.Body.Dialog2_HTML %>
    </body>

</html>

 

 

 

 


Alternatively, you might want to generate the UX component dynamically on an Ajax callback. For example, the following Xbasic function in a UX component handles an Ajax callback. The function dynamically creates a UX and then sends the name of the dynamically created UX component back to the UX so that the name can be stored in a variable and used when you want to open this component.

 

 

function xb_generate as c (e as p)

dim wp as p
DIM wp.page_fields[0] as P
with wp.page_fields[]
.controltype = "layout_directive_statictext"
.v.StaticText = "Created by Xdialog"
end with

with wp.page_fields[]
.v.variableName = "c"
.v.breakType = "None"
end with

with wp.page_fields[]
.v.variableName = "d"
.v.label = "Field D"
.v.hasWaterMark = .t.
.v.waterMark.text = "Enter name"
end with

with wp.page_fields[]
.controltype = "layout_directive_button"
.v.buttonText = "click me"
.v.javascript.onclick = "alert('click');"
end with

with wp.page_fields[]
.controltype = "layout_directive_FrameBegin"
.v.FrameTitle = "frame"
.v.Frame.ID = "FRAME_1"
.v.Frame.type = "Simple"
end with

with wp.page_fields[]
.controltype = "layout_directive_hyperlink"
.v.hyperlinkText = "this is my hyperlink"
.v.javascript.onclick = "alert('you clicked a hyperlink');"
end with

with wp.page_fields[]
.controltype = "layout_directive_image"
.v.ImageMode = "Static"
.v.javascript.onclick = "{grid.Object}.ajaxCallback('G','{Grid.RowNumber}:all','xb','','',{deviceOfflineFunction: function() { }});"
.v.Imagename = "images/$$application.alpha.png.a5image"
end with


with wp.page_fields[] ' initialize tmpl.page_fields[8]
.controltype = "layout_directive_FrameEnd"
end with

DIM wp.XbasicFunctionDeclarations as C = <<%code%
function xb as c (e as p)
xb = "alert('callback');"
end function
%code%

fn = "__sessionFile__myuxonthefly"
a5wcb_createDialogUsingXbasic(wp,fn,.f.)

'generate a response to send back to the client

'the name of the dynamically generated UX will be stored

'in a variable called {dialog.object}._ux
 

xb_generate = "alert('done: "+js_escape(fn)+"');" + crlf()+\

"{dialog.object}._ux = '"+js_escape(fn)+"';"

end function

 

 

Now, in order to open this dynamically generated UX, you would need to make another Ajax callback. The easiest way to code this is use use Action Javascript to define an action that opens a UX component, and then convert the action to text mode. Then edit the generated code and replace this line:

 

go.dialog2Name = 'Name of component to open';

 

with this line:


go.dialog2Name = {dialog.object}._ux;
 

 

 

Build 1856-4237  18-Dec-2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Videos

Xbasic - Xdialog Using the Chrome Embeddable Browser in Xdialog Xdialog allows users who are building desktop applications to create very powerful 'screens' to prompt for and display information to users. You can now embed Google's Chrome browser directly into your Xdialogs. This means that you can use the full power of HTML, CSS3 and Javascript to create amazing looking Xdialog screen. When you embed the Chrome control in an Xdialog you can easily respond to events in the HTML with either Javascript of Xbasic code. You can also easily send events from Xbasic to the HTML that is displayed in the embedded Chrome control.

If you have used Xdialog in your desktop applications in the past, this new feature will open up many exiting possibilities.

Introduction
Watch video - Part 1
Watch video - Part 2

Debugger
Watch Video - Part 3

Binding events:
Watch video - Part 1
Watch video - Part 2

Google Charts:
Watch video

Using jQuery:
Watch video

For extensive documentation on how to embed a Chrome control into Xdialogs see the release notes.

 

 

Change in Behavior

UX Component - Abstract Events - Enable Expression - If the client-side enable expression was false, the click event did not fire (correct), but the down event did. This has now been changed and the down event will also not fire.

Bugs

Grid Component - Image and File Upload - New Records - Form Layout - If a Grid component used a Form layout (as opposed to a Tabular layout), then image and file upload to the new record rows did not work. There was no problem when doing uploads to existing rows, or to new rows when the Grid used a Tabular layout.

UX and Tabbed UI Component - Session Timeout Warning Feature - Under certain conditions, the Session Timeout Warning for the UX and the Tabbed UI did not open at the correct time and did not show the correct time remaining. This has now been fixed and the message box will now show the actual seconds left in the session since the last request from the component.

 

sql_lookup() Function - As a result of a change made in build 1788 the data type returned by the sql_lookup() function was always a character value, when it should have been correctly typed (i.e. a datetime value, a numeric value, etc, depending on the data type of the column value that the function was returning).

Now, if sql_lookup() specifies a filter and returns a single field in the return expression, the return value is correctly typed. If more than one value is returned, or no filter is specified, the return value is a character string.

 

 

Grid Component - Search Part - SQL Query Using Group By - If a Grid built in V11 used a GROUP BY clause in the SQL statement, performing a search on the Grid would fail. The problem did not occur if the Grid was build in V12 and the solution was to de-select the Search Part fields and re-select them. Now, this is no longer necessary.


 

A5_HTML_Pretty() Function - XML - The A5_HTML_Pretty() function, which takes an HTML string and adds the correct indentation to all of the elements can now also be used to format XML. The function takes a second, optional, parameter that indicates if the input string is XML. By default, this flag is .f.

 

txt = http_get_page2("http://feeds.gawker.com/lifehacker/full")
txt = a5_HTML_Pretty(txt,.t.)
showvar(txt)
 

 

 

Xbasic - Working With XML - Working with XML in Xbasic is now even easier. The following functions have been enhanced:

 

 

In addition, the showXML() function has been enhanced.

 

Consider the following very simple snippet of XML.

 

xml = <<%txt%
<name city-name="boston">
    Fred Smith
</name>
%txt%
 

 

If you view this XML using the XML viewer function (showXML()), you will see this:

 

 

You will notice that the XML has an attribute called 'city-name'. This is not a valid Xbasic variable name, so the attribute has to be renamed (to 'city_name'). In order that the *property_to_xml() function can get back to the same XML that was originally parsed, a list of all of the attribute names that were changed is kept in the special __A5_Xml_Manifest property.

 

 

 

Also, you will notice that in the XML snippet, the 'name' element has a value and also it has attributes. The attribute values are shown as properties and the element value is shown using the special property name '__A5_elementContent'.

 

Here is how you can parse the above XML into an Xbasic dot variable:

 

delete p
dim p as p

'set the optional 3rd flag to .t. to use the special properties
*property_from_xml(xml,p,.t.)

 

 

'convert the dot variable into a script so we can 'see' what's in the variable

?*variable_to_script(p)
= DIM name as P
DIM name.city_name as C = "boston"
DIM name.__A5_elementContent as C = <<%str%

Fred Smith
%str%
DIM __A5_Xml_Manifest as C = <<%str%
@Mapping:
city_name=city-name%str%
 

'now, go back to XML
?*property_to_xml(p,"")


= <name city-name="boston">
    Fred Smith
</name>
 

Notice how this is a perfect 'round-trip'! The generated XML is the same as the initial XML that was parsed.

Now, try the above exercise without using the new optional flag on the *property_to_xml() function

 

delete p
dim p as p

*property_from_xml(xml,p,.f.)

 

 

'convert the dot variable into a script so we can 'see' what's in the variable

?*variable_to_script(p)
= DIM name as P
DIM name.city_name as C = "boston"
 

Notice how the Xbasic dot variable only has the value of the attribute. It does NOT have the value of the element!

 

 

*HTML_GET_ATTRIBUTE() Function - Quick way to extract an attribute value from some HTML markup.

The syntax is:

C result = *HTML_GET_ATTRIBUTE( markup as c, attributePattern as c)

 

Consider the following HTML markup:

 

 

dim html as c
html = <<%html%
<img  
    id="GRID1.V.R2.PICTURE1"  
    onmouseover="$('bp').src=img;"  
    style="height: 1in; cursor: pointer;"
    src="pictures/5.jpg"  
    title="pictures/5.jpg"  
    onerror="{grid.object}._executeEvent('onImageError',{element: this});"  />
%html%

 

Say you wanted to extract the 'src' attribute from this HTML. A simple string search for the text 'src=' would be wrong because it would get confused by the code for the onmouseover event handler.

 

dim attr as c
attr = *HTML_GET_ATTRIBUTE(html,"src")
? = src="pictures/5.jpg"


 

 

AlphaDAO - ResultSet - Generating JSON Data - .ToJSONObjectSyntax() Method - When you use the .ToJSONObjectSyntax() method to generate JSON data from a resultset, and you set the optional ConvertToText flag to .f. (it defaults to .t.), then date and date time values in the resultset now create Javascript date objects. For example:

 

dim cn as sql::Connection
cn.open("::Name::_northwind")

cn.PortableSQLEnabled = .t.
cn.Execute("select first 5 orderid, orderdate from orders")

rs = cn.ResultSet

?rs.ToJSONObjectSyntax(-1,-1,.f.,.f.)
= {"orderid" : 10255, "orderdate" : new Date(1952, 11, 18, 0, 0, 0, 0)}
{"orderid" : 10249, "orderdate" : new Date(1996, 6, 5, 0, 0, 0, 0)}
{"orderid" : 10250, "orderdate" : new Date(1996, 6, 8, 0, 0, 0, 0)}
{"orderid" : 10251, "orderdate" : new Date(1996, 6, 8, 0, 0, 0, 0)}
{"orderid" : 10252, "orderdate" : new Date(1996, 6, 9, 0, 0, 0, 0)}

 

Xdialog - Chrome Browser Control - Xdialog now allows you to embed the Chrome browser control. This allows you to build some amazing desktop applications using the full power of HTML, CSS3 and Javascript. This is a really fantastic new feature and all developers of desktop applications are strongly encouraged to check it out!

Previously, Alpha Anywhere allowed you to use the Internet Explorer ActiveX control in an Xdialog. While this is still possible, using the Chrome control is now so much easier and more powerful, that it is hard to imagine a scenario under which using the Internet Explorer ActiveX control would be preferable to using the Chrome control.

NOTE: With Internet Explore, some of Xdialogs that used the Internet Explorer ActiveX control have stopped working because of changes Microsoft has made to IE in IE Version 11. Using the Chrome control instead of the IE ActiveX control circumvents this issue.

With the Chrome control hosted in an Xdialog you can:

Since the HTML loaded in the Chrome control can use open source Javascript libraries, such as jQuery, you can build really powerful Xdialogs for your desktop applications using a myriad of techniques made possible by third party libraries. (See below for information on the a5_html_page_prepare() function.)

 

NOTE The code for all of the examples used here is available in the sample Learning Xdialog workspace that ships with Alpha Anywhere. To get an updated version of 'Learning Xdialog' you must do a full install, not a patch install.

 

A simple Xdialog that uses the Chrome Control

Watch video

 

Create a new script with this code:

 

dim cp as helper::Chrome
cp.html = <<%html%
<h1>Hello</h1>
<p>This is html inside an Xdialog.</p>
%html%

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=100,20cp};
%dlg%
dim dlg_event as c
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

And here is the resulting Xdialog when you run the code.

 

 

In the above code, notice that a new object is declared with the

dim cp as helper::Chrome

command.

Also notice that the HTML to display in the Chrome control was set by setting the .html property.

You can either set the object's .html property if you want to specify explicit HTML to display, or you can set the .url property (if you want to show a URL - see next example).

Once the Chrome object has been declared, it can be placed in the Xdialog using this Xdialog command:

{chrome=100,20cp};
 

In this above example, the width of the Chrome control is set to 100 'characters' and the height to 20 'lines'.

Notice that the 'cp' in the above command is the name of the helper::Chrome object that was defined.

You can put as many Chrome objects on an Xdialog as you want. For exmaple:

 

dim cp1 as helper::chrome

dim cp2 as helper::chrome

....

dim cpn as helper::chrome

 

And then in your Xdialog body:

{chrome=100,20cp1};
{chrome=100,20cp2};
{chrome=100,20cpn};
 

 

 

Specifying a URL to load

Watch video

 

 

dim cp as helper::Chrome
cp.url = "http://www.google.com"

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{stretch=height,width}
{chrome=100,30cp};
%dlg%
dim dlg_event as c
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

 

 

 

 

Specifying a Dynamic URL

 

In this next example we show how the URL property can be dynamically changed after the Xdialog has been rendered.

 

 

dim cp as helper::Chrome
cp.url = "http://www.google.com"

dim urls as c
urls = <<%txt%
http://www.google.com
http://www.bing.com
http://www.yahoo.com
%txt%

dim url as c
url = word(urls,1,crlf())

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{startup=urlchanged}
{stretch=width}
[.160url^+urls] <Go!urlchanged>;
{stretch=height,width}
{chrome=173,60cp};
%dlg%
dim dlg_event as c
dlg_event = <<%code%
if a_dlg_button = "urlchanged" then
    a_dlg_button = ""
    cp.url = url
end if
%code%
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

 

The resulting Xdialog looks like this:

You can type any address into the address bar and then hit the Go button to go to the page.

 

 

 

Notice that in the above code, when the user clicks on the Go button the  Xbasic that gets executed is:

cp.url = url

We simply set the URL of the Chrome object to the new URL and Chrome automatically navigates to the target URL.

 

 

Using Xbasic to Execute Javascript in the Chrome Control

The Chrome object exposes two methods that allows you to execute Javascript from Xbasic. These are:

<chromeObject>.executeJavascript(codetorun) - executes the Javascript asynchronously

<chromeObject>.executeJavascriptResult(codeToRun) - executes the Javascript synchronously and returns the result to Xbasic

 

Consider the following example of an Xdialog that is hosting the Chrome control, showing some HTML with an input control. We have to Xdialog buttons, one to set the value in the HTML input, and the other to read the value from the HTML input.

 

dim cp as helper::Chrome
cp.html = <<%html%
Name: <input id="name" />
%html%
dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=40,10cp};
<Set Name!setName> <Read Name!readName>;
%dlg%
dim dlg_event as c
dlg_event = <<%code%
if a_dlg_button = "setName" then
    a_dlg_button = ""
    dim jstorun as c
    dim name as c
    name = ui_get_text("Name","Enter name")
    jstorun = "document.getElementById('name').value = '" + js_escape(name) + "';"
    cp.ExecuteJavascript(jstorun)
else if a_dlg_button = "readName" then
    a_dlg_button = ""
    dim jstorun as c = "document.getElementById('name').value"
    dim result as c
    result = cp.ExecuteJavascriptResult(jstorun)
    ui_msg_box("Notice:","Value read from the HTML is: " + result)
end if
%code%
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)
 

 

The important thing to notice in this example is that the Javascript that gets executed here is computed by Xbasic and Xbasic is invoking the Javascript.

 

Using Javascript to Invoke Xbasic

In the previous example, we used Xbasic to invoke Javascript on the Chrome control. In this example, we turn it around and invoke Xbasic from Javascript.

This Xdialog has an event called 'event1' (see code in red below) and the HTML has a button. When the user clicks on the HTML button, the Xdialog event ('event1') is fired.

In order to make this work, a special Javascript function (called xDialogEvent) must be added to the HTML page. The onclick event for the button is then set to:

xDialogEvent('event1')

 

TIP: Because it is cumbersome to have to have to add the xDialogEvent() helper function to the HTML yourself, a special helper function can be called to 'prepare' the HTML you pass into the chrome object. For example:

dim cp as helper::Chrome
cp.html = a5_html_page_prepare(<<%html%
<button onclick="xdialogEvent('event1');">Invoke Event on My Parent Xdialog</button>
%html%)

 

dim cp as helper::Chrome
cp.html = <<%html%
<html>
    <head>
        <script>
        function xDialogEvent(eventName) {
            var client = new XMLHttpRequest();
            client.open('GET', 'a5xdialog:' + eventName,false);
            client.setRequestHeader('My-Custom-Header', 'Some Value');
            client.send();
        }
        </script>
    </head>
    <body>
        <button onclick="xDialogEvent('event1');">

        Invoke Event on My Parent Xdialog</button>
    </body>
 </html>
%html%

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=40,10cp};
%dlg%
dim dlg_event as c
dlg_event = <<%code%
if a_dlg_button = "event1" then
    a_dlg_button = ""
    ui_msg_box("Notice","This is Xbasic here. Event1 has just been fired.")
end if
%code%
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)


 

Using Built In Images

Alpha Anywhere comes with a large library of built in images and icons that you might want to use in the HTML that is shown in the Chrome control.

You can easily use built in images using this syntax:

 

<img src="a5res:images/$$application.chrome.png" />

 

The portion shown in red is the built in image name.

 

For example

 

dim cp as helper::Chrome
cp.html = <<%html%
<img src="a5res:images/$$code.aScript.png" />
<img src="a5res:images/$$file.open.png" />
<img src="a5res:images/a5_email_people.png" />

%html%

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=100,20cp};
%dlg%
dim dlg_event as c
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)
 

And the resulting Xdialog:

 

 

Referencing Static Resources

To display image files you can either use the special a5file prefix on the filename, or you can use the standard file:// protocol. However, in order to the use file:// protocol, you have to turn Chrome security off using the command shown in red.

 

 

dim cp as helper::Chrome
'in order to use the standard file:// protocol you have to turn

'Chrome's web security off.
'otherwise you can use use the special a5file: command.

cp.flag_web_security_disabled = .t.
cp.html = <<%html%
<img src="a5file:C:\Program Files (x86)\a5V12\a5v12logo.jpg" />
<br>
<img src="file://C:\Program Files (x86)\a5V12\a5v12logo.jpg" />
%html%
dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=100,20cp};
%dlg%
dim dlg_event as c
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)
 

 

And the resulting Xdialog:

 

Using the Chrome Debugger

You can use the Chrome debugger to debug Javascript that is running inside the Chrome control. For example, consider the following Xdialog.

The HTML has a Javascript function that executes a loop. The function uses the 'debugger;' Javascript command to turn on the debugger.

The Xdialog has a button that executes this code:

cp.OpenDevtools()

 

'cp' is the Chrome object (created by the dim cp as helper::Chrome command), and we are calling the object's .OpenDevTools() method to enable the Chrome Developer tools.

Once the Developer Tools have been opened, we can click the button on the HTML page to run the Javascript and debug into the code.

Watch Video

 

dim cp as helper::Chrome
cp.html = <<%html%
<script>
function loopTest() {

    debugger;
    for(var i = 1; i < 10; i++) {
        document.getElementById('div1').innerHTML = 'Count: ' + i ;
    }
}
</script>
<button onclick="loopTest();">Start Loop</button>
<div id="div1"></div>
%html%
 

dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=100,20cp};
<Open debugger!openDebugger>;
%dlg%
dim dlg_event as c
dlg_event = <<%code%
if a_dlg_button = "openDebugger" then

    'open the Chrome debugger
    a_dlg_button = ""
    cp.OpenDevtools()
end if
%code%
dlg_title = "Chrome in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)
 

 

Setting the Zoom Level of the HTML Document

You can set/get the zoom level of the HTML shown in the Chrome control by using these methods:

The level is a numeric value


 

Binding Events Programmatically

When you write the HTML that is displayed in the Chrome control you can either add events directly into the HTML markup, or you can bind the events programmatically using Xbasic.

For example, if your HTML included this markup:

 

<button onclick="myclickevent();">Button1</button>

 

then, when you ran the Xdialog and clicked on the button, the Javascript function myclickevent() would be invoked.

However if your HTML included this markup:

<button >Button1</button>

then, clicking on the button would do nothing because no event had been bound to the button.

Using methods of the Chrome control, you can bind event handlers to any element.

The syntax is:

<chromeObject}.AddEventListner(definition)

 

Where definition is a string in this format:

elementId|eventName|xdialogEventToFire

 

For example:

dim definition as c

definition = "btn1|click|xbasicEvent1"
cp.AddEventListeners(definition)

 

The definition string that you pass into the .AddEventListners() function can be a cr-lf delimited string. This allows you to bind events to multiple elements with a single call to the .AddEventListners() function.

 

 

 

The above code will bind an onClick event to an element with an id of 'btn1'. When the user clicks the button, the Xdialog event called 'xbasicEvent1' will be fired.

Note: We are using the .AddEventListeners() to invoke Xbasic (by calling an event in the parent Xdialog). We are NOT using the method to bind a Javascript event handler, since there are existing Javascript methods to bind Javascript events to elements.

Watch video to see an example of using the .AddEventListners() method.

Watch video - Part 1

Watch video - Part 2

Download sample code used in video

 

The .AddEventListners() function can be called before the Xdialog is even instantiated. There is no need to wait for Xdialog and the Chrome control inside the Xdialog to be ready. For example, consider the following script:

 

 

dim cp as helper::Chrome

html = <<%html%

<div id="div1">This is div1</div>

<button id="b1">Button1</button>

<button id="b2">Button2</button>

%html%

cp.html = html


'notice that the event binding is defined before the xdialog has even been rendered!

dim mapping as c 

mapping = <<%txt%

b1|click|event1

b2|click|event2

%txt%

cp.AddEventListeners(mapping)


dim dlg_title as c = "Binding Multiple Events Handlers at Once"

dim dlg_body as c 

dlg_body = <<%dlg%

{chrome=80,10cp};

%dlg%

dim dlg_event as c 

dlg_event = <<%code%

if a_dlg_button = "event1" then 

    a_dlg_button = ""

    ui_msg_box("Notice","Event 1 has fired")

else if a_dlg_button = "event2" then 

    a_dlg_button = ""

    ui_msg_box("Notice","Event 2 has fired")

end if 

%code%

ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

 

 

Setting/Getting Attributes and Values Programmatically

When you host a Chrome control in an Xdialog you will often want to manipulate attributes of the HTML that is displayed using Xbasic.

You can obviously do this by using Xbasic to send Javascript to the Chrome control (using the <chromeObject>.executeJavascript() method), but a more direct method is available using methods of the Chrome object that let you directly manipulate the DOM.

For example, say you want to set the Inner HTML of a div with the id of 'div1'.

You Xdalog could execute this code

 

dim js as c

js = "document.getElementById('div1').innerHTML = '" + js_escape("some text") + "'; "

cp.ExecuteJavascript(js)

 

However, the .SetInnerHTML() method provides a more direct way of accomplishing this. For example

cp.SetInnerHTML("div1","some text");

 

NOTE: The js_escape() function is a helper function that ensures that all text in the string is properly escaped so as not to cause Javascript errors.

Similarly you can use the following methods:

HasElement(elementId) - indicates whether the specified elementId is present
HasAttribute(elementId,attributeName) - indicates if the specified element has the specified attribute
GetAttribute(elementId,attributeName) - gets the value of the specified attribute from the specified element
SetAttribute(elementId,attributeName,attributeValue) - sets the value of an attribute
GetInnerText(elementId) - gets the inner text property of an element
GetValue(elementId) - gets the value of element (for example, an INPUT control)
SetValue(elementId,value) - sets the value of an element
GetOuterHtml(elementId) - gets the outer html for an element
GetInnerHtml(elementId) - gets the inner html for an element
SetInnerHtml(elementId,value) - sets the inner html of an element

 

Example code

 

dim cp as helper::Chrome
html = "<div id=\"div1\">This is div1</div>"
cp.html = html
dim dlg_title as c
dim dlg_body as c
dlg_body = <<%dlg%
{chrome=80,10cp};
<Set Inner HTML of div1!setdiv>;
<Set Attributes on div1!setattr>
%dlg%
dim dlg_event as c
dlg_event = <<%code%
if a_dlg_button = "setdiv" then
    a_dlg_button = ""
    cp.SetInnerHtml("div1","Test Alpha Anywhere's ability to set the Inner HTML of an element.")
else if a_dlg_button = "setattr" then
    a_dlg_button = ""
    cp.SetAttribute("div1","style","border: solid 1px blue; border-radius: 10px; background: yellow;")
end if
%code%
 

dlg_title = "Using Google Charts in a Chrome Control in an Xdialog"
ui_dlg_box(dlg_title,dlg_body,dlg_event)


 

 

Using Google Charts in an Xdialog

You can use the Google Charts API to add charting to your Xdialogs. For example, the image below shows an Xdialog with a Google chart.

For example, the image below shows an Xdialog with a Google chart.

 

Watch video

Download code

 

 

TIP: In addition to watching the above videos, you might also find these videos helpful. They show how Googl Charts can be used in a UX Web component and they give more background information on using the Google API documentation to get working code samples:
Watch Video - Part 1
Watch Video - Part 2

 

 

 

Using the Alpha Anywhere Javascript Library, Styles and 3rd Party Javascript Libraries

A huge advantage of being able to use the Chrome control in your Xdialogs is the ability to use Alpha Anywhere Javascript libraries and styles and 3rd party libraries and styles in your Xdialog.

A special helper function called a5_html_page_prepare() makes it very easy to create the HTML page that you will load into the Chrome control with all of the libraries and styles that you want.

The function takes some input HTML and then adds the necessary code to your input HTML to load the Javascript and styles that you specify.

 

The function syntax is:

c html = a5_html_page_prepare(C html [,C javascriptLibrariesPublic [,L flagIncludeA5JSlibraries [,C A5StyleName [,C jQueryTheme [,L flagIncludeGoogleJSAPI ]]]]])

 

where:

 

The javascriptLibrariesPublic Parameter

The following libraries can be loaded.

For each library that you load, you can specify an optional build number. The syntax is:

libraryName|buildNumber

 

If you leave out the buildNumber then the most recent build on the Google CDN as of December 1, 2013 is loaded.

If you set the buildNumber to 'internal' then the code is loaded from the Google CDN and then cached locally so that future loads are faster.

 

Example

 

dim html as c

html = ""

html = a5_html_page_prepare(html,"jquery|internal,jquery ui|internal,angularjs|internal",.t., "iOS","Sunny")

 

In the above example:

 

IMPORTANT: When you specify that Alpha Anywhere Javascript library and jQuery should be loaded the jQuery object is automatically changed from its default '$' to 'jQuery'.

 

For example, in the code below, the jQuery date picker is used for the input control.

 

Watch video

 

 

dim html as c
html = <<%html%
<body class="{style}Page">
    <p>This input control uses the jQuery Date Picker</p>
    <input id="dt1" name="dt1" value="1/1/2013"/>
    <script>
    jQuery('#dt1').datepicker(
        {
            onSelect: function(dateText, inst) {
                $e.execute(this,'change')
            }
        }
   );
   </script>
</body>
%html%
 

html = a5_html_page_prepare(html,"jquery|internal,jquery ui|internal",.t., "MobBlue","Sunny")
 

dim cp as helper::Chrome
cp.html = html
ui_dlg_box("Xdalog with Chrome Control - Using jQuery",<<%dlg%
{stretch=width,height}
{chrome=150,50cp};
%dlg%,<<%code%
%code%)

 

And the resulting Xdialog

 

 

Using the .OnReady() Event

The Chrome control has an .OnReady() event that fires, and executes Xbasic, once the control has been initialized.

For example:

 

dim cp as helper::Chrome

html = <<%html%

<div id="div1">This is div1</div>

%html%

cp.html = html


'the onReady event fires when the chrome control has been initialized

cp.OnReady = "ui_msg_box(\"Notice\",\"The Chrome control has been initialized.\")"


dim dlg_title as c 

dim dlg_body as c 

dlg_body = <<%dlg%

{chrome=80,10cp};

%dlg%

dim dlg_event as c 

%code%

dlg_title = "Xdialog"

ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

Notice: The .onReady() event executes Xbasic code, not Javascript. If you want to fire Javascript when the Chrome control is ready, simply put an onload event in the <body> tag of the HTML you display in the control. For example:

<body onload="myfunction()">

</body>

 

Summary of Properties and Methods of the Chrome Object

When you dim a Chrome object, the resulting object instance has many properties and methods that are exposed to Xbasic.

For example

dim cp as helper::chrome

 

When the above Xbasic is executed, the resulting Xbasic variable 'cp' has various method and properties, which are summaries here:

 

 

Properties

url - allows you to set the URL for the page to be shown in the Chrome control
html - allows you to set the HTML to be shown in the Chrome control
error   gets set if you call Javascript and there is an error, or if there is an error loading the page

flag_web_security_disabled  
flag_allow_file_access_from_url
flag_allow_universal_file_access_from_url
flag_page_cache_disabled
flag_caret_browsing_enabled
flag_databases_disabled
flag_plugins_disabled
flag_java_disabled
flag_javascript_disabled
flag_dom_paste_disabled
flag_encoding_detector_enabled
flag_drag_drop_disabled
flag_load_drops_disabled
flag_history_disabled
flag_remote_fonts_disabled
flag_image_load_disabled

 

Methods

ExecuteJavascript(code) - executes some Javascript
ExecuteJavascriptResult(code) - executes some Javascript and returns a result to Xbasic
Print() - invokes the Chrome control's print dialog
GoBack()
GoForward()
Reload() - reload the current page
Stop() - stops the page loading
GetZoomLevel() - gets the numeric zoom level
SetZoomLevel(level) - sets the zoom level
OpenDevtools() - opens the Chrome developer tools
CloseDevtools() - closes the Chrome developer tools
OnReady(xBasicCode) - executes Xbasic code when the Chrome control has been initialized.

 

NOTE: The tasks performed by the following method could just as well be done by using the .ExecuteJavascript() or .ExecuteJavascriptResult() methods. However, since these methods that go directly against the DOM without having to execute Javascript, they are more convenient to use.

HasElement(elementId) - indicates whether the specified elementId is present
HasAttribute(elementId,attributeName) - indicates if the specified element has the specified attribute
GetAttribute(elementId,attributeName) - gets the value of the specified attribute from the specified element
SetAttribute(elementId,attributeName,attributeValue) - sets the value of an attribute
GetInnerText(elementId) - gets the inner text property of an element
GetValue(elementId) - gets the value of element (for example, an INPUT control)
SetValue(elementId,value) - sets the value of an element
GetOuterHtml(elementId) - gets the outer html for an element
GetInnerHtml(elementId) - gets the inner html for an element
SetInnerHtml(elementId,value) - sets the inner html of an element

 


AddEventListeners(definition) - binds an event handler to an element. See section above 'Binding events programmatically'
DropEventListeners(elementId) - drops an event listener.

 

 

 

Tips

AlphaDAO - SQL Server - Stored Procedures - Output Arguments - If you have a SQL server stored procedure that sets the value of an output argument, reading the value in the output argument, after the stored procedure has executed can be tricky. That's because you have to ensure that you first loop through all of the result sets that are returned by the stored procedure before reading the output arguments.

 

Consider the following trivial stored procedure:

 

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE TestSP
-- Add the parameters for the stored procedure here
@InParam CHAR(10),
@OutMessage CHAR(50) OUTPUT

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SET @OutMessage = 'initialized'

END
GO

 

From the interactive window:

 

dim cn as sql::Connection
cn.open("::Name::sqlserver")
delete args
dim args as sql::Arguments
dim Message as c = "test message"

'need to pad out the argument so it matches the definition in the stored procedure
message = padr(Message,50," ")
args.set("InParam" , "1234567890")
args.set("OutMessage",Message,sql::ArgumentUsage::InputOutputArgument)
?cn.Execute("{CALL TestSP(:InParam, :OutMessage)}",args)
= .T.
 

 

Now try to read the output parameter value

?args[2].data

= "Initialized"

 

 

Notice that this worked as expected. But it only worked because the stored procedure did not return any resultsets.

 

Now let's modify the stored procedure so that it returns two resultsets:

 

USE [Northwind]
GO
/****** Object: StoredProcedure [dbo].[TestSP] Script Date: 12/6/2013 1:25:13 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TestSP]
-- Add the parameters for the stored procedure here
@InParam CHAR(10),
@OutMessage CHAR(50) OUTPUT

AS
BEGIN
select * from customers
select * from employees
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
select * from customers
SET @OutMessage = 'initialized'

END
 

 

Now, From the interactive window:

 

dim cn as sql::Connection
cn.open("::Name::sqlserver")
delete args
dim args as sql::Arguments
dim Message as c = "test message"

'need to pad out the argument so it matches the definition in the stored procedure
message = padr(Message,50," ")
args.set("InParam" , "1234567890")
args.set("OutMessage",Message,sql::ArgumentUsage::InputOutputArgument)
?cn.Execute("{CALL TestSP(:InParam, :OutMessage)}",args)
= .T.
 

 

Now try to read the output parameter value

?args[2].data
= "test message"
 

This is not what we expect!. The output parameter cannot yet be read because we have not yet looped through all of the result sets returned by the stored procedure.

 

So, execute:

?cn.ResultSet.NextResult()

= .t.

and again:

?cn.ResultSet.NextResult()

= .t.

and again (the .f. return value tells you that there are no more resultsets):

?cn.ResultSet.NextResult()

= .f.

 

Now, that there are no more resultsets, you can read the output arguments:

?args[2].data

= "initialized"

 

 

 

Build 1839-4234  10 Dec 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Notice

UX Component - List - Change in Behavior - Clicking on 'whitespace' in the list (if there are not enough rows to fill the list), the list header, or list footer/header/footer will no longer de-select the current selection. Therefore the onclick event will no longer fire when the user clicks on whitespace, the header, or the footer (which includes the 'Fetch More' button, if the list is paginated using the 'Fetch More' option).

De-selecting the current selection when clicking off the list was an unintended consequence of an important optimization added to the List in a recent update.

Grid and UX Component - Auto-suggest and Edit-combo Controls - SQL Data Sources - Null Values - If the list of data to be shown in the auto-suggest or edit-combo included null values, Javascript errors might occur.

 

Bugs

UX Component - Slider Control - Dates - Setting Min and Max Value - If the slider control was configured to return date values, then setting the starting date value on the slider to a date that did not start on the 1st of the month would sometimes fail. This is now fixed. Here is a sample Javascript code that sets the slider start date to a value read from another control on the UX and then sets the end date to the start date + 90 days.

 

function setStartAndEnd() {
    var dob = {dialog.object}.getValue('dob');
    var s = {dialog.object}.getControl('sl1');

    var d1 = new Date();
    d1.fromFormat(dob,'MM-dd-yyyy');

 

    //set min and max with a date string using the date format specified
    s.min = dob;
    d1.setDate(d1.getDate() + 90);
    s.max = d1.toFormat('MM-dd-yyyy');
    s.refresh();

}

 

 

Build 1826-4231  4 Dec 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Videos

UX Component Using Google Charts as an Alternative to the Built-in Chart Controls The UX component contains a powerful built-in chart control (based on the Microsoft .Net visualization library). This is a 'server-side' control (meaning that the chart is rendered on the server and then the resulting image is sent to the browser. However, there may be times when you want 'client-side' charting (i.e. charts that are rendered using Javascript). The Google Chart API is perfect for this. (Note: There are number of high quality open source Javascript libraries that you can choose from).

In this video we show how you can use the Google Chart API to add client-side charts to a UX component.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Using SQL data in a Google Chart In previous videos we have shown ho easy it is to use Google Charts in a UX component by simply copying code from the Google Charts API documentation. However, in all of the example in the Google Chart API documentation, the data plotted by the chart is static (i.e. it is hard coded into the Javascript).

Of course, in a real application, it is likely that you will want to query a SQL database to get the data to be plotted on the chart. In this video we show an example of how this can be done.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download Component
UX Component Control Behavior Overrides - Customizing The Data Picker and Edit-Combo Behavior on a Phone The UX component allows you to customize the behavior of certain controls based on the screen size of the device. For example, normally, the 'picker' for a date control, or an edit-combo control opens in a drop-down window, immediately under the control. However, on a phone, which has a narrow screen, there is not enough room to display the control's 'picker' in a dropdown window. Instead, you are likely to want the control to appear in a window that is docked to the bottom of the screen, centered horizontally.

In this video we show how you can define Javascript to override the behavior of certain controls, depending on the screen size.


Watch Video
     

 

Notice

Report Server - The Report Server code was previously part of the A5ApplicationServer.exe executable. Now, the Report Server has been moved into its own executable - A5reportserver.exe. When you install the Application Server patch you will notice this new executable has been installed. If you have both the Application Server and the Development version installed on the same computer and you want to be able to use the Report Server when printing reports using the server in the Development version, copy the a5reportserver.exe file from the folder where the Application Server is installed to the folder where the Development version is installed.

Bugs

HTML Editor - Internet Explorer V11 - As a result of changes Microsoft made to Internet Explorer V11, the HTML editor (which is based on the Internet Explorer ActiveX control) would fail to open under certain circumstances. While it is still not clear exactly what change Microsoft made, a work around has been found and now the HTML editor will work if you have IE11 installed.

UX Component - Absolute Layout Editor - Internet Explorer 11 - Has been re-written to remove its dependency on the Internet Explorer 11 ActiveX control. As a result, this editor will now work correctly even if you have Internet Explorer 11 installed. Previously, the editor would fail if you had Internet Explorer 11 installed.

 

UX Component - Web Style Builder - Internet Explorer 11 - Has been re-written to remove its dependency on the Internet Explorer 11 ActiveX control. As a result, this editor will now work correctly even if you have Internet Explorer 11 installed. Previously, the editor would fail if you had Internet Explorer 11 installed.

 

UX Component - List Control - onTap Event - this.value - The previous update introduced a bug causing the this.value in an abstract onTap event to be wrong.

Reports - Absolute Layout - Images - Internet Explorer - The image background on an Absolute Layout cell did not render properly in Internet Explorer under certain circumstances.

Grid Component - DBF Tables - Export to Excel - International Characters - International characters did not export to Excel correctly from a Grid if the Grid was based on a .dbf table. There is no problem with Grids that use SQL tables.

Features

UX Component - Server Side Event Handlers - Data Submitted  - JSON - When the UX makes any type of Ajax callback, the data that are submitted (including data in Repeating Sections) are now available in a convenient new property called

e.dataSubmittedJSON

 

For example, assume your UX had the following controls:

Firstname, Lastname and a Repeating Section called 'CONTAINER_1' with AddressType and Address.

The e.dataSubmittedJSON value might look like this:

{

    FIRSTNAME: 'Fred',

    LASTNAME: 'Smith',

    CONTAINER_1: [

        {

            ADDRESSTYPE: 'Work',

            ADDRESS: '123 Main St'

        },

        {

            ADDRESSTYPE: 'Home',

            ADDRESS: '456 Center St'

 

        }

    ]

}

You can use the Xbasic JSON_Parse() function to parse this JSON string.

 

 

UX Component - Mobile Devices - Control Behavior Overrides - The UX component allows you to customize the behavior of certain controls based on the screen size of the device. For example, normally, the 'picker' for a date control, or an edit-combo control opens in a drop-down window, immediately under the control. However, on a phone, which has a narrow screen, there is not enough room to display the control's 'picker' in a dropdown window. Instead, you are likely to want the control to appear in a window that is docked to the bottom of the screen, centered horizontally.

To define control behavior overrides, click the smart field button for the 'Control behavior overrides' property on the UX Properties pane.

 

Watch Video

 

This will open a dialog where you can insert the Javascript that defines the behavior override. The behavior override is expressed in the form of Javascript code that uses the A5.override.add() function to define the behavior override.

For example, in the code snippet shown below, the behavior of the 'Edit-combo' control is changed when the screen size is less than 500 pixels.

 

/*
if the width of the viewport is less than 500px make datePickers and edit-combos
pop up from the bottom of the screen, centered horizontally
*/
var vpSize = AUI.u.getVPSize();
if(Math.min(vpSize.width,vpSize.height) < 500){
    A5.overrides.add('editCombo',{
        base: {
            decouple: true,
            window: {
                width: '100%',
                height: '50%',
                pointer: {show: false},
                location: ['dock','bottom'],
                animation: {
                    show: {type: 'css-slide'}
                }
            }
        }
    }

    );
}

 

NOTE: The 'base' behavior of the control is defined in the style.js file. For example, if you are using the iOS style, then the base behavior is defined in the css/iOS/style.js file in your executable folder.

 

 

 

 

UX Component - List Control - NULL Values - If your data has NULL values, you can now specify the text to show for the NULL values. For example, you might want to show n/a for null values.

You can include HTML markup in the text to display.

The new property is on the List Properties pane.

 

UX Component - List Control - onDownHold Event - A new event, onDownHold has been added to the List control.

Add_bus_days() and Bus_days_between() Functions - SQL 'Holidays' Table - These two functions can now use a SQL table as the data source for the list of holiday dates.

To specify a SQL table, the 'holidayTable' argument that is passed into the function is in the form of a JSON string with these properties:

 

 

 

Example:

days = Bus_days_between(  {12/1/2013},{12/31/2013},"yes","{connectionstring: 'myconnstring', table: 'holidays', column: 'dates'}")

 

days = Bus_days_between(  {12/1/2013},{12/31/2013},"yes","{connectionstring: 'myconnstring', table: 'holidays', column: 'dates', filterColumn: 'country', filterColumnType: 'c', filterValue: 'USA'}")

 

 

 

a5_sql_nested_query_to_json_document() Function - Queries one or more SQL databases and returns a JSON document with the query result.

This function is inspired by NoSQL databases that return a JSON document with a query result. The JSON document return by such a query often contains nested JSON documents (for example for each customer, show orders for that customer, and for each order, show order details for that order).

For example, here is a sample JSON document returned by this function showing customers, nested orders, and nested order details:

{
    "customer": [
        {
            "customerId": "HUNGO",
            "companyName": "Hungry Owl All-Night Grocers",
            "orders": [
                {
                    "orderid": "10298",
                    "customerid": "HUNGO",
                    "value": "10298",
                    "orderDetails": [
                        {
                            "OrderID": "10298",
                            "ProductID": "2",
                            "UnitPrice": "15.2",
                            "Quantity": "40",
                            "Discount": "0"
                        }
                    ]
                },
                {
                    "orderid": "10309",
                    "customerid": "HUNGO",
                    "value": "10309",
                    "orderDetails": [
                        {
                            "OrderID": "10309",
                            "ProductID": "4",
                            "UnitPrice": "17.6",
                            "Quantity": "20",
                            "Discount": "0"
                        },

                        truncated for brevity....
 

 

The syntax for the function is

P result = a5_sql_nested_query_to_json_document( P options, SQL::Arguments Args)

 

The result object that is returned has these properties

 

The options object that is passed into the function has these properties:

 

 

Example options.SQL parameter:

 

options.sql = <<%txt%
{sql: 'select * from customers where country = :whatCountry ', name: 'customer' }
    {sql:'select * from orders', name: 'orders', parentKey: 'cId', key: 'cId'}
%txt%

 

Notice that the options.sql property is a CRLF delimited string of JSON strings in this format:

options.SQL = <<%txt%

{JSON string 1}

    {JSON string2}

%txt%

 

The fact that {JSON string 2} is indented (using a single Tab character NOT spaces) is significant. The indentation indicates that this query is an immediate child of the query in the line above it.

You can have multiple levels of indentation. and multiple queries with the same parent, for example:

options.SQL = <<%txt%

{JSON string 1}

    {JSON string2}

        {JSON string 3}

    {JSON string 4}

%txt%

 

In the above example, the SQL query defined by {JSON string 3} is a child of {JSON string2}. The query defined by {JSON string 1} has two child queries. A real world example of an hierarchy that would be defined using the above structure might be:

 

Customers

`    Orders

            OrderDetails

    Payments

 

The individual JSON strings each have these properties

 

 

 

Example 1 - Simple two level query

dim ops as p
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers where country = :whatCountry ', name: 'customer' }
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId'}
%txt%
dim args as sql::Arguments
args.add("whatCountry","France")
p = a5_sql_nested_query_to_json_document(ops,args)
?p.data

 

 = {
    "customer": [
        {
            "CustomerID": "BLONP",
            "CompanyName": "Blondesddsl père et fils",
            "ContactName": "Frédérique Citeaux",
            "ContactTitle": "Marketing Manager",
            "Address": "24, place Kléber",
            "City": "Strasbourg",
            "Region": null,
            "PostalCode": "67000",
            "Country": "France",
            "Phone": "88.60.15.31",
            "Fax": "88.60.15.32",
            "image": null,
            "imageThumb": null,
            "orders": [
                {
                    "OrderID": "10265",
                    "CustomerID": "BLONP",
                    "EmployeeID": "2",
                    "OrderDate": "07/25/1996 12:00:00 00 am",
                    "RequiredDate": "08/22/1996 12:00:00 00 am",
                    "ShippedDate": "08/12/1996 12:00:00 00 am",
                    "ShipVia": "1",
                    "Freight": "55.28",
                    "ShipName": "Blondel père et fils",
                    "ShipAddress": "24, place Kléber",
                    "ShipCity": "Strasbourg",
                    "ShipRegion": null,
                    "ShipPostalCode": "67000",
                    "ShipCountry": "France"
                },
                {
                    "OrderID": "10297",
                    "CustomerID": "BLONP",
                    "EmployeeID": "5",
                    "OrderDate": "09/04/1996 12:00:00 00 am",
                    "RequiredDate": "10/16/1996 12:00:00 00 am",
                    "ShippedDate": "09/10/1996 12:00:00 00 am",
                    "ShipVia": "2",
                    "Freight": "5.74",
                    "ShipName": "Blondel père et fils",
                    "ShipAddress": "24, place Kléber",

 

                    truncated for brevity......

 

 


 

Example 2 - Simple three level query

 


dim ops as p
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers where country = :whatCountry ', name: 'customer' }
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId'}
        {sql: 'select * from [order details]', name: 'orderDetails', parentKey: 'orderId', key: 'orderId'}
%txt%

 


dim args as sql::Arguments
args.add("whatCountry","France")
p = a5_sql_nested_query_to_json_document(ops,args)
 

 



 

Example 3 - Three level query where each query is in a different database (the connection string is specified for each query).

 


'since each query specifies its own connection string, the flagUseSubSelects flag must

'be set to .f.


ops.flagUseSubSelects = .f.
ops.sql = <<%txt%
{sql: 'select * from customers where country = :whatCountry ', name: 'customer' , connectionString: '::Name::northwind'}
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId', connectionString: '::Name::northwind2'}
        {sql: 'select * from [order details]', name: 'orderDetails', parentKey: 'orderId', key: 'orderId' , connectionString: '::Name::northwind2'}
%txt%
dim args as sql::Arguments
args.add("whatCountry","France")
p = a5_sql_nested_query_to_json_document(ops,args)


 

 

Limiting the Number of Child Records

If you want to limit the number of records retrieved at any level in the hierarchy, you can.

To limit the number of records at the top level of the hierarchy, you would simply use the FIRST clause in your SQL select statement. However, for child queries, using the FIRST clause in the SQL will not work (because you want the FIRST n records within EACH parent group, not the FIRST n records in ALL parent groups).

To limit the number of records in a child query, you use the 'limit' property in the JSON object that defines the query.

For example in the code shown below we are fetching the first 5 orders for each customer:

 

dim ops as p
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers', name: 'customer' }
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId', limit: 5}
%txt%
 

 

NOTE: If you do use a FIRST clause in a child SQL statement, the SQL statement is automatically parsed and the FIRST clause is removed and converted into a 'limit' property in the JSON definition. So, the following two objects are actually equivalent:

 

dim ops as p
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers', name: 'customer' }
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId', limit: 5}
%txt%
 

 

dim ops as p
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers', name: 'customer' }
    {sql: 'select FIRST 5 * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId'}
%txt%
 

 

 

Eliminating Key Values

By default, the JSON that is created shows the parent key value in the child data. For example in the example JSON shown below (which shows a customer, and all of their orders), the 'CustomerID' property is shown n each item in the 'orders' array. This is really not necessary.

 

 = {
    "customer": [
        {
            "CustomerID": "BLONP",
            "CompanyName": "Blondesddsl père et fils",
            "ContactName": "Frédérique Citeaux",
            "orders": [
                {
                    "OrderID": "10265",
                    "CustomerID": "BLONP",
                    "EmployeeID": "2",
                    "OrderDate": "07/25/1996 12:00:00 00 am",
                    "ShipVia": "1",
                    "Freight": "55.28",
 

 

In order to suppress parent key values in child records, you can set the 'sparse' property to .t. in the object you pass into the a5_sql_nested_query_to_json_document() function. For example:

 

dim ops as p

ops.sparse = .t.
ops.connectionString = "::Name::northwind"
ops.sql = <<%txt%
{sql: 'select * from customers', name: 'customer' }
    {sql: 'select * from orders', name: 'orders', parentKey: 'customerid', key: 'customerId', limit: 5}
%txt%
 

 

Preserving Data Types in the JSON

You can use the convertToText property in the options that you pass in to control whether the generated JSON converts all data to strings, or preserves data types.

For exmaple:

 

ops.convertToText = .f.
p = a5_sql_nested_query_to_json_document(ops,args)

 

would result in JSON that looked like this:

 

 "customer": [
                {
                    "customerId": "GREAL",
                    "companyName": "Great Lakes Food Market",
                    "orders": [
                                    {
                                        "orderid": 10528,
                                        "orderdate": new Date(1997,05,06,00,00,0),
                                        "value": 10528,
                                        ........

 

Notice that the 'orderDate, orderId, and value properties are typed.

Tips

UX Component - List Controls - onClick Event - List Headers and Footers - If you have defined a header or a footer for List control, and you have also defined an onClick event, you will notice that the onClick event fires when you click on either the header or the footer.

In your application, this might not be desirable. If so, then you can use the onTap event, rather than the onClick event, or alternative, in the onClick event, you can test what row index the user clicked on. The row index is 0 based, and will return -1 if the user clicked on either the header or the footer. Your onClick event would then be:

if( arguments[0] > -1) {

    //your onClick code goes here

}

 

 

 

Grid Component - Alphabet Buttons Spacing - Different Browsers - Because of difference in the amount of default margin sizes the different browsers use for buttons, Alphabet button in a Grid will render slightly differently in different browsers, as shown in the image below.

 

To fix this problem, you can add the following markup to the AboveGrid free-form edit region:

<style>
    .{grid.style}Grid button {
        margin: 0px;
    }
</style>

 

 

Build 1794-4227  18 Nov 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

Bugs

UX Component - Slider Control - Slider Message - If you turned on the slider message, but did not have an onChange event defined, you would get an error when trying to save the component. If you had defined an onChange event, there was no error.

 

Build 1790-4226  16 Nov 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Bugs

Internet Explorer 8 - Fixed an issue that would occasionally result in a page failing to load in Internet Explorer Version 8.

Tabbed UI - Print Reports - HTML - The Breaking Change described in the release notes for build 1788-4225 is no longer true. It is not necessary to recalculate Tabbed UI components.

Features

API_UUIDSEQCREATE Function - Similar to the existing API_UUIDCREATE() function, but creates the GUIDs in sequential order.

 

? API_UUIDSEQCREATE

= "e220817f-4e10-11e3-8ac1-e0cb4e1cb692"

? API_UUIDSEQCREATE

= "e2208180-4e10-11e3-8ac1-e0cb4e1cb692"

? API_UUIDSEQCREATE

= "e2208181-4e10-11e3-8ac1-e0cb4e1cb692"



 

? API_UUIDCREATE()

= "e57b36bb-ba36-48a5-990d-fccf0ac18307"

? API_UUIDCREATE()

= "561f9dcf-8c5a-4485-8f65-a99fdfff4195}"

? API_UUIDCREATE()

= "2e1f5004-9a83-4d90-8da7-3fdc6c8a244a"

 

 

 

*guid_seqcreate() Function - Similar to the existing *guid_create() function, but creates the GUIDs in sequential order.

 

?*guid_create()
= "{c4bc6cbc-d5a8-44a8-aada-3e94cf5e868f}"
?*guid_seqcreate()
= "{ae059bff-51f0-11e3-89bf-f04da23a263b}"
 

 

Build 1788-4225  15 Nov 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

 

Breaking Changes

Tabbed UI - Print Reports - HTML - If your Tabbed UI has any buttons that print reports with the initial view set to HTML then you will need to recalculate the button that opens the report. To do this, edit the Tabbed UI component, then click the Menu button and select 'Recalculate all controls'. If you don't recalculate the button, you will get this error when you try to print the report: 'phtm.pdfOptions not found'.

 

Videos

 

UX and Grid Component Accordion Control - Changing the Background Color of the Pane Selector When you define the properties of an Accordion control you can specify class names to apply to the Title Band when the band is opened, closed, or disabled. This can be used to change the appearance of the title band depending on its state.

In this video we show how the background color and font title of the title band can be dynamically controlled through custom CSS classes.

Watch Video
     

Bugs

Reports - Session Variables - Calculated fields that referenced Session variables were not displaying the value of session variable.

UX Component - Server-side Action Scripting - Send Email Action - If you specified that the e-mail body should be read from the repository table, and that the name of the item in the repository was based on a field in the UX (rather than a hard coded name), the action did not retrieve the entry in the repository correctly.

 

Web Component - Styles - Global Styles -  If you used the Style Editor to create a new global style, the global style folder was not in the correct location. It was placed in a folder called 'Shared Resources' in the current Project. It should have been one folder up in the .WebProjects (plural) folder.

 

Grid Component - Detail View - Edit On Demand - Date Picker, Edit-Combo, Auto-suggest - Did not work if the Detail View as set to 'Edit on Demand' mode.

 

sql_lookup() Function -  The function will now accept a blank filter expression and return all values. Previously, if the "result_Expression" in the function was a comma delimited list of fields, the function would return only the first field in the list for the first record found if the option "flagReturnAllValues" was false. It now returns all fields listed in "result_Expression" for the first record found when "flagReturnAllValues" is false.

The function now has an optional parameter for a column delimiter that is only added between fields if the expression is a comma delimited field list. The default column delimiter is a tab.

IMPORTANT: If sql_lookup() specifies a filter and returns a single field in the return expression, the return value is correctly typed. If more than one value is returned, or no filter is specified, the return value is a character string.

 


sql_records_get() Function - Now allows a blank filter expression which will return all records.

 

UX Component - Client-Side Calculated Fields - In certain cases Javascript rounding errors in math calculations were causing wrong values to be displayed.

Application Server  - Report Server - Multiple Application Servers - If you were running multiple instances of the Application Server on a machine, the Report Server did not work correctly.

Reports - Web Applications - Reports - Report Server - If a SQL connection string contained high order characters, it could cause the report to fail.

 

Forms - Desktop Applications - Web Content Chrome -  The Toolbox now has a new item 'Web Content Chrome'. This controls duplicates the functionality of the 'Web Content' control, but uses Chrome and not Internet Explorer to render the content. For example, you can use this control to render Google Maps on the form.

Forms - Desktop Applications - Google Maps Supercontrol - Fixes issues with this control. You now can create a Google Map supercontrol on a form using either the 'Web Content' control (uses Internet Explorer) or 'Web Content Chrome' (uses Chrome).

UX Component - Client-side Calculated Fields - Round() Function - The round() function in client-side calculated fields was using the built-inJavascript Math.round() method to round values. The Javascript Math.round() function rounds negative numbers differently that some people might expect (and differently than Excel does, for example).

For example:

Math.round(-4.5,0)  returns -4

 

However, Excel returns -5.

To be consistent with Excel's behavior (which is likely what most users would expect), when the Round() function is used in a client-side calculation, it now uses the Excel convention.

Behind the scenes, the round() function in a client-side calculation is actually translated into the built-in $u.n.round() function in the Alpha Anywhere Javascript library. This function now takes these optional flags

For example:

$u.n.round(4.25,1)= 4.3
$u.n.round(-4.25,1) = -4.3

$u.n.round(4.25,1,'u') = 4.3
$u.n.round(-4.25,1,'u') = -4.2

$u.n.round(4.25,1,'d') = 4.2
$u.n.round(-4.25,1,'d') = -4.3

$u.n.round(4.25,1,'a') = 4.3
$u.n.round(-4.25,1,'a') = -4.3

$u.n.round(4.25,1,'t') = 4.2
$u.n.round(-4.25,1,'t') = -4.2
 

 

Features

UX Component - List Control Performance - The way in which events are bound to List controls elements has been improved. This will result in a improvement in performance when doing an orientation change on the device and switching to a different List layout based on the orientation.

 

Reports - Layout Table Reports - Project Reports - Text Dictionary - You can now insert text dictionary tags in Layout Table reports defined at the Project level. Workspace reports do not support Text Dictioanries.

For example, you can specify the title of a column in a Layout Table report as

<a5:t>title1</a5:t>

When the report is printed, the text dictionary tags are resolved.

NOTE: To define the Text Dictionary, go to the Project Properties dialog on the Web Control Panel.

 

To define entries in the Text Dictionary, select the Text Dictionary... command from the Report menu in the Layout Table Report Editor.

 

 

When you preview your report, you can specify which Language you want to use by selecting the 'Default Language for Text Dictionary...' command on the Report menu.

 

 

When you define a Layout Table report, the Cell Contents dialog allows you to edit the contents of a cell in the Layout Table. If you want to use Text Dictionary tags on some static text, you must check the 'Is Template' checkbox as shown below.

 

 

When you click the 'Is Template' checkbox, then <a5:t> ..</a5:/t> tags will be evaluated. In addition, any text enclosed in { } brackets will be evaluated as an Xbasic expression.

 

Mobile Theme - Slate - A updated version of the new Slate stylesheet is ready for testing. 

To download the style click here. Unzip the file into the CSS folder where you have Alpha Anywhere installed. This will create a new folder called Slate in the CSS folder. To use the style, edit a UX component, and then change the style name for the component to 'Slate'.

NOTE: See Release Notes for more information on the Slate stylesheet.

 

 

Grid Component - Query By Example Searches - The search performed by the QBE search feature is now case-insensitive on databases that are normally case sensitive.

You can disable this feature by setting this property in the Grid's Advanced Properties section:

tmpl.qbeSearchIsCaseInsensitive = .f.

 

Grid Component - Alphabet Button Search - Case-insensitive Searches - The search performed by the Alphabet Button search feature is now case-insensitive on databases that are normally case sensitive. To see this change you must make the Grid dirty and then resave it.

UX and Layout Table Report - AbsoluteLayout Editor - The AbsoluteLayout editor is now based on an embedded version of the Chrome Browser. Previous versions were based on the Internet Explorer ActiveX control. However, as a result of some very unfortunate changes that Microsoft apparently made to IE11 (which comes standard on Windows 8.1), the AbsoluteLayout editor did not work correctly on machines where IE11 was installed. Now that the AbsoluteLayout Editor is based on an embedded version of Chrome, there is no dependency on Internet Explorer and no risk that a future update to IE will break some aspect of the AbsoluteLayout editor.

Tips

Grid - Search Part - Setting Initial Value of a Checkbox Control - Multiple Values - The Search Part allows you to define the initial value of each control in the Search Part. However, in the case of a multi-valued controls, such as a Checkbox control, you might want to set the initial value of the control to two or more checked values. You can do this by specifying some Javascript in the client-side onSearchRender event. Use the .setValue() method and pass in an array of the initial selections. For example:

{grid.object}.setValue('S','COLOR',['Red','Green']);

 

 

 

Build 1770-4221  6 Nov 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Bugs

UX Component - Signature Capture Control - Show in Window -  If the Signature Capture control was placed in a Window Container, when the window was opened, the signature capture control was shown but you could not draw on it.

List Control - Microsoft Access - Paginated Lists - There is a bug in Microsoft Access where if you specify a SQL Select statement with a limit clause and an Order By clause, the limit is interpreted as a percentage. For example

SELECT TOP 5 CustomerID, CompanyName, City FROM Customers ORDER BY City

 

In the above query, Access returns the top 5% of records in the query, not the top 5 records. This bug causes the wrong number of records to be shown in the List when the pagination option is set to .t.

A work around for the above Access bug has been added so that the List now correctly shows the correct number of records.

 

UX and Grid Controls - Submitting Data with Leading Quote Sign - If you submitted a field value that had a leading quote, the quotes were stripped. For example, if you tried to save this data into a field:

"alpha"

the value that was actually saved was:

alpha

 

Grid Component - Postgres - UUID Fields - Fixed an error when entering a new record with a primary key that was set to a UUID.

Features

Grid Component - Search Part - Case-insensitive Search Options - The Search Part of the Grid allows you to specify a search option for each search field. These options are:

 

The above search-options perform a case-insensitive search on databases that are not case-sensitive, and perform a case-sensitive search on databases that are case-sensitive. Oracle and Postgres are examples of databases that are typically configured to perform case-sensitive searches, while MySQL and SQLServer typically perform case-insensitive searches.

Now, new search options are available to force a search to be case-insensitive, regardless of how the database is configured. These options use the portable SQL lower() function to force a case-insensitive search. For example:

lower(name) LIKE lower(:what_name)

 

 The new options are:

 

AlphaDAO - Postgres - SSL - Support for SSL is now available for PostgreSQL ODBC extension driver variants – these include PostgreSQL, PostgresPlus and FoundationDB (under development):

email_smtp_send() Function - Character Set - You can now specify the character set when using the email_smtp_send() function.

 

DIM ps as P
DIM pm as P
pm.from = "aaron@alphasoftware.com"
pm.from_alias = "Aaron Brown"
pm.to = "ed@alphasoftware.com"
pm.subject = "This is a test"
' Text that contains non ascii characters - encoded as UTF8
pm.message = convert_acp_to_utf8("même manière")
' Indicate that we want to send the text with 'utf8' encoding
pm.charset = "utf8"
IF email_smtp_open(ps, "mail.alphasoftware.com")
email_smtp_send(pm, ps)
END IF
Email_smtp_close(ps)

 

Mobile Theme - Slate - A updated version of the new Slate stylesheet is ready for testing. 

To download the style click here. Unzip the file into the CSS folder where you have Alpha Anywhere installed. This will create a new folder called Slate in the CSS folder. To use the style, edit a UX component, and then change the style name for the component to 'Slate'.

NOTE: See Release Notes for more information on the Slate stylesheet.

 

Reports - Free-form Reports - Maximum Report Height - The maximum height of a report section was previously limited to 22 inches. This limit has now been substantially expanded. The maximum height of a report section is now approximately 300 inches.

 

 

Tips

UX Component - Watermarks - High Order Characters (e.g. Hebrew)  - Specifying watermark text for a textbox or textarea control using high order characters (for example, Hebrew characters) is possible, but requires the text for the Watermark to be entered as a unicode encoded string, with the {unicode} prefix.

For example, to set the watermark to the characters shown in the screenshot below, enter:

 

{unicode}05D0{unicode}05D1{unicode}05D2

 

In the screenshot shown below, the watermark is in Hebrew and it is on the right side of the control.

 

To get the text flow direction to 'right-to-left' (so that the watermark is on the right side of the control), the following Javascript was added to the client-side onRenderComplete event:

document.body.style.direction = 'rtl';

 

 

Display List of all Session Variables and their Values - The following .A5W page shows how you can list all of the session variables in the user's session and also display the value of each session variable.

 

<%a5
'test variables - you can delete these if you want
session.var1 = "alpha"
session.var2 = "beta"
 

'get a list of all of the session variables

'!f flag indicates that no functions should be returned
dim vars as c
vars = properties_enum(session.variables,"!f")

dim html as c
html = ""

'loop over each session variable and get its value
for each vn in vars
    html = html+"session."+vn.value+"="+eval("session.variables."+vn.value)+"<br>"
next
'print out the contents of 'html'
?html
%>

 

Build 1759-4217  1 Nov 2013

IMPORTANT: If you currently have build 1620-4172 from 21 Aug 2013 or an earlier build installed, then this is a required update.

 

Bugs

Application Server - Activation - Fixes a bug in build 1755-4125 that prevented an Application Server that had not previously been activated from being activated.

List Control - Microsoft Access - Paginated Lists - There is a bug in Microsoft Access where if you specify a SQL Select statement with a limit clause and an Order By clause, the limit is interpreted as a percentage. For example

SELECT TOP 5 CustomerID, CompanyName, City FROM Customers ORDER BY City

 

In the above query, Access returns the top 5% of records in the query, not the top 5 records. This bug causes the wrong number of records to be shown in the List when the pagination option is set to .t.

A work around for the above Access bug has been added so that the List now correctly shows the correct number of records.

 

UX and Grid Controls - Submitting Data with Leading Quote Sign - If you submitted a field value that had a leading quote, the quotes were stripped. For example, if you tried to save this data into a field:

"alpha"

the value that was actually saved was:

alpha

Features

Mobile Theme - Slate - A updated version of the new Slate stylesheet is ready for testing. 

To download the style click here. Unzip the file into the CSS folder where you have Alpha Anywhere installed. This will create a new folder called Slate in the CSS folder. To use the style, edit a UX component, and then change the style name for the component to 'Slate'.

NOTE: See Release Notes for more information on the Slate stylesheet.

 

Reports - Free-form Reports - Maximum Report Height - The maximum height of a report section was previously limited to 22 inches. This limit has now been substantially expanded. The maximum height of a report section is now approximately 300 inches.

 

Tips

UX Component - Watermarks - High Order Characters (e.g. Hebrew)  - Specifying watermark text for a textbox or textarea control using high order characters (for example, Hebrew characters) is possible, but requires the text for the Watermark to be entered as a unicode encoded string, with the {unicode} prefix.

For example, to set the watermark to the characters shown in the screenshot below, enter:

 

{unicode}05D0{unicode}05D1{unicode}05D2

 

In the screenshot shown below, the watermark is in Hebrew and it is on the right side of the control.

 

To get the text flow direction to 'right-to-left' (so that the watermark is on the right side of the control), the following Javascript was added to the client-side onRenderComplete event:

document.body.style.direction = 'rtl';

 

Build 1755-4215  29 Oct 2013

IMPORTANT NOTICE

This update is a required update. It must be installed before November 1.

Breaking Changes

UX Component - Client-side Readonly Expression - If your UX component has a client-side readonly expression you must recalculate the control and then resave the UX component. To recalculate the control, select the control that has the client side readonly expression and then make a change to any property of the control.

Videos

 

UX Component Image and File Upload - In Depth Look at What Happens Behind the Scenes When a File is Uploaded When you upload a file or image in the UX component, the binary data that is uploaded is stored in temporary session storage until the user commits the record they are editing. This video discusses what happens when a file is uploaded and what happens when the record you are editing is committed.

The video also shows how you can write Xbasic to modify the filename that is stored on disk when the Camera is used to capture an image on a mobile device.

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

Download Component
Reports Printing Data that Contains HTML Markup In some cases the data in a report you are printing might contain HTML markup. You might want to print the HTML markup in its rendered form, rather than its raw form. In this video we show how you can configure the report editor to print HTML markup as rendered HTML.

Watch Video
UX and Grid Component Understanding Component Aliases and the Use of Placeholders in Javascript Code When you write your own Javascript code in a Grid or UX component, you often use 'placeholders' (such as {Dialog.object} ) in your code. In this video we explain in depth how these placeholders work and we discuss the concepts of a component 'alias'.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Watch Video - Part 4
Watch Video - Part 5
UX Component Consolidate Multiple Ajax Callbacks into a Single Callback This video is aimed at advanced developers. It shows how the a5_ux_action() utility function can be used to optimize certain types of UX and List control actions into a single Ajax callback.

Watch Video - Part 1
Watch Video - Part 2

Download Component
Xbasic Working with XML Documents Xbasic has always had a powerful XML parser, but the new *property_from_xml() function and the new XML document viewer make it ever easier to work with XML documents.

Watch Video
Grid and UX Component Image Upload to a Character Field When you upload images in either the Grid or UX component, the target field can either be a binary field or a character field. In the case of a character field, the filename of the image is stored in the field and the image file itself is stored in a file in the specified 'upload folder'.

The filename of the image that is stored in the target character field can be a fully qualified filename, or more likely, you will store the 'shortfilename' (i.e. a relative filename).

If you choose to store the 'shortfilename', then you must configure an image path property so that the image filename can be resolved.

This video discusses this issue.

Watch video
UX Component Responsive Layout - Modifying the Design of a Component Automatically Based on the Device and Screen Orientation 'Responsive' is the term used to refer to a design that automatically changes its layout based on the device on which it is running, the device orientation and the window size (for desktop browsers). The UX component has very powerful tools for implementing responsive layouts.

In this video we show how the Responsive Layout Genie can be used to build highly responsive UX component designs.

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

Advanced settings
Watch Video


Download Components
UX Component List Controls/Data Series - Using an IN Clause with Array Arguments in a SQL Statement List controls, Charts and Data Series in a UX can all be based on a SQL query. In some cases you might want to use an IN clause in the SQL query and reference an argument value to get the values for the IN clause.

This video shows how you can use arrays in a SQL::argument object and then reference the argument in a SQL IN clause.

Watch Video
Download Component
UX Component - List Control Using the Server-side AfterQuery Event - Computing a Column Total For List controls that are based on a SQL query, the server-side AftterQuery event fires after the query to get the List data has been executed. This event is typically used to compute some Javascript code to return to the browser.

In this video we show how the event can be used to return the total for a column in the List. Since the List is paginated, all of the data in the List query is not currently shown in the List and therefore the calculation of the total must be done on the server.

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

Download Components
UX Component Computing a List Column Total using Client-side Calculations In cases where the List data is not paginated (and therefore the List contains all of the data in the List query), column totals can be computed client-side.

In this video we show how the data in a column in the List is computed using Javascript.

Watch Video
Download Components
UX Component - List Control Adding Dynamic Bubble Help (tooltips) to a Field in a List In this video we show how you can add dynamic bubble help to a field in a List control using some Javascript in the onItemDraw event.

Watch Video
Download Component
UX Component Embedded UX Components - Understanding the onPanelActivateEvent A common practice when designing mobile applications is to break a large application into multiple smaller UX components and then embed components in Panel Cards in the 'master' UX component. When you do this, it is useful to be able to execute code whenever a child UX component gets focus.

In this video we show how the onPanelActive client-side event in a child UX will fire whenever the Panel Card in which it is embedded gets focus.

Watch Video
Download Components
UX Component Annotating an Image using the Signature Capture Control The signature capture control can be used for more than capturing images. In this video we show how a medical application can use the signature capture control to annotate an image of the body to indicate affected areas.


Watch Video
Download Component
UX Component - List Control Server-side Summary Values For List controls that are based on SQL data, you can specify that summary data (e.g. total, avg, count, min and max) should be computed for certain columns in the List control. The summary computations are based on the List query (not on the rows actually visible in the List). In the case of a paginated List, there may be more rows in the query than are visible in the List. For example, the query might have 1,000,000 rows, but the list might show 20 rows at a time.

This video shows how a List control is configured to compute summary values, and then how the afterServerSideSummaryCompute event in the List is used to update a label on the UX component showing the summary values.

Watch Video
Grid Component Locking the Screen while a Long Running Ajax Callback is Executing If a Grid or UX component makes an Ajax callback that takes a long time to complete, you might want to display a message to the user telling them to wait and also you might want to 'lock' the screen to prevent them from firing other callbacks until the current callback has completed.

In this video we show how this is easily done using a custom modal window.

Watch Video
Grid Component Storing State Information Both the Grid and the UX allow you to store 'state' variables that are available on both the client and server-side.

The UX has always allowed you to set state variables on the server side (in any server-side event or an Ajax callback) by setting variables in the 'e._state' object. Previously, to set state variables on the server side in the Grid you had to generate Javascript code. Now, you can also set variables in the e._state object on Grid server side events.

This video shows how this is done.

Watch Video - Part 1
Watch Video - Part 2
UX and Grid Component Overview of How to Localize a UX or Grid Component In this video we give a brief overview on how a Grid or UX component can be localized so that the same component can be used for different languages. The technique involves using either Language tags (<a5:r>) or Text Dictionary tag (<a5:t>) around text strings that need to be localized.

Watch Video - Part 1
Watch Video - Part 2

For certain languages, the text flow direction is 'right to left' (e.g. Hebrew, Arabic). In this video we show how you can execute Javascript to change the text flow direction for the whole page. The Javascript is added to the component's render complete event. It sets the text direction using this code: document.body.style.direction= 'rtl'

Watch Video - Part 3
UX Component Show/Hide Buttons in Panel Header/Footer Without Messing Up Button Alignment A common pattern in mobile applications is to have buttons in a Panel header or footer and to space the buttons so that some are left justified, some centered and some right justified. Then you might show/hide one or more of the buttons, but you don't want the spacing on the buttons to be affected.

This video shows how this can be done.

Watch Video
UX Component Building a Menuing System in a UX Component Using Docked  Panels in a Panel Layout In mobile applications is it common to build menus that slide in from the right or left of the screen. In this video we contrast how this is accomplished in jQuery mobile and Alpha Anywhere. The approach we have taken in this video for Alpha Anywhere shows how the menus can be placed in Panel Cards that are docked inside a Panel Navigator.

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

Download Components
UX Component How to Dynamically Change the Code on a Button (Advanced Javascript Developers) This video shows how you can dynamically change the code associated with a button on a UX component by 'unbinding' the existing code and then 'binding' new code.

Watch Video
UX Component - List Control Edit the Current Row in a List Control in another UX Component The Grid component has an option in Action Javascript to edit the current row in a Grid using a UX component (that is data bound to the same table that the Grid is based on). This option also allows you to add a new record to the Grid using a UX component. The action for the Grid is called:

"Open a UX component to Edit Current Record in Grid, or add a new Record"

Now an analogous action is available in Action Javascript to edit the current row in a List control (for Lists that are based on SQL or DBF data sources) using another UX component that is data bound to the same table that the List is based on. The action for the UX is called:

"Open a UX component to Edit Current Record in List Control in a UX, or add a new Record to a List Control in a UX"

Watch Video
UX Component - Mobile Panel Layout - Understanding the Different Ways in Which a Docked Panel Can Be Shown - 'Over', 'Slide' and 'Push' Using Panel Layouts that contain multiple child Panels is common when building mobile applications. One or more of the child Panels that are shown in a Panel Layout can be 'docked' (i.e. hidden). Panels can either be explicitly docked, or conditionally docked (for example, on an orientation change).

Panels that have been docked can be shown (typically by clicking on a 'controller' button in a Panel Header). When a docked Panel is shown, you can specify the method use to show the Panel. This method discusses the various methods - Over, Slide and Push

Watch Video
UX Component - Mobile Overview of Different Methods for Specifying the Size of a Panel in a Panel Layout When using a Panel Layout you can optionally specify the size of each Panel that is displayed within the Panel Layout. When you specify the size of a Panel, you can use either an absolute, percentage or relative size. This video discusses the various options.

Watch Video
UX Component Embedding Reports into a UX Component and Dynamically Filtering the Report Reports can be 'embedded' into the UX component and then dynamically filtered based on values that the user enters into controls on the UX. This allows for powerful interactive dashboard type applications where users can interact with reports. This video shows how this can be done.

Watch Video
UX Component Custom Styling for RadioButton and CheckBox Controls The standard way in which browsers render checkbox and radiobutton controls is pretty drab. In this video we show how the UX component allows you to apply a rich set of styling options to radiobutton and checkbox controls.

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

Download Component
UX Component Positioning Controls at Absolute Locations on the Screen using the WYSYWIG Builder -  Understanding the AbsoluteLayout Container By default, the UX component lays out the controls that have been placed on the component automatically, 'flowing' the controls from left to right, top to bottom. All controls are perfectly aligned. However, there are times when you want more precise control over the placement of controls. This is especially true when you want to use an image (for example, an image  of a PDF form you might have) as the backdrop to a form and then place your UX component controls at precise locations exactly over the 'fields' in the image.

This video shows how you can place controls in an an AbsoluteLayout container and the set the absolute position and size of each control.

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
UX Component Understanding the 'NoFloat' Container Type By default, all controls in a UX component are wrapped in a DIV with a class name of A5CWLayout. This class adds a CSS float and padding so that the controls 'flow' automatically, left to right, top to bottom across the page. If a control has a 'break' after it, a new 'line' is started. This automatic lay out of the controls on a UX makes it very easy to design attractive, perfectly aligned forms.

However, there are cases when the padding that is automatically added to all controls gets in the way of the effect that you are trying to achieve and in these cases you can wrap controls in a special 'NoFloat' container.

This video explains how the 'NoFloat' container works.

Watch Video
UX Component Adding a 'Flow Collapse' Button to Panels in a Panel Layout to Hide/Show Panels Panels in a PanelLayout can be hidden or shown by adding a 'flow collapse' button to a Panel. A common reason for doing this is to create a 'full screen' view for the 'primary' Panel in a PanelLayout. This video shows how this is done.

Watch Video
Download Component
UX and Grid Component - 'NotInList' Event for Auto-Suggest and Edit-Combo Controls The 'NotInList' event fires when the user enters a value into an Auto-suggest or Edit-combo control and the value entered is not is the list of available choices for the control.

Watch Video
Reports Printing QR Codes Printing QR Codes on Layout Table Reports is now a built-in feature.

Watch Video
UX Component Displaying QR Codes on a UX Component A common requirement, especially in mobile applications, is to display data encoded as a QR code. The UX component has a built-in QR Code control that makes it very easy to display any data in the form of a QR Code. This control uses Javascript to generate the QR Code. Because it is a pure Javascript control, no Ajax callback is required and therefore it is very fast. However, you can also generate QR codes on the server.

This video shows how QR codes can be shown on a UX component using both client-side and server-side techniques.

Watch Video - Part 1
Watch Video - Part 2
Download Component
Reports Absolute Positioning of Objects in a Layout Table Report - Using a Form Image as Report Background In a previous video we have shown how the UX component supports absolute positioning of controls over a bitmap image of a form (typically a PDF form).

Layout Table reports also offer the ability to also use an image of a form as the report background and to then position the report fields directly over the 'fields' on the background image.

This video shows how this is done.

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

Tips

Reports - Printing Reports that Contain HTML Markup in the Data - In some cases the data in a report you are printing might contain HTML markup. You might want to print the HTML markup in its rendered form, rather than its raw form. In this video we show how you can configure the report editor to print HTML markup as rendered HTML.

Watch Video

 

UX Component - Buttons - How to Programmatically Enable and Disable Buttons - In V12 all buttons on the UX component are 'Adanced Buttons'. (In V11 buttons could either be 'standard' or 'advanced'). Advanced buttons are implemented as Javascript objects and so in order to enable or disable them programmatically, you need to get a pointer to the object and then call the object's .setDisabled() method.

 

NOTE: All Javascript controls, not just buttons, in the UX (List, ButtonList, SpinList, Tree, etc.) support the .setDisabled() method.

 

For example:

var bObj = {dialog.object}.getControl('BUTTON_1');

//set the button disabled

bObj.setDisabled(true);

//now enable the button

bObj.setDiabled(false);

 

 

If the button is in a Repeating Section, and you want to call the .setDisabled() method for a specific button instance (say the button in row 3), then you can pass in an optional parameter to the .setDisabled() method. For example:

//get a pointer the button element in row 3

var eles = $('{dialog.componentname}.V.R1.BUTTON_2_A5INSTANCE3');

//pass in eles as an optional argument to the .setDisabled() method
{dialog.object}.getControl('BUTTON_2').setDisabled(true,eles);

 

NOTE: In the above example, if you did not pass in the optional second argument to the .setDisabled() method, the button in every row of the Repeating Section would have been disabled.

 

Bugs

UX Component - Lists and Embedded Components - Delay Render Until Visible - Panel Layouts - Panels and Embedded Objects that were set to delay render until visible were not rendered if they were in a Panel Card inside a Panel Layout if the initial state of the Panel Card was 'docked'.

Forms - Super Controls - Google Maps Supercontrol - Windows 7/8 - If you used the Google Maps Superconrol in a Form on a machine where IE10 was installed, you would get a Javascript error. This error is apparently a bug in IE10 because the same Form runs without error on XP (where IE8 is used). A work around for this IE bug has been found and now the Form will work on Windows 7/8 without error.

Reports - Layout Table Reports - Linked Reports - If a child report uses arguments, and the parent report also uses arguments, then in the dialog where the child report is linked, you can now specify argument bindings to bind a child report argument to a parent report argument. Previously you could only bind child report arguments to literal or field values.

Report - Layout Table Reports - Linked Reports - Arguments in the Report Filter - If a child report (that was based on a SQL query) defined a filter in the report definition that used arguments, when this report was linked by a parent report, the child report arguments were not seen. Child report arguments were only seen if they were part of the report Data Source.

UX Component - List Control - Scrolling - As a result of changes to the change event described in a previous pre-release build, scrolling in he List caused the List's onClick event to fire. This is now fixed. Here is how tapping, and scrolling and List events now work:

 

 

ReportMailer and Netmailer - The installers for both have been updated for V12. If you need to use either of these addins with V12, please download the installers from the location specified in your order confirmation email.

UX Component - Data Bound - Security - If a UX component had security on a control so that for certain roles a control was not present on the UX, when doing an insert into a SQL table, you would get an error.

UX Component - Action Javascript - Insert, Update or Delete on an Unbound UX - Fixed some issues with the action.

Grid Component - Detail View - Edit on Demand - Cancelling out of the New Record -  If a Grid with a Detail View was configured to only edit on demand when cancelling out of a new record, the Detail view did not return to the correct state (showing controls as labels, and not textboxes).

 

AlphaDAO - MySQL - Longbinary Fields - Fixes an issue with inserting null blobs inot longbinary fields.

Grid Component - File Export - In the case of an ascii export, was not honoring the extension if you supplied a custom client side filename.

 

Windows 8.1 - Working Preview - Windows 8.1 has made a change that is causing Working Preview in the Component Builders to fail. You will receive an error message from Javascript ("access denied"). This build has a work around so that Working Preview is now working in Windows 8.1.

Report Server - The 4 core Report Server is now automatically enabled without requiring a Feature Key to be added. Previously, the Report Server was only enabled if you had entered a Feature Key.

TIP: If you want to disable the Report Server, you can go to Project Properties and disable it from there. The setting will apply to the current project.

UX Component - Action Javascript - Map Actions - Add Marker to a Map - If you selected the action to add a marker to a map and you passed in a comma separated latitude/longitude value (e.g. 31.65583, -81.21025) the marker was not positioned correctly on the map. The problem did not occur if you passed in an address. The reason that the marker was not being positioned correctly was that the generated code passed the lat/lng value to the .addMarker() method as a string, when it should have been passed in as an array. To fix the problem you will need to edit and resave the action in your component.

 

UX Component - Cascading Dropdown Controls - Repeating Sections - If a UX component had Repeating Sections, and had cascading dropdownbox controls in both the top level section of the UX and in a Repeating Section, the cascading dropdown in the Repeating Section was not populated correctly when the UX was populated with an existing record.

UX Component - Opening Child UX Components in Dynamic Panels - Fixed a bug where the Image Upload action in a child UX component that was opened in a Dynamic Panel did not work.

TabbedUI Component - Grid Component - Multi-line Text Area - Under some circumstances when working with a Grid that has a multi-line text-area control in a Tabbed UI, pressing down or up arrow in the text-area would not move the insertion point.

 

Grid and UX Component - Edit Combo - Did not scroll the current selection into view.

Reports - HTML Reports - SQL Tables with Spaces in Field Names - Fixed a bug in HTML reports when there were spaces in field names.

 

Notice

.Net Framework 4.5 - Alpha Anywhere currently requires .Net 4.0. We will soon be switching to .Net 4.5. In anticipation of this change the Full and Patch installers will now install .Net 4.5 on your machine if it is not already installed.

Features

UX and Grid Component - Javascript Confirmation Windows - Title Direction - By default, all confirmation dialogs show the title on the left and the close icon on the right. For right to left languages, you might want to change this.

To do so, put the following Javascript in the Grid or UX onRenderComplete client-side event:

 

A5.msgBox.window = {
    title: {
    direction: 'rtl'
    }
}

 

Reports - Layout Table Reports - Absolute Layout - Layout Table Reports now support absolute positioning of fields. This feature is similar to the absolute positioning of controls in a UX component using an AbsoluteLayout container.

The primary motivation for adding this feature to reports is to allow you to use an image of a form (for example, an image of a IRS 1040 PDF form) as the background for a cell in a Layout Table report, and to then allow you to place the fields in the report at explicit locations so that they print 'on top of' the fields in the image background.

NOTE: This feature is only available for Layout Table reports that are being edited in the full report editor - not in the Quick Report genie.

To access the feature, double click on a cell in the Layout Table report. The 'Cell Contents' dialog opens up. Note a new choice in the dialog - 'Absolute HTML'.

 

 

If you select this option, then click the 'Edit...' button, the Absolute Layout editor for the cell opens up:

 

 

The editor shows the available fields, a 'canvas' where you can place the fields using drag and drop actions, and a property sheet showing properties of the selected field.

NOTE: Unlike the UX component, the size of the editing region (shown as 312 by 138 pt in the above image) cannot be changed in the editor. The size of the editing region is determined by the size of the cell in the Layout Report.

For each field that you place on the canvas, you can use the Style property in the Property Sheet to define properties (using HTML CSS syntax) to control the appearance of the field in the report.

For example, if you want a field in the absolute layout HTML to appear in red, with a blue border, you would define the following for its Style property:

color: red; border: solid 1px blue;

 

Placing 'Radio Buttons' and 'Checkbox' Controls

Assume that the background image for a cell uses the image shown below. Consider the 'Filing Status' area. It is likely that in your table, you have single field called 'filingStatus' that might have a value of 1, 2, 3, 4, or 5 stored in the field.

However, when you print a report, you want to print an 'X' above the appropriate box in the image.

To do this, you would need to define five calculated fields in your report. For example:

 

filingStatus_1 = if(filingStatus = 1, "X","")

filingStatus_2 = if(filingStatus = 2, "X","")

filingStatus_3 = if(filingStatus = 3, "X","")

filingStatus_4 = if(filingStatus = 4, "X","")

filingStatus_5 = if(filingStatus = 5, "X","")

 

Having done this, when you open the Absolute Layout editor, your field list will show the five calculated fields you have defined, and you can place each one of these fields over the appropriate radio button control on the image.

 

Defining the Background Image for the Cell

When you are in the Absolute Layout editor, you can define the background image for the cell. When you specify the image, you can specify how the image should be scaled to fit the cell. The options are:

 

UX Component - Mobile Applications - Location Information - Current location information can be used in several actions in Action Javascript. These actions include Ajax Callbacks, Centering a Map, Placing a Marker on a Map, Filtering a List for Records within the Vicinity of the Current Location.

Now, the Action Javascript builders expose three properties which previously were hard coded to default values. These properties are:

 

High accuracy - If true, the device will use its most accurate method to get location information. If false, the device will use its fastest or lower power consumption method depending on the device. (Default true)

Timeout - The amount of time in milliseconds to wait on the device to acquire location information excluding the amount of time it takes the user to grant the web page access to geolocation data. (Default 15000)

Max age - The amount of time in milliseconds to accept a previously acquired location. 0 means that a new location must be acquired from the device. (Default 30000).

You can also change the default settings for these properties, by adding Javascript like this (using appropriate values for each of the properties) to the onRenderComplete client-side event:

 

{dialog.object}.locationMaximumAge = 30000;
{dialog.object}.locationTimeout = 15000;
{dialog.object}.locationHighAccuracy = true;

 

 

UX Component - ListControl - onBeforeSelect event - The onBeforeSelect event fires before the Select event. If the event returns false, then the user is prevented from moving off the currently selected row in the List.

Grid and UX Component - Windows, Auto-suggest and Edit-combo - Specifying a Maximum Window Height - When you define the window height for a pop-up window, an auto-suggest control or an edit-combo control, you can specify a window height.

If you leave the height property blank, the window will be sized to accommodate the entire height of the content (which will result in a window that is too high if there is a lot of content).

On the other hand, if you specify an explicit size, then you will end up with a window that looks too big if there is just a small amount of content in the window.

Now, when you specify the window height you can use the 'max' syntax to specify that the window should be automatically sized to fit its content, but should not grow bigger than the specified max size. For example, you can specify the height property as:

max: 300px

 

 

UX and Grid Component - Auto-suggest and Edit-combo Controls - 'NotInList' Rule - The 'NotInList' event fires when the user enters a value into an Auto-suggest or Edit-combo control and the value entered is not is the list of available choices for the control.

Watch Video

The primary use case for this event is to allow the developer to add code to the component to add the value that was entered into the control into the table on which the control choices are based so that the next time the user visits the control the value entered will be in the pick list for that control.

 

UX Component - QRCode Control Type - A new control type has been added to the UX component. The QRCode control displays its value as a QR Code.

The image shown below shows a UX with a QRCode controls.

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

 

NOTE: The QRCode control is a client-side control. That means that Javascript is used to generate the QR code. You can also use Xbasic methods to generate servers-side QR codes (as bitmaps or SVG). See ::Qrcode::Creator:: below for more details.

To place a QRCode control on a UX, select the control type from the toolbox.

 

 

The QRCode control is just like other data bound controls in that it has a .getValue() and .setValue() method.

To display a QR code, you simply call the .setValue() method of the control. For example:

{dialog.object}.setValue('MYQRCONTROL_1','value to encode');

 

QRCodes - Xbasic - New methods have been added to Xbasic to generate QRCodes. The methods are:

 

::Qrcode::Creator::GenerateBmp(c text, c flags)

::Qrcode::Creator::GenerateBmpFile(c text, c filename, c flags)

::Qrcode::Creator::GenerateJpeg(c text, c flags)

::Qrcode::Creator::GenerateJpegFile(c text, c filename, c flags)

::Qrcode::Creator::GeneratePng(c text, c flags)

::Qrcode::Creator::GeneratePngFile(c text, c filename, c flags)

::Qrcode::Creator::GenerateRTF(c text, c flags, n width, n height)

::Qrcode::Creator::GenerateSVG(c text, c flags)

 

The flags parameter can be set to 'L' (low), 'M' (medium) or 'H' (hight) to indicate the level of error correction in the generated QR Code.

 

For example, from the Interactive window:

 

dim svg as c

svg = ::QRCode::Creator::GenerateSVG("http://www.alphasoftware.com","L")
a5_show_html(svg)

 

To display a QR code in an Xdialog:

 

svg = ::QRCode::Creator::GeneratePngFile("http://www.alphasoftware.com","c:\myfiles\qr1.png","L")
ui_dlg_box("QRCODE","{image=c:\myfiles\qr1.png}")

 

 

 

Qrcode_bitmap() Function - Generates a bitmap of a QR Code - This function is a wrapper for the ::QRCode::Creator::GeneratePng() function. However, it is able to scale the bitmap to an explicit size.
 

Returns either binary PNG data or base64 encoded string with 'data:image/png;base64,' prefix

 

Syntax

A blobOrString = qrcode_bitmap(c text, c flag [,N width , [N height [, L  flagBase64encodedWithPrefix]]])

 

QRCodes - Layout Table Reports - Layout Table Reports now support printing any cell in the Layout Table that contains a text value as a QR code.

To print the contents of a cell as q QR code, simply check the 'Display QRCode for text in cell' property at the bottom of the 'Cell Contents' dialog box.

 

 

 

For example, here is a report showing customers in the sample Northwind database:

 

 

 

 

Watch Video

 

UX Component - PanelLayout Containers - Flow Collapse Buttons - Allows you to put a button in a Panel (only applies if the Panel is contained within a PanelLayout) to 'collapse the flow' of Panels that come 'before' the current Panel. By 'collapsing the flow' of a Panel, you make the Panel invisible.

 

Watch Video

 

The following set of images help to explain the concept:

 

The image below shows a Panel Layout with 3 child Panel (the child Panels can be PanelCards, PanelNavigators or PanelLayouts). The PanelLayout flow is set to LTR so that the Panels 'flow' from left to right. All of the Panels in the PanelLayout are currently visible. PanelCard1 and PanelCard2 both have an explicit size (say 100px) and PanelCard3 takes up the remaining available space.

 

Now, let's assume that PanelCard3 has a button (either in the Panel body itself, but more likely in its header or footer) to 'collapse the flow' (of the Panels that come before it).

If this button was pressed, then the Panels that come before it (PanelCard1 and PanelCard2 - because the flow direction is LTR) will get 'collapsed'. Their widths will get set to zero using an animation.

 

 

When the animation has completed, Panel Card3 will consume all of the available space in its parent PanelLayout.

 

The 'Flow collapse' button acts as a toggle. So, if the button were pressed a second time (while PanelCard1 and PanelCard2 are collapsed), then PanelCard1 and PanelCard2 will be re-shown, again, using an animation.

 

 

When would you use a 'Flow collapse button'? Assume that in the above example, PanelCard1 and PanelCard2 contain navigation or menu controls and that PanelCard3 is the main 'work' area of your application. By have a 'flow collapse' button in PanelCard3, you can allows you users to toggle 'full screen' mode on and off.

 

The primary use case for this pattern is when PanelCard1 and PanelCard2 contain 'navigation' or 'menu' controls and

 

Defining a 'Flow Collapse' Button

To define a 'Flow Collapse' button for any Panel (PanelCard, PanelNavigator or PanelLayout), set the 'Has a 'flow collapse' button' property in the Panel's Property Sheet.

Once you click this property, you can specify the ID of the button that will act as a 'flow collapse' button.

NOTE: If you have defined an onClick event for the flow collapse button, the event will be ignored since the button is being 'hijacked' to perform the 'flow collapse' action.

The builder allows you to define separate icons to use for when the Panels are in the collapsed state and when they are in the expanded state.

IMPORTANT: If you want to display icons on the flow collapse button you must set the button type to the appropriate option in the properties for the button you specify as the 'flow collapse' button.

 

 

 

 

UX Component - NoFloat Container Type - By default, all controls in a UX component are wrapped in a DIV with a class name of A5CWLayout. This class adds a CSS float and padding so that the controls 'flow' automatically, left to right, top to bottom across the page. If a control has a 'break' after it, a new 'line' is started. This automatic lay out of the controls on a UX make it very easy to design attractive, perfectly aligned forms.

However, there are cases when the padding that is automatically added to all controls gets in the way of the effect that you are trying to achieve and in these cases you can wrap controls in a special 'NoFloat' container.

Watch Video

In the image below, the first container (red) is a standard container. 'Firstname' and 'Lastname' are on the same line (because the break after 'Firstname' was turned off) as are 'City' and 'State'. Also, each control has padding around it.

The second container (blue) has been set to a 'NoFloat' container. Notice that all controls now are on their own line (even though there is no break after 'Firstname' and 'City' and all padding between controls has been removed.

 




 

 

Xdialog - List Control - W=milliseconds Directive to Delay Firing Selected Event - A new directive can be added to a List control to delay firing the selected event for a specified number of milliseconds.

The directive:

W=milliseconds

 

is inserted in the Listbox commands (between the % symbols).

To test the effect of this directive, create a new Xbasic script and paste this code in. Then click on a row - a message box will show the selected value. Then hold the down arrow down and the selection will move quickly down the list, but the event which shows the current selection will not fire until you have stopped holding down the down key.

Then, repeat the exercise with te W=2000 directive removed. You will see that the message box is shown for every row.

 

 

dim colors as c
colors = a5.Color_Enum()
dim selected as c
dim dlg_title as c
dim dlg_body as c
dim dlg_event as c
dlg_title = "Title"
dlg_body = <<%dlg%
{removecomments}
{removeleadingspaces}
[%W=2000%.100,30selected^#colors!selected_changed];
%dlg%
dlg_event = <<%code%
if a_dlg_button = "selected_changed" then
a_dlg_button = ""
ui_msg_box("",selected)
end if
%code%
dim flagOK as l = .f.
ui_dlg_box(dlg_title,dlg_body,dlg_event)

 

 

UX Component - Radiobutton and Checkbox Controls - Custom Styling - The standard way in which browsers render checkbox and radiobutton controls is pretty drab. The UX component allows you to apply a rich set of styling options to radiobutton and checkbox controls.

For example, here is an example of how these controls can be styled:



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

Download Component

 

To style a Radiobutton or Checkbox, check the 'Has custom design' property.

 

Then click the smart field for the 'Custom appearance designer' to open the builder. The builder gives you control over a large number of appearance properties and also shows a real-time preview of the control's appearance.

 

 

 

UX Component - Embedded Obects - Reports - HTML Reports - When you embed a report into a UX component, you now have the option to specify that the report should be rendered as HTML.

Watch Video

 

 

Panel Layout - Display Method - 'Push' Option - A new option for the 'Docked Panel display method' property has been added. The option is 'push'. The 'push' method pushes the Panel that are to the left (or right, above or below - depending on the Flow direction)

 

Watch Video

 

Panel Layout - Dock Options - Several new options have been added to specify when a Panel that is contained in a Panel Layout should be docked (i.e. hidden). The complete list of options is shown below:

 

The options prefixed with 'landscape', 'portrait', and 'self' are new.

If a Panel's dock option is set to 'portrait-collapse-before' then the Panel will be docked (i.e. hidden) when the device is in portrait mode, but not when in landscape mode.

If a Panel's dock option is set to 'self-portrait-collapse-before' then the Panel will be docked when the Panel Layout in which it is contained is in 'portrait' mode (i.e. it has a width that is less than its height), regardless of the orientation of the device itself.

 

 

Panel Layout - Size Options - New options have been added for specifying the size of a Panel in a Panel Layout. You can now use percentages and negative sizes.

If you specify a percentage size, the percentage represents the percentage of the available space in the Panel Layout.

If you specify a negative size (e.g. -100px), then the Panel Layout will have a size equal to the size of the Panel Layout (in the flow direction), minus 100px.


Watch Video

 

 

Grid Component - Alphabet Button Search - Custom Buttons - The Alphabet Button search feature in the Grid has always allowed custom button definition. For example:

A..C = left({searchfield},1) >= 'A' and left({searchfield},2) <= 'C'

 

In the above example, a button with a label of 'A..C' is defined with a corresponding filter of:

left({searchfield},1) >= 'A' and left({searchfield},2) <= 'C'

 

Now, you can specify that the filter expression uses arguments. For example the above custom button can now be defined as:

A..C = left({searchfield},1) >= :arg1 and left({searchfield},2) <= :arg1 && a|||c|arg1

 

The argument value is defined using the syntax:

argumentValue|||argumentType|argumentName

and is separated from the filter by:

&&

 

When specifying the argument value you can use an expression by prefixing the argument value with an = sign.

For example:

 

Today's Orders = orderDate = :d1 && =date()|||d|d1

 

If you want o use International characters in an argument value, then you must use an expression that uses the *html_to_text() function and an html encoded version of the argument value.

For example:

 

&;#1489; = left({searchfield},1) = :arg1 && =*html_to_text("&;#1489;")|||c|arg1
 

 

 

UX and Grid Component - CSS Editor - Remember Last Pane Used - The CSS editor now remembers the last pane you were on. If you switched to the Code pane, then closed the editor, the next time you open the editor you will be on the Code pane. Previously, the editor always opened on the Design pane.

UX Component - List Control - Action Javascript - Edit Current Row in List - A new action has been added to Action Javascript to allow you to edit the current row in a List control that is based on a SQL or DBF data source in another UX component.


Watch Video

 

The action is called:

 

Open a UX component to Edit Current Record in List Control in a UX, or add a new Record to a List Control in a UX

 

The UX component that is used to edit the List record must be data bound to the same table that the List is based on, and the AfterDialogValidate event in the UX used to edit the List row must have a server-side Action Script to save the record when the Submit button is pressed.
 

UX Component - Logical Checkbox - Prompt Text - You can now specify an optional label that appears to the right of the logical checkbox.

 

UX Component - Radiobutton, Checkbox and Logical Checkbox Controls - Now wrap the individual choices and their corresponding label in a <span> element. You can specify the class name for this <span> element. This allows for more styling options on these controls.

 

Web Projects Control Panel - Find File - A new option on the right click menu allows you to search for a particular file in all of the Web Projects in the current Workspace. This function is useful if you have many Web Projects in a particular Workspace and you are not sure in which Web Project a particular file is located.

 

 

UX Component - AbsoluteLayout (WYSIWYG) - You can now position controls in a UX component at absolute locations on the screen.

A common use case for absolutely positioning controls is so that you can display an image of a professionally designed form as a 'backdrop' to your UX and then precisely position your UX controls over the 'fields' in the form image.

By default, when you place controls on a UX component, the controls are positioned on the screen automatically by the UX component. The controls 'flow' from left to right, then top to bottom.

 

For example, say you have have a UX component that has these controls on it:

 

As the image shows, there is no break after the 'firstname' field, so 'firstname' and 'lastname' will be on the same 'line'.

'address' will be on its own 'line' because there is a break before and after it. Finally, 'city', 'state' and 'zip' will all be on the same 'line'.

Here is how this UX will render:

Because the UX was in charge of rendering, you can see that the baselines of all controls on the same 'line' are automatically aligned. And the left edges of controls at the start of each line are also automatically aligned. Furthermore, automatic spacing has been placed between the controls so that the form lays out nicely.

NOTE: The amount of spacing between controls is defined by setting the 'A5CWLayout Class Padding' property on the UX Properties Pane. By default this is set to 4px. You can set explicit values for top, right, bottom and left using the standard CSS convention: For example: 4px 4px 0px 0px.

An important (and extremely powerful) aspect of the way Alpha Anywhere lays out controls automatically is how the UX component will react when the window in which it is contained is resized. In the example show above, City, State and Zip are on the same line. However if the window is resized smaller and there is no longer space for all of the controls on the line, the Zip control will automatically 'wrap' to the next line. As the window is further resized smaller, eventually the State field will also automatically 'wrap' to the next line.

When you use Absolute Layout, you turn off the automatic layout of controls that the UX component does and instead you take on responsibility for positioning and sizing controls yourself.

For example, you might lay out the controls in the following (admittedly decidedly odd) fashion:

 

The way in which you indicate that you want to absolutely position controls in a UX is by wrapping the controls in an AbsoluteLayout container.

 

The AbsoluteLayout container has these properties:

 

 

Absolute positions for controls - The smart field for the 'Absolute positions for controls' property will open the builder where you can visually set the position and size of each control in the container.

Has background image - The 'Has background image' property indicates if the AbsoluteLayout container has a background image.

Control style overrides - The 'Control style overrides' property is a convenience feature. It allows you to automatically add some CSS to use for the in-line style of every control in the AbsoluteLayout container without having to go to individual controls in the AbsoluteLayout container and set the in-line style, control by control. For example, if you wanted every control in the AbsoluteLayout to have a red border, you could just set this property to:

border: solid 1px red;

 

 

The layout of controls in the screenshot shown earlier is represented in the AbsoluteLayout builder as follows:

 

 

 

 

NOTE: Data controls (such as textboxes, textareas, dropdown boxes, etc.) only show the control itself (and not the control Label - if the labels are turned on), when placed in an AbsoluteLayout container.

 

Working with the AbsoluteLayout Editor

The AbsoluteLayout editor allows you to position controls on a 'canvas'. You also define the size of the control on the canvas. The editor has many advanced features that make positioning and sizing controls precisely extremely quick and easy.

To place an object on the canvas, select the object in the field list on the left. The click on the canvas at the position you want to place the object, and while holding down the mouse button, draw a rectangle that represents the size of the object.

While you are drawing, the current size and position of the object are shown.

You can also edit the size and position of an object in the Property Sheet shown on the right.

To

 

Toggling the Background Image On/Off

If you have specified that your AbsoluteLayout container has an image background, then when you open the editor, the image background is shown. However, with the image shown, it can be hard to see all of your controls against the image background. You can therefore toggle the image on/off by clicking the 'Background Image' button on the toolbar:

 

 

Guidelines

Guidelines make it very easy to position controls relative to other controls. For example in the image shown below, the width of the bottom control is being adjusted and a vertical guide line has been drawn to show the the right edge of the control is aligned with the right edge of the control above it.

 

 

 

Adjusting Multiple Controls as Once

You can select multiple controls by shit-clicking on controls. Once you have more than one control selected, the Edit Selected button on the toolbar becomes enabled.

This button displays a menu that allows you to perform actions on multiple controls at once, such as aligning them, or sizing them.

A useful option is the ability to size multiple controls to a be the same size as a 'reference' control. The 'reference' control is the first control that was selected when you selected multiple controls.

 

 

 

Positioning Individual Radiobutton and Checkbox Controls

Normally when you position a Checkbox or Radiobutton control in an AbsoluteLayout container, you position the control as a single object and then Alpha Anywhere renders the individual radio button or checkbox controls for each choice (either horizontally, vertically, or in snaking columns). However, in certain use cases (typically when using an image as a background), it is necessary to precisely position the individual choice objects.

For example, consider the section of the IRS 1040 form shown below. The checkboxes show on the form (which are really radio buttons - since only a single box is meant to be checked) are laid out in a custom fashion.

When using this image as the background image for an AbsoluteLayout container you would clearly want to have a 'FilingStatus' Radiobutton control and then be able to position each choices over the checkbox shown in the image.

Furthermore, you would want to suppress the label associated with each Radiobutton choice because the image background explains what each option represents.

 

In order to turn on the ability to individually position choices in a Checkbox or Radiobutton control, you must turn on the Custom layout when in AbsoluteLayout container property for the Checkbox or Radiobutton control:

 

 

NOTE: The  Custom layout when in AbsoluteLayout container property is only shown if the Radiobutton or Checkbox control is based on a static list of choices.

 

Once you have checked the Custom layout when in AbsoluteLayout container property, when you open the AbsoluteLayout editor, the individual choices for the control will be available in the field list so that you can place them on the canvas. For example, in the image below the Radiobutton control has 3 choices, and so the AbsoluteLayout builder shows three objects which can be individually placed.

 

 

 

 

UX Component - {dialog.object}.setFocus() Method - Javascript Controls - Now works for Javascript controls (such as the List control). Previously this only worked for HTML controls (such as a checkbox, textbox, etc). The motivation for adding support for Javascript controls to the .setFocus() method was to enable the following use case:

Assume you have a UX component with a List control on one Panel and some other controls on another Panel. The second Panel has a button that returns focus to the first Panel. However, when focus returns to the first Panel, pressing up and down keys (when running on a desktop browser) did not navigate in the List (even though visually, the List appeared to have focus). By using the .setFocus() method in the event handler for the button that returns focus to the first Panel, you can solve this problem.

UX Component - List Control - Client-side Summary Values - You can specify that client-side summary values should be computed for any column in a list.

To turn on client-side summary values for a field in the List, check the property shown below in the List builder:

 

NOTE: For Lists based on SQL data, you can also specify server-side summary values. Server-side summary values are only different than client-side summary values if the List is paginated. Server-side summary values compute the summary based on the List query, whereas client-side summary values are based on the data that is currently loaded into the List. In the case of the paginated List, there can be many more records in the List query than are displayed in the List.

 

 

When you compute summary data for a List column, you will typically want to display the data on the UX component. The List's afterClientSideSummaryCompute event is useful for this. The afterClientSideSummaryCompute fires after the client-side summary values have been updated.

In this event handler you can reference the summary data that was computed. Here are some examples of how your Javascript code can reference summary values:

csSummary['QTY'].total

csSummary['PRICE'].avg

csSummary['PRICE'].max

 

The 'csSummary' object contains all of the summary data. The field name must be in uppercase and the summary type (total, avg, count, min, or max) must be in lower case.

 

You can also use a method of the UX object to read a List summary value using the following method:

 

{dialog.object}.getListClientSideSummaryValue(listName, fieldName, summaryType)

 

For example:

var tot = {dialog.object}.getListClientSideSummaryValue('list1','QTY','total');

 

 

 

UX Component - List Control - Static Data - Group Breaks - If your data is already in the the correct sorted order, you can instruct the List not to sort the data on the break field.

 

 

 

Reports - Layout Table Reports - Creating Custom Style Sheets - It is now much easier to create custom style sheets for Layout Table Reports.

 

In the Quick Report Genie, you can click the 'New Style Sheet...' hyperlink.

 

In the Layout Table Report editor when you select the 'Apply or Create Stylesheet..' menu, you can then click the 'New Style Sheet' button shown below.

 

 

 

When you select the New Style Sheet option, you get a dialog that allows you to define the color and other properties of the style.

 

 

ShowResultSet() Function - The showResultSetFunction() is a useful utility function to quickly show data in an AlphaDAO resultset. It is typically used in the Interactive window, or while debugging code.

Here is an example of an Interactive window session:

 

dim cn as sql::Connection
cn.open("::Name::sqlserver2012_northwind")
dim sql as c = "select * from customers where city = 'london'"
cn.PortableSQLEnabled = .t.
?cn.Execute(sql)
= .T.

dim rs as sql::ResultSet
rs = cn.ResultSet
showResultSet(rs)

 

 

Note:  After you have called the showResultSet() function once to show a resultset, you cannot call it a second time to show the same resultset without first executing the query again. That's because AlphaDAO resultsets are 'forward only'.

 

Grid Component - State Variables - Setting State Variables on the Server-Side Using the e._state Object - Both the Grid and the UX allow you to store 'state' variables that are available on both the client and server-side.

 

NOTE: State variables are variables whose value can be set or read on either the server-side (using Xbasic), or the client-side (using Javascript). Once a state variable has been set, its value is available on all subsequent Ajax callbacks.


The UX has always allowed you to set state variables on the server side (in any server-side event or an Ajax callback) by setting variables in the 'e._state' object. For example, in a server side event:

e._state.mystatevar1 = "alpha"

 

However, in the Grid, you could not use this syntax. Instead, you had to generate Javascript to set the state variable and then return that Javascript in the response from your server side event. For example:

 

{grid.object}.setStateInfo({mystatevar1: 'alpha'});

 

Now, you can also set variables in the e._state object on Grid server side events.

NOTE: Some Grid events do not take 'e' as the input parameter. These events take 'args' as one of their input parameters. In events that do not take 'e' as in input parameter, you can still set state variables on the server-side by setting

args.rtc._state.mystatevar1 = "alpha"

 

On a Grid, when a server side event is executing, state variables can be read from the e.__si2 object. (For the few server-side events that take 'args' you can read state variables in the args.rtc.__si2 object).


Watch Video - Part 1
Watch Video - Part 2

 

The section below summarizes how state variables are set and read on both the server-side and client-side in the Grid and UX:

 

UX

    Server-side (Xbasic)

        Set state variable - e._state.myvar1 = "alpha"

        Read state variable  - myvar = e._state.myvar1

    Client-side (Javascirpt)

        Set state variable - {dialog.object}.setStateInfo({myvar1: 'alpha'})

        Read state variable - var myvar = {dialog.object}.stateInfo['myvar1'];

   

UX

    Server-side (Xbasic)

        Set state variable - e._state.myvar1 = "alpha"

        Read state variable  - myvar = e.__si2.myvar1

    Client-side (Javascirpt)

        Set state variable - {grid.object}.setStateInfo({myvar1: 'alpha'})

        Read state variable - var myvar = {dialog.object}.stateInfo['myvar1'];

   

NOTE: The inconsistency between the Grid and the UX in the way state variables are read in server-side code is because of legacy code in the Grid that could not be changed without making a breaking change to Grids. Therefore when you read a state variable in a Grid you read from the e.__si2 object (and not the e._state object). Setting state variables, however, is done in the e._state object.

 

 

Mobile Theme - Slate - A updated version of the new Slate stylesheet is ready for testing. 

To download the style click here. Unzip the file into the CSS folder where you have Alpha Anywhere installed. This will create a new folder called Slate in the CSS folder. To use the style, edit a UX component, and then change the style name for the component to 'Slate'.

NOTE: See below for more info on the Slate stylesheet.

 

UX Component - List Control - Server-side Summary Values - For List controls that are based on SQL data, you can specify that summary data (e.g. total, avg, count, min and max - total and avg are only available for numeric fields) should be computed for certain columns in the List control.

NOTE: Client-side summary values can also be computed. Client-side summaries are not limited to SQL data sources.

The summary computations are based on the List query (not on the rows actually visible in the List). In the case of a paginated List, there may be more rows in the query than are visible in the List. For example, the query might have 1,000,000 rows, but the list might show 20 rows at a time. If the List is not paginated, then the number of rows in the List is the same as the number of rows in the List query.

Server-side summary values are automatically updated when the List data is refreshed. If your UX is data-bound and you have specified that the List should be updated when records are updated or saved, the server-side summaries will be updated when data in the List is edited.

 

Watch Video

 

To turn on summary calculations for a column in a List, check the 'Compute summary values' property. Once this property is checked, the 'Summary field formatting' property is shown where you can define display formats for the data. For example, to round the average to 2 decimal places, you would use:

round(<value>,2)

You can use any Xbasic function for format the data.

 

 

When you compute summary data for a List column, you will typically want to display the data on the UX component. The List's afterServerSideSummaryCompute event is useful for this. The afterServerSideSummaryCompute fires after the server-side summary values have been updated.

In this event handler you can reference the summary data that was computed. Here are some examples of how your Javascript code can reference summary values:

summary['QTY'].total

summary['PRICE'].avg

summary['PRICE'].max

 

The 'summary' object contains all of the summary data. The field name must be in uppercase and the summary type (total, avg, count, min, or max) must be in lower case.

 

You can also use a method of the UX object to read a List summary value using the following method:

 

{dialog.object}.getListServerSideSummaryValue(listName, fieldName, summaryType)

 

For example:

var tot = {dialog.object}.getListServerSideSummaryValue('list1','QTY','total');

 

 

 

UX Components - Abstract Tap and DoubleTap Events - Two new abstract events have been added to the UX component. These events have been added because the behavior of the click and dblClick events have been changed in an important, but subtle way. (See below for more details on the click and dblClick events.) The tab and dblTap events allow you to get the previous behavior of the click and dblClick events should your application require this behavior.

Assume you have a large button and you click on the button and then, before releasing, you move your finger or mouse by more than the threshold amount (used to be 5px, now upped to 10px). You then released, while still over the button.

Previously, the click event would not have fired. Now it will fire. The tap event, however, will not fire (because you moved by more than the threshold amount).

If you have moved off the button by the time you release, then neither the tap or click events will fire.

NOTE: The List control has also added onTap and onDblTap events. The behavior of the onClick and onDblClick events in the List has been changed.

 

UX Component - Click and DblClick Event - The behavior of the abstract click and abstract dblClick events have been changed slightly so as to make it consistent with the behavior of a these events on native devices.

Previously, if you clicked (or dblClicked) on a control and then, before releasing, moved your pointer by more than the threshold amount (was 5px, but has not been changed to 10px), then when you released (assuming you will still over the original element), the event did not fire. Now, the event will fire as long as you are still anywhere over the original element at the time you release.

NOTE: If your application need the original click event behavior, use the new tap event.

 

UX Component - Action Javascript - Delete Record Action -  Enhancements - The Delete Record action allows you to delete a record in a UX component that has been data bound.

Previously, this action required that the primary keys for the data bound table had been loaded (normally done in the onDialogInitialize event using the 'Load Primary Keys for Parent Table' server-side action, or by an Ajax callback).

It is no longer necessary for primary keys to have been loaded in order to use this action.

When you use this action now, the builder now gives you these options for specifying the primary key of the record to delete:

The dialog for this action is shown below.

 

 

UX Component - Signature Control - Client-side Enable Expression - Now honors the client-side enable expression. When the control is disabled, the buttons are disabled, not the canvas (where the user signs).

UX Component - Signature Control - Client-side Show/Hide Expression - Now honors the client-side show/hide expression.

UX Component - Client-Side Events - onPanelActivate - A common practice when designing mobile applications is to break a large application into multiple smaller UX components and then embed components in Panel Cards in the 'master' UX component. When you do this, it is useful to be able to execute code whenever a child UX component gets focus.

The UX component now has a new client-side event - onPanelActivate. This event fires when the UX gets focus (because the Panel Card in which it is embedded has gotten focus).

IMPORTANT: This event will only fire if you have assigned an explicit alias to the UX component when you embed it into its parent UX component.


Watch Video
Download Components

 

pdf_exportJPG() function - Converts a PDF file to a JPG image - A new function converts a PDF file into a JPG file. If the PDF file has multiple pages then one .jpg file is created for each page. The .jpg files are numbered sequentially.

Syntax:

L flag =  Pdf_exportJPG(c file, c result_file , c resolution)

 

resolution - 'default', 'low', 'medium', 'high'

result_file - name of the .jpg file to create.

 

 

UX Component - Session Timeout Warning - The UX component can now be configured to display a warning to the user that their session is about to expire.

 

 

To turn on session timeout warning, check the 'Display warning before session timeout' property on the Properties pane of the UX builder.

Once you turn this property on, there are a number of properties that allow you to customize the feature.

 

 

The onSessionTimeoutWarning client-side event will fire just before the warning dialog comes up telling the user that their session is about to expire.

 

 

UX Component - List Control - Server-side In-line and Conditional Style - Previously, if you defined a server-side in-line or conditional style for a field in a List control, a span was inserted into the data on the server to format the data. While this gave the required visual appearance, it meant that if you read the value from the control, the value that you read included the HTML markup.

This has now been changed. The server-side style is computed on the server and is now included in a separate (hidden) field in the List data. The style is then applied on the client-side. The net result of this change is that when you read data from a field that has a server-side style, the data no longer includes any HTML markup.

 

Reports - Double Lines - When setting the style for the border around a cell in a Layout Table, you can now set the style to 'double' to create a double line, as shown in the image below.

 

 

Here is how the Properties Pane is configured to set the left edge of the field to a double line:

UX Component - Setting Default Values - Multi-valued Controls - Certain controls in a UX are multi-valued. For example, the checkbox control, a List control that has been configured to allow multi-select, a dropdownbox that has been configured to display more than one line and allow multi-select, etc.

To set the initial (i.e. default value) for a control, you can either set the value in the Default Value property in the control properties, or you can set the value in the onDialogInitialize event, using code like this:

e.control.color = "a"

 

However, there was no easy way to set the default value to more than a single value.

Now, when you specify the default value for a multi-value control, you can use a special array() keyword.

For example, to set the initial value for a checkbox that displays a list of colors, you can enter this in the Default Value property:

array(red,green,blue)

 

Or, you can enter this in the onDialogInitialize event:

 

e.control.selectedColors = "array(red,green,blue)"


 

UX Component - List Control - Custom Datasource - The Xbasic function that is called to compute the data in a List populated by a Custom data source can now return Javascript to the browser by setting a value in this property in the 'e' object that is passed into the Xbasic function for the Custom data source:

e.javascript

 

UX Component - List Control - SQL Data Source - AfterQuery Server-side Event - A new server side event is available for List controls that are populated using a SQL data source.

The AfterQuery event fires after the List query has been performed. The typical use case for this event is to compute some Javascript to return to the browser. For example, you might want to compute the total for a column in the List and then update some control on the screen.


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

Download Components

 

argument_add_array_argument() Function - Adds or updates an array argument to a sql::arguments object.

The sql::arguments object can be populated with argument arrays (typically used when passing values to a SQL query that uses an IN clause).

Syntax: argument_add_array_argument( sql::arguments argumentObject, c argumentName, c argumentType, c argumentValues)

Example:

dim args as sql::arguments

dim cities as c

cities = <<%txt%

London

Boston

Bulawayo

%txt%
argument_add_array_argument(args,"color","c",cities)
 

UX Component - List Control and Data Series - Using Argument Arrays in SQL Queries - You can now use an IN clause with an argument array in the SQL query for a Data Series or List Control.

For example

SELECT customerId FROM customers where country IN (:array_whatCountry)

 

Notice that when using an IN clause with arguments, the argument name must start with array_.

Also notice that the argument reference in the SQL statement is in parentheses.

 

UX Component - Responsive Layout Genie - Mobile applications must run on multiple device form factors and must respond to orientation changes. You typically want to design a single UX component that will respond automatically (i.e. make layout changes) based on the device it is running on (e.g. phone, small tablet, large tablet, desktop browser) and the orientation of the device (mobile devices) or window size (desktop browsers).

The new Responsive Layout Genie makes it easy to create responsive layout designs.

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

Download Components

 

To open the Responsive Layout Genie, click the smart field for the 'Responsive layout settings' property on the UX properties pane.

 

 

This will open the builder as shown below:

 

The builder is divided into three sections. In the first section you define your layout rules. In the second section you define the actions that should take place when a rule is true, and in the third section you define the properties for the action.

 

Rules

Layout rules are simply Javascript expressions that evaluate to true or false. The rules can reference special system fields, such as screen.width, or device.isWebKit.

IMPORTANT: Since the expression is Javascript, you need to use Javascript syntax, such as == for an equality test, && for an AND operator and || for an OR operator.

You can define as many rules as you want. Each rule you define is given a name. The name is arbitrary, but a meaningful name is recommended as you can refer to the rule name in client-side watch expressions.

For example, in the screen shot show above, there are two rules that have been defined.

To add a new rule click the Add Rule button an give the rule a name and enter its expression. When entering the expression, you can click the Insert Field hyperlink to get a list of available system fields to use in the expression.

The image below shows the system fields that can be used in the rule expression.

 

 

You can also save rule sets so that they can easily be imported into other UX components.

 

Actions

Actions are performed when a rule is true. You can define as many actions as you want. To add a new action, click the Add actions button. A dialog allows you to select the action you want to perform:

Once you have selected an action, the Properties for that action can be defined.

Properties

Action properties must be defined for each rules. Therefore, for a given action, you will select the first rule and define the action properties. Then you will select the next rule and define the action properties for this rule, an so on, moving through all of the rules.

 

Using Javascript to Specify an Action Property Value

In some cases you can use Javascript to specify the value of a property. For example, in the screenshot shown above, the 'Layout size' property for PANELCARD_2, for the 'portrait' rule has been specified as:

javascript:getpanelwidth(screen,device)

 

The 'javascript:' prefix indicates that the property value should be computed by calling a Javascript function. This function takes screen and device as inputs so you can reference the special system fields that the Javascript rules expressions reference. In the above case, we are calling a Javascript function, but we could just as easily specified inline Javascript code after the Javascript: prefix.

 

Viewing Generated Javascript

It can be useful to view the generated Javascript for the actions so that you can learn how certain actions are performed.

To see the generated Javascript, right click on an action in the builder.

The dialog (shown below) shows you:

 

When are Layout Rules Evaluated

Layout rules are evaluated:

When the Layout Rules are evaluated the rules are evaluated in the order in which they were defined. When a true rule is found, the actions for that rule are performed and a special property in the UX object is set with the name of the rule that was true.

You can reference this property as follows:

{dialog.object}._activeLayoutRule

 

 

Using Active Layout Rule Name in a Client-side Watch Expression

Client-side watch expressions (e.g. show/hide, dynamic images, enable and dynamic style) can reference a special system field called:

dialog.activeLayoutRule.

 

This field has the name of the currently active Layout Rule.

In the screen below, a container in the UX is only being shown if the 'landscape' rule is true.

 

 

 

Rules Mode

 

By default, the actions associated with the first Layout Rule that is true are executed and then further rules are not checked. However, you can set the Rules Mode to AllRules so that the actions for all true rules (not just the first true rule), are evaluated. To change the Rules Mode, you need to set the Responsive rules mode property in the UX Properties.

 


Watch Video
 

Manually Executing a Rule

Regardless of whether a rule is true or not, you can use a method of the UX object to force the actions for a particular rule to fire.

For example:

{dialog.object}.fireLayoutRule(ruleName)  

 

 

UX, AppLauncher and Custom Component - Page Title Property - The components now have a page title property that allows you to set the page title when the component is run from an .a5w page.

 

 

 

 

Web Projects Control Panel - Search in Files - This feature has now been enhanced to allow you to specify the type of files to search

 

UX Component - List Control - Read-only Property - The List control now has a read-only property. This is especially useful if you have configured the list to behave like a carousel and you want to prevent any item in the List from displaying as selected. To find out what row a click, right click, or double-click action occurred on, your Javascript can reference

arguments[0]

This gives the zero based row index of the target row.

UX Component - Action Javascript - Panel Action - A new action to show/hide a Panel header or footer has been added.

 

ShowXML() Function - Displaying an XML Document Structure - The ShowXML() function is a utility Xbasic function that is helpful in understanding the structure of an XML Document.

Watch Video

The image below shows the user interface displayed by the ShowXML() function.

 

The first image shows the XML pane where the raw XML is displayed. The second image shows the Xbasic Properties pane is shown where a tree view of the Xbasic variable (into which the XML has been parsed) is shown.

 

 

 

 

*property_from_xml() Function - Populates an Xbasic Dot Variable with XML Attribute/Element Values - Xbasic has always had very strong XML parsing features (see Help, Open Documentation and search for 'Parsing XML Documents with Xbasic'), however the new *property_from_xml() function provides a new way in working with XML. This function populates an Xbasic dot variable with the data from the XML document. Once you have he Xbasic variable, it is very easy to extract a specific element or attribute value from the XML document.

 

Watch Video

 

UX Component - List Control - Word Wrapping Text in a Column - New options are available for controlling how long text in a list column should be handled. By default, long text is truncated and ellipses are displayed to indicate that the text is truncated.

You can turn on the word-wrap option for individual fields. When you turn on word-wrap, you now get a 'wordwrap option' property with these choices:

 

UX Component - Server Side Actions - Send E-mail - The server-side Send E-mail action now supports the option of using the Mandrill mail service to deliver the e-mail.

a5_ux_action() - New options added to the a5_ux_action() Xbasic Utility Function - The a5_ux_action() is a utility function that generates the Javascript for certain actions that the UX can perform. The use case for this function is to consolidate several Ajax callbacks into a single callback. New options have been added to this method. The full list of options current supported are summarized below:

The actions that can be performed by this utility function are:

 

 

 

List Control Action:Filter List

Filters/sorts the data in a List control.

This action is equivalent to the {dialog.object}.filterList() method.

Example:

 

Function myAjaxCallback as c (e as p)

 

    dim ops as p
    ops.Action = "Filter"
    ops.filter = "country = :country and city = :city"
    ops.order = "companyname desc"

 

    'the arguments are specified in a crlf() delimited string.

    'syntax is argumentValue|||type|argumentName

    ops.parameters = "UK|||c|country" + crlf() + "London|||c|city"
 

    'specify the id of the list to filter

    ops.listId = "list1"

 

    dim xb as c

    xb = a5_UX_Action(e,ops,"ajaxListAction")

 

    myAjaxCallback = xb

 

end function

 

 

List Control Action: Refresh List

Refreshes the data in a List control.

This action is equivalent to the {dialog.object}.refreshListData() method.

Example:

Function myAjaxCallback as c (e as p)

    dim ops as p
    ops.Action = "Refresh"
    ops.listId = "list1"

    dim xb as c

    xb = a5_UX_Action(e,ops,"ajaxListAction")

    myAjaxCallback  = xb

end function

 

 

List Control Action:Refresh Row(s) by key value

Refreshes data in one or more rows of a List control.

This action is equivalent to the {dialog.object}._listRefreshRecordsByKey() mehod.

Example:

 

Function myAjaxCallback as c (e as p)

    dim ops as p

    'primary keys to refresh (case sensitive!)

    ops.primaryKey = "EASTC,GALED,FURIB"
    ops.listId = "list1"
    ops.action = "refreshRowByKey"

 

    'if the record to be refreshed is not currently in the list,

    'should it be added to to the list?
    ops.appendRowsNotInList = .f.
 

    dim xb as c
    xb = a5_UX_Action(e,ops,"ajaxListAction")
    myAjaxCallback = xb

end function

 

 

 

 

List Control Action:Append row(s) by key value

Appends data to a List control.

This action is equivalent to the {dialog.object}._listFetchRecordsByKey() method.

Example:

 

Function myAjaxCallback as c (e as p)

    dim ops as p

    'primary keys to fetch and add to list (case sensitive!)

    ops.primaryKey = "EASTC,GALED,FURIB"
    ops.listId = "list1"
    ops.action = "appendRowByKey"
    dim xb as c
    xb = a5_UX_Action(e,ops,"ajaxListAction")
    myAjaxCallback = xb

end function

 

Refresh Data Series

Refreshes one or more data series. All controls that are bound to the data series are refreshed.

This action is equivalent to the {dialog.object}.refreshDataSeries() method.

Example:

Function myAjaxCallback as c (e as p)
    dim ops as p
    ops.Action = "refreshDataSeries"
    ops.seriesNames = "series1,series2,series3"
    dim xb as c
    xb = a5_UX_Action(e,ops,"ajaxListAction")
    myAjaxCallback = xb
end function
 

Set UX into 'New Record' mode

This action is equivalent to the {dialog.object}.newRecord() method

Example:

Function myAjaxCallback as c (e as p)

    dim ops as p
    myAjaxCallback = a5_UX_Action(e,ops,"NewRecord")
end function

 

 

Populate Controls with Data From a Table

(Applies only if the UX has been data bound). Populates controls on the UX with data from the data bound tables for a specified primary key value.

This action is equivalent to the {dialog.object}.populateControlsFromTable() method.

Example:

Function myAjaxCallback as c (e as p)
    dim ops as p

    ops.primaryKey = "ALFKI"  'case sensitive!

    dim js_getRecord as c 

   

    ops.__dtfmt = e.rtc._state.__dtfmt

    dim js as c
    js = a5_UX_Action(e,ops,"populateControlsFromTable")

    myAjaxCallback = js

end function

 


Refresh choices in a dropdownbox control

This action is equivalent to the {dialog.object}.refreshDropdownBoxChoices() method.

Example:

 

function myAjaxCallback as c (e as p)
    dim js as c
    dim ops as p

    'name of dropdowncontrol to refresh
    ops.controlName = "CITIES"

    'if the control is in a repeating section should just the current instance

    'be repopulated
    ops.currentRepeatingSectionRowOnly = .f.

   

    'filter for query
    ops.filter = "country = :whatcountry"

    'argument value - format is value|||type|argumentName
    ops.arguments = "USA|||c|whatCountry"

 

    'value in dropdownbox to select after it has been populated
    ops.selectedValueAfterPopulate = ""


    js = a5_ux_action(e,ops,"refreshDropDownBox")
    myAjaxCallback = js

end function

 

 

SQL Query Genie - Export to Excel - The 'Actions' button on the SQL Query Genie toolbar now has a new option - export to Excel.

TabbedUI Object - New methods added to the TabbedUI object - You could previously get the active Pane by examining private variables in the tbiObj object. Now, these new methods provide an easier method.

 

tbiObj.getCurrentPaneIndex() - zero based pane number for the current pane

tbiObj.getCurrentPaneName() - internal name of the current pane

tbiObj.getCurrentPaneLabel() - HTML label for the tab current pane.

 

You can also programmatically set the active pane, either by its index (zero based), or by it label.

tbiObj.selectPaneByIndex(index) - set active pane by index

tbiObj.selectPane(label) - set active pane by Label

 

 

 

UX Component - Frame and Container Controls - Client-side Conditional Style and Class - You can now define client-side watch expressions to automatically change the style and/or class of a container or frame control. Previously, conditional client-side style and class were limited to input controls, buttons, etc.

 

UX Component - Repeating Sections - Setting a Column Width Using Javascript - A new method has been added to the UX control to allow you to programmatically change the width of a Repeating Section column at run-time.

{dialog.object}.setRepeatingSectionColumnWidth(columnName,width);

Width is expressed using CSS units (e.g. '100px'). Percentage widths are not supported.

 

Mobile Theme - Slate - A new stylesheet for mobile applications is ready for testing. This style (screenshots shown below) is not yet complete and will only work for UX components. If does not contain any CSS classes for Grids or Tabbed UI. We are making this new style available to mobile developers now to get feedback on what you like and don't like about the style.

To download the style click here. Unzip the file into the CSS folder where you have Alpha Anywhere installed. This will create a new folder called Slate in the CSS folder. To use the style, edit a UX component, and then change the style name for the component to 'Slate'.

 

 

 

12

 

 

pdf_optimize() Function - Optimize a PDF document to make it smaller. Results may vary based on the compression of the original file, but file size may be reduced by up to 50%.

Syntax:

pdf_optimize(C file [, C NewFile])

 

If NewFile is not specified the input file is replaced.

json_generate() Function - Performance - The json_generate() function has been re-written and is now considerably faster.

NOTE: Previously the json_generate() function would escape single quotes. However the JSON spec does not require this and so single quotes are no longer escaped. For example:

dim pj as p
pj.text = "some text with ' single quote"
?json_generate(pj)
= {
       "text": "some text with ' single quote"
}

 

 

UX Component - Spin List Control - Large Data Sets - There has been a significant improvement in the time taken to populate a Spin List control when populating it with a large number of choices.

 

UX Component - Map Control - Specifying the Map Language - By default, the language used on the Map control is based on the browser setting for language preference. A new property has been added to allow you to specifically set the language preference. To get a list of valid language code go to:

http://msdn.microsoft.com/en-us/library/ms533052(VS.85).aspx

 

SQL Query Genie - Count Query - When you build a SQL query using the SQL Genie and you preview the query, a count query is automatically performed when your query is executed. This is done so that your preview will show you how many records satisfied the query. However, in some cases the database to which you are connected might take a long time to execute a count query and therefore you might want to turn off the count query when previewing your query. A new property on the Properties pane of the SQL Genie allows you to do this.

 

 

UX Component - Action Javascript - Buttons - A new action has been added to Action Javascript to enable or disable a button. This action only applies to Advanced Buttons (all buttons in a UX component are advanced buttons by default).

 

email_send_mandrill() Function - Setting the Key Value Globally - You can now set the key for this function in the Web Project Properties dialog. If you do set the key in Web Project Properties, then you can pass in a blank key in the email_send_mandrill() function. If you pass in an explicit key when calling email_send_mandrill(), then the key you pass in will override the gloal key.

 

Grid and UX Component - Field Validation - Xbasic - If you write custom Xbasic code to validate an individual field, your Xbasic code and now send back a Javascript response to the client by setting this property in Xbasic code:

e.javascript

 

 

UX Component - Buttons - .getControl() Method - The {dialog.object}.getControl() method can now be used to get a pointer to a button object. Once you have a pointer to the object, you can call the .setDisabled() method.

For example:

var bObj = {dialog.object}.getControl('BUTTON_1');

//set the button disabled

bObj.setDisabled(true);

//now enable the button

bObj.setDiabled(false);

 

NOTE: As a result of this change, if you have a client-side enable expression for a button in a Repeating Section, you will need to edit the enable expression and resave it in order to re-generate the Javascript code.

 

ADVANCED NOTE: If you have a button in a Repeating Section, the .getControl() method will point to ALL of button instances (i.e. the button in row1, row2, etc.). If you then call the .setDisabled() method, you will be set the state on the button in each row.

If you want to call the .setDisabled() method for a specific button instance (say the button in row 3), then you can pass in an optional parameter to the .setDisabled() method. For example:

//get a pointer the button element in row 3

var eles = $('{dialog.componentname}.V.R1.BUTTON_2_A5INSTANCE3');

//pass in eles as an optional argument to the .setDisabled() method
{dialog.object}.getControl('BUTTON_2').setDisabled(true,eles);

 

 

 

 

 

Build 1620-4172  21 Aug 2013

Videos

UX Component Preventing a Panel from Losing Focus A common design pattern in a mobile application is to have multiple Panel Cards inside a Panel Navigator. If one of the Panel Cards contains a form, you might want to prevent the user from navigating to another Panel Card if the form has been edited, but not yet been saved.

In this video we show how this is easily done using the Panel Navigator's onBeforePanelActivate event. The same techniques can be used in a PanelLayout.

Watch Video
Download Component

   

UX Component Responsive Design - Dynamically Resizing Controls on Orientation or Window Size Change - Understanding the FlexLayout Container A common requirement when designing a UX component is to have a control dynamically resize when the orientation of a mobile device changes or when the window size (in a desktop browser) changes. This is easily accomplished using the FlexLayout container on a UX.

Any of the controls in a FlexLayout container can have their width specified as a 'relative' size (relative to the size of the other controls in the FlexLayout container). This video shows how to use the FlexLayout container type.


Watch Video - Part 1
Watch Video - Part 2

Bugs

UX Component - Image Upload Action - Thumbnails - If you specified that you wanted to create a thumbnail when uploading images, and the target for the thumbnail image was a character field in the target table, the 'image filename transformation expression' was being ignored and the actual filename for the thumbnail image that was stored was always just the short filename.

<Resultset>.ToJSONObjectSyntax() method - The JSON generated by this AlphaDAO method has been changed. Previously, the values in the generated JSON were single quoted. Now, to be consistent with the official JSON syntax, values are double quoted.

UX Component - Tab Control - Genie Style - If a 'genie' style Tab Control was wrapped in a Container control and the [Tab Control End] control came immediately before the [ContainerEnd] control, the genie buttons did not render.

Grid Component - Images - Under some circumstances, if a Grid contained an image control, it would generate an error. This was a newly introduced bug. If you received this error, you will need to edit and resave the Grid.

 

Features

 

UX Component - PanelNavigator and PanelLayout - onBeforePanelActivate Event - A new event has been added to the PanelNavigator and the PanelLayout. This event is useful if you want to prevent the Panel that has focus losing focus. For example, if the form fields on a Panel have been edited, but not yet committed, you might want to prevent the Panel from losing focus. This is much like preventing a pop-up window that contains a Grid or UX component from closing if the child component has been edited.

If the Javascript that you define in the onBeforePanelActivate event returns false, then any attempt to activate another Panel will fail and focus will remain on the Panel that currently has focus. If the event returns true, then you will be able to give focus to another Panel.

Watch Video
Download Component

 

UX and Grid Component - Image Upload - Thumbnails - The Action Javascript builder now has a new option in the Thumbnail Definition Builder to allow you to specify if the thumbnail file that is created should overwrite an existing file, or be renamed, so as not to conflict with existing files.

 

UX and Grid Component - Image Upload - File Rename - When you upload images or files and store the uploaded images or files in a filename on a server, there is an option to rename the file if there is an existing file with the same name on the server. The algorithm that computes the filename in the case of a conflict has been changed slightly.

Previously, if a filed called "c:\myimages\image1.jpg" existed and you wanted to create a new file called 'image1.jpg', the new file would have been called "c:\myimages\images2.jpg".  This is now changed to "c:\myimages\myimage1_1.jpg".

 

UX Component - FlexLayout Containers - A new container type in the UX component makes it easy to dynamically size controls when the orientation of the device changes (mobile devices), or the window size changes (desktop browsers).

Watch Video - Part 1
Watch Video - Part 2

 

The purpose of the FlexLayout container is to dynamically size the widths of controls that are on a single line. This container does not size the height of controls.

 

NOTE FlexLayout containers are not supported in Repeating Sections.

 

For example in the image below, the device is in portrait mode. The button to the right of the textbox control is set to have a fixed size of 80px. The text box has been set to have a flexible width, so it consumes all of the available space (less the built-in padding between controls, defined by the A5CWLayout class padding property).

 

Notice in the image below, when the device orientation is changed to landscape, the button size has not changed - it is still 80px wide. But the textbox had grown in width.

 

 

Here is how the textbox and button control are represented in the builder. Note that the controls are wrapped in a container with a sub-type of 'FlexLayout'.

 

 

When you set the container sub-type to FlexLayout, a new property in the Property Grid is exposed.  The image shows that the 'Flexible layout width settings' have been set to:

flex(1),80px

This means that the first control in the FlexLayout container will have relative width of flex(1) (this is the textbox), and the second control (i.e. the button) will have a fixed width of 80px.

 

 

 

The property has a smart field which brings up a builder to help you set the control widths.

Notice that the builder also shows the 'Defined Width' for each control. The 'Defined Width' is the width that was defined for each individual control.

Typically when you wrap controls in a FlexLayout container, you will want to set each control's Defined Width to 100%. The builder will show you at a glance if any of the top-level controls in the FlexLayout container have not been set to 100%.

The 'Break' column will also show you at a glance if any of the top-level controls in the FlexLayout have breaks after them. You should not have breaks after top-level controls, so the builder will give you a warning to fix this problem.

 

In the case where only one control in a FlexLayout container has a 'flex' width, the meaning of the flex setting is simply to fill the available space on the line (after allocating space to the fixed size controls).

However, if you have two or more controls with a 'flex' setting, then all of the flex controls together will fill the available space (after allotting space to any fixed size controls), and each 'flex' control will have a relative size based on its 'flex' setting.

For example, if you have two flex controls with settings of flex(1) and flex(2), then the second control will always be twice the width of the first control.

 

 

 

Build 1617-4170  19 Aug 2013

Videos

 

UX Component Storing and Restoring the 'state' of a UX Component with multiple Panels UX Components can use complex layouts that involve multiple Panel Cards inside Panel Navigators and Panel Layouts. You might want to persist the state of the Panel (i.e. remember which Panel Card in a particular Panel Navigator is active and which Panels in a Panel Navigator have been docked) so that you can later restore this state. This video shows how this can be done.

Watch Video
Download Component

 

Tips

SQL Server 2008 - Date Fields - Occasionally, users report a problem when trying to update a MS SQL table that has a 'Date' field. The problem is caused because the correct Microsoft files are not installed on the machine where SQL Server is running. The error reported by SQL Server is:

 "Function requested is not supported" 

The correct MIcrosoft drivers can be downloaded here:

Here are the links to the download on the Microsoft web site:

X86 Package(sqlncli.msi) - 4549 KB
X64 Package(sqlncli.msi) - 7963 KB
IA64 Package (sqlncli.msi) - 11112 KB

Bugs

Forms - Embedded Browse - Data Entry - Fixed a cosmetic issue with data entry when working with a set that has a one-to-one link off a table that is linked to the parent in a one-to-many link.

UX - Signature Capture - If the UX component was not using Panels, and if the component had been vertically scrolled, the signature capture area did not scroll with the window. This only affected UX components that did not use Panels.

UX Component - Image and File Upload Actions in Action Javascript - As a result of a change made in a recent update to make the value in the client side controls available to the server side Xbasic events, when you clicked the button to upload a file or image, the popup window which was displayed did not have any controls in it. This bug, however, only happened if there were a large number of controls on the UX component. It also only happened in IE. The reason it happened is that the maximum length for a query string was exceeded. This is now fixed.

 

UX Component - Image and File Upload Actions in Action Javascript - Xbasic Event Handlers - When the Xbasic event handlers execute, the value of the control on the UX component are now available in the

e.formData

property. Previously, the data was made available in another of the e object's properties. If you have an event handler that references client side control values, you will need to change your code.

UX Component - Image Controls (Data Bound) - Repeating Sections - Fixed a bug that was introduced in the last update.

 

Features

Email - Sending Email Using the Mandrill Email Service - Alpha Anywhere has always offered Xbasic functions to send email. However, these functions require that you have access to a SMTP mail server. The existing functions in Xbasic include:

 

With the emergence of email services, such as Mandrill (www.mandrillapp.com) an alternative, possibly easier, certainly more powerful, way of sending emails from your applications is now possible.

A new function,

email_send_mandrill()

 

allows you to send email using the Mandrill service.

Benefits of using a 3rd party emailing service include the easier setup, better deliverability, and access to powerful value added features offered by the service, such as tracking whether people open your email message, etc.

The full functionality of the Mandrill email service can be read by navigating to this address:

https://mandrillapp.com/api/docs/index.JSON.html

In order to use the Mandrill email server, you will have to visit their web site and apply for a key. The key allows you to send a certain number of free emails each month. Beyond that, there is a fee.

NOTE: Alpha Software is not involved in any way at all in the fee and does not receive any payment at all if you use the Mandrill service.

There are two different ways in which you can use the email_send_mandrill() function.

1. Simple Method: Define Message Using Xbasic Dot Variable

In the simple method, you define an Xbasic dot variable that defines the properties of the message you want to send and then you call email_send_mandrill(), passing in your Mandrill key and the dot variable. This simple method does not expose all of the functionality of the Mandrill service, but it is very easy to set up and use, and it is great for simple email messages.

For example:

 

 

'create a .dot variable to define the message

dim ms as p
ms.send_to = "john@acme.com:John Smith,sally@acme.com:Sally Jones"
ms.send_to_cc = ""
ms.send_to_bcc = ""
ms.from_email = "sales@alpha.com"

ms.from_name = "Sales at Alpha" 'friendly name - optional

ms.subject = "Information You Requested"
ms.message_html = "Here is the <b>information</b> you requested."
ms.message_text = "Plain text version of the message"
ms.attachments = "c:\files\mychart1.pdf,c:\files\mytext1.txt"
 

 

 

Notes About the Properties in the Dot Variable

CC and BCC Addresses

Even though the Dot variable allows you to specify separate comma delimited lists for the TO and CC addresses, in reality, Mandrill does not support CC addresses. Furthermore, Mandrill only supports a single BCC address.

If you specify any CC addressesl, the TO list and the CC list of addresses is combined into a single list and the emails are sent to all addresses in the combined list. However, the Mandrill internal .preserve_recipients property is set to false, so that none of the recipients will see the names of any other recipients.

If you provided a list of names in the TO list, and no names in the CC list, the recipients of the email would all be able to see the names of the other recipients.

Once you have defined the .dot variable, you can send the message. For example

 

dim pResult as p

pResult = email_send_mandrill("mysecretkey",ms)

 

The function returns a .dot variable with several properties:

Here is what a typical item in the .result array looks like:

result[1].email = "john@acme.com"

result[1].status = "sent"

result[1]._id = "some message id" --- used to make queries against the Mandrill API for message status

 

Here is a complete example of sending an email in the simplest possible way (eliminating all optional properties in the Xbasic .dot variable). As you can see, it just a few lines of code.

'create a .dot variable to define the message

dim ms as p
ms.send_to = "john@acme.com:John Smith,sally@acme.com:Sally Jones"
ms.from_email = "sales@alpha.com"

ms.from_name = "Sales at Alpha" 'friendly name - optional

ms.subject = "Information You Requested"
ms.message_html = "Here is the <b>information</b> you requested."
dim pResult as p

pResult = email_send_mandrill("mysecretkey",ms)


 

Alternative Method for Specifying Attachments - Specifying the Attachment Data

We have previously indicated that attachments are specified by setting the .attachments property to a comma delimited list of filenames. An alternative method is to set the .attachmentsArray property as a property array with .name, .type and .content properties.

Where:

 

For Example

dim ms.attachmentsArray[1] as p
ms.attachmentsArray[1].name = "chart.pdf"
ms.attachmentsArray[1].type = resolve_mime_type("pdf")
ms.attachmentsArray[1].content = base64encode(file.to_blob("c:\myfiles\chart.pdf"))

 

Merge Variables - Mail Merge Variables into the Message Body and Subject

An advanced feature of the Mandrill service is to allow you to specify placeholders in the message subject and body that will be replaced with variables that you supply at the time Mandrill sends out the email to each recipient.

The format for the placeholders is:

 *|VariableName|*

 

For example, here is how the message subject or body could have been specified using placeholders:

ms.subject = "*|Fname|*, here is the Information You Requested"
ms.message_html = "*|Fname|* *|Lname|* here is the information you requested."
 

When you use placeholders in the subject or body, you must specify the placeholder values. Obviously, you need to specify placeholder values for each recipient.

For example, assume that you had specified two recipients as follows:

ms.send_to = "john@acme.com:John Smith,sally@acme.com:Sally Jones"
 

You would then need to specify the FName and LName variables for john@acme.com and for sally@acme.com.

Here is how you would do this:

 

'define the .merge_vars[] array with 2 items

dim ms.merge_vars[2] as p

 

'define the actual variables for the first recipient.

'since there are two variables, we define a sub-array with two items

dim ms.merge_vars[1].vars[2] as p

 

'here are the variables for the first recipient
ms.merge_vars[1].vars[1].name = "FName"
ms.merge_vars[1].vars[1].content = "John"
ms.merge_vars[1].vars[2].name = "LName"
ms.merge_vars[1].vars[2].content = "Smith"
ms.merge_vars[1].rcpt = "john@acme.com
 

'here are the variables for the second recipient
dim ms.merge_vars[2].vars[2] as p
ms.merge_vars[2].vars[1].name = "FName"
ms.merge_vars[2].vars[1].content = "Sally"
ms.merge_vars[2].vars[2].name = "LName"
ms.merge_vars[2].vars[2].content = "Jones"
ms.merge_vars[2].rcpt = "sally@acme.com
 

In addition to supplying merge variables for each recipient, you can also supply global merge variables - for all recipients. You do this by specifying the .global_merge_vars property array. If a merge variable is defined at the individual recipient level, it will override the corresponding global merge variable.

For example:

dim ms.global_merge_vars[1] as p

ms.global_merge_vars[1].name = "Company"

ms.global_merge_vars[1].content = "Alpha Software"

 

 

Using a DataSource Property

Instead of supplying the actual email addresses and merge variables directly in the dot variable you can pass in a 'dataSource' (an array of JSON objects), and then indicate that the .send_to property should be populated from the data source.

 

For example, consider the following definition of the .dataSource property:

ms.dataSource = <<%txt%
[
    {email: "sam@acme.com", firstName: "Sam", lastname: "Smith"},
    {email: "joe@acme.com", firstName: "Joe", lastname: "Jones"}

]
%txt%

If the above .dataSource property has been defined, then you can define the .sent_to property as follows:


ms.send_to = "{datasource:email}"

 

This indicates that the .send_to property should be populated from the 'email' property in the dataSource.

If you pass in a .dataSource property, then there is no need to pass in the .merge_vars property - these properties are automatically generated from the data in the .dataSource property.

Here is what happens if you pass in a .dataSource property: The .message_html, .message_text and .subject properties are scanned to see if any merge-variables are used. If any merge variables are found in any of these properties, then the merge variables for each address are automatically extracted from the .dataSource property.

Using the .dataSource property, it is extremely easy to create a mass mailing with custom merge variables for each recipient.

 

2. Advanced Method: Define Message Using a JSON String

The JSON method exposes the full functionality of the Mandrill service. To see all of the options that are available, please see the Mandrill API documentation.

If you want to use advanced features, like track opens, or schedule delivery, you will need to use this option.

Here is an example of how you can use this method:

 

 

DIM json as C = <<%str%
{
    "message": {
    "to": [
        {
        "email": "john@acme.com",
        "name": "John Smith"
        }
    ],
    "from_email": "Sales@alpha.com",
    "subject": "Information You Requested",
    "html": "Here is the <b>information</b> you requested",
    "text": "Plain Text Message",
    "preserve_recipients": false
},
"asynch": false,
"ip_pool": null,
"send_at": null
}
%str%

dim pResult as p

pResult = email_send_mandrill("mysecretkey",json)

 

Generating the JSON String From Xbasic

Xbasic has powerful functions for generating JSON from an Xbasic dot variable. For example, the json_generate() function will generate JSON from a .dot variable.  A powerful way to programmatically construct the JSON string that you pass into the email_send_mandrill() function is to build up an Xbasic .dot variable with the various properties that you want to set, then call json_generate() to generate the JSON.

 

 

UX Component - Panels - New Methods - Some new methods have been added to the UX component that allow you to save and restore the state of a complex Panel Layout.

Watch Video

 

.getPanelObject()

If the UX component use Panels, gets a pointer to the Panel object. Once you have a pointer to the Panel Object you can call methods of the Panel Object (such as .getState() and .setState()). For example:

var pno = {dialog.object}.getPanelObject();



 

<panelObject>.getState()
Gets the 'state' of the Panel Object so that it can later be restored. An object is returned. The active Panel in all Panel Navigators is stored as well as the dock state of Panels in Panel Layouts.
The purpose of getting the Panel State is so that you can later restore is using the .setState() method. For example:

//Get a pointer to the Panel Object
var pnObj = {dialog.object}.getPanelObject();

//Get the current state of the Panel Object
var state = pnObj.getState();

//See what's in the 'state' object
alert($u.o.toJSON(pnObj.getState());

 

<panelObject>.setState();

Restores the state of a Panel Object from a previously created
 


//Get a pointer to the Panel Object
var pnObj = {dialog.object}.getPanelObject();

//Restore the state of the Panel Object. (Assume that the state is in a variable called 'state')
pnObj.setState(state);
 

 

 

Video Player Component - SSL - A new property to use SSL has been added.

UX Component - List Control - Data Source - A new option has been added for specifying the data source of a List control. The 'Javascript Function' option allows you to specify the name of a Javascript function. This function must return an array of JSON objects that contain the data for the List.

When you choose this option, you must specify the name of the Javascript function as well as a list of columns that the List has.

For example, assume that you specify that the List has these columns:

Firstname,Lastname,City

 

Your Javascipt function could then be defined as follows:

function getListData() {

    var data = [

        {Firstname: 'Jim', Lastname: 'Smith', City: 'Boston'},

        {Firstname: 'Cecelia', Lastname: 'Dawkins', City: 'Denver'}

    ]

    return data;

 

}

 

Build 1607-4169 14 Aug -2013 8:47 AM

Bugs

Ux Component - Client-side Conditional Style and Text - Repeating Section - If you set a text property (as opposed to a style property) for a control that was in a Repeating Section, you would get a Javascript error.

Web Applications - Publishing - FTP Optimized - AEX Files - If you used Optimized FTP publishing to publish a web application that used .aex files, the functions in the .aex file would not be seen until the server had been stopped and restarted. This is now fixed.

UX Component - Image Upload Action Javascript - A bug introduced in build 1605 was fixed.

Build 1605-4168 13-Aug -2013 10:15 AM

 

 

Videos

UX Component Chart Control - Dynamically Changing the Chart Appearance by Changing the Stylesheet In the previous video we showed how aspects of the chart appearance could be changed at run-time. In this video we show how a dynamic stylesheet can be applied to the chart to control even more aspects of the chart appearance.

Watch video
Download Component

TIP: To get started creating a custom stylesheet for a chart, you should start with the style builder, then convert to CSS. See video.
UX Component User-defined Sub-themes to Style UX Component Controls Many of the controls on a UX component allow you to specify a sub-theme. The sub-theme controls various aspects of a control's appearance and also behavior. For most of the controls there are several built-in sub-themes to chose from. For example, buttons have sub-themes that can make the button look like a 'back' or 'next' button. A powerful aspect of sub-themes is the fact that it is very easy for developers to create their own sub-themes to create highly customized appearances for controls on a UX.

In this video we show how a custom sub-theme for a window can be created and used.

Watch Video - Part 1
Watch Video - Part 2
Download Component
UX Component Getting a Pointer to a Parent or Child Component So You Can Call Methods of the Parent or Child Component The ability to re-use components and open a child component in a window, div, TabbedUI pane, Panel, or embed into a parent component is one of the most powerful aspects of the Alpha Anywhere architecture.

When you open a component from a parent component, you will often want to get a pointer to the child component so you can manipulate it in your Javascript code in some way. For example, you might want some code in the parent component to read a control in the child, or set a value in the child. Similarly, you might want some code in the child component to read or set a control in its parent.

The .getParentObject() and .getChildObject() methods are used to get pointer to an object's parent or child objects.

In this video, we show how this is done.

Watch Video - Part 1
Watch Video - Part 2
Download Component
Grid Component Putting the Search Part in a Pop-up Window In this video we show how the Search part of a Grid component can be shown in a window. By default, the Search part is shown on the page directly above the Grid part, but by showing the Search Part on in a window, you can save space on the page.

Watch Video
Download Component (requires a connection string called 'Northwind' that points to the sample Northwind.mdb files database in the MDBFiles folder).
UX Component Example App Showing How to Synchronize an Embedded UX Component when a Value in a Parent UX Component Changes A common pattern when building mobile applications is to break the application into multiple sub-components and then embed child components into the parent component. Using this pattern, you break your application into manageable pieces. However, when you follow this pattern, it is often necessary to synchronize the embedded child component when a value in the parent component changes.

In this video we show a sample application that shows customers in the sample Northwind database. An embedded UX component shows the orders for the selected customer. When the user selects a different customer, the embedded 'Orders' UX component is synchronized.

Watch Video - Part 1
Watch Video - Part 2
Watch Video - Part 3
Download Components (requires a connection string called 'Northwind' that points to the sample Northwind.mdb files database in the MDBFiles folder).
UX and Grid Component Handling Missing Images When a UX or Grid component displays images, there is a possibility that an image referenced in an image tag is missing. A new onImageError client side event allows a developer to programmatically handle this situation and decide what image to display in place of the missing image.

Watch Video
UX Component - List Control Custom Layout - Setting a List Item Size to Fill the Screen - Understanding the 'Fill' Option for List item size and Custom Scrolling Options. When you are working with a List control that uses a free-form layout for the List, you can set the height (and width in the case where the List is set to scroll horizontally) of each 'row' (i.e. 'item') in the List. In addition to setting an explicit size (say 200px) for an item height or width, you can also use the special 'fill' keyword to indicate that the item should fill the viewport.

When you use the 'fill' option, it is often desirable to customize the way in which the List scrolls, so that it scrolls in discrete amounts (for example the size of the viewport) rather than scrolling continuously.

By setting the item size to use the 'fill' keyword, and by customizing the List scrolling, it is possible to make a List behave much like a Panel Card in a Panel Navigator.

In this video we show how these options are used.

Watch Video - Part 1
Watch Video - Part 2
UX Component Signature Capture Control A common requirement in mobile applications is the ability to capture a signature and store the signature in a database. In this video we show how this is easily achieved by placing a Signature Capture control on a UX component.

Watch Video - Part 1
Watch Video - Part 2
Reports Printing QR Codes Video shows how to print a QR Code on a report.

Watch video
UX Component Using a UX Component to Create  a Login Component for a Mobile Application A common requirement for any application, Mobile included, is to authenticate users before they can interact with the application. There are several ways in which authentication can be performed in Alpha Anywhere. These include using the standard Login component, or using the AppLauncher. In addition to the above two techniques, you can also build a UX component for performing the authentication.

The advantage of building the Login screens using a UX component is that you can make a much richer UI for the login and it can include standard mobile elements like Panel Headers, etc.

In this video we show how an authentication layer has been added to a mobile application.

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

Download Web Project Used in Videos - Note: To use the project, create a new, empty Web Project, then click the 'Open Project Folder in Windows Explorer' button and paste these files into the folder. The passwords for the sample accounts are:
a@a.com - aalpha,
s@a.com - salpha
m@a.com - malpha
 
     

Tips

Xbasic - Running External Programs from Within Alpha Anywhere - .NET Framework- A common requirement is to run external programs from with Alpha Anywhere. Xbasic has had the sys_shell() and sys_shell_wait() command for many versions, but you can also use .Net framework methods. The method is:

System::Diagnostics::Process::Start()

 

For example, say you want to log onto a VPN