Grid Component - New Features

The V10 Grid component has been completely rewritten to use Web 2.0 Ajax features.  A huge number of new features have been added to the Grid and the Grid performance is now dramatically faster than the V9 Grid component.

'Alphabet'/Custom Button Search

'Alphabet' buttons provide a convenient metaphor for searching for records in your Grid. When you click on a particular alphabet button, the Grid is filtered to show all records in a specified field that start with the letter that you clicked. For example, if you specify that your Alphabet buttons should search on the lastname field, when you click on the 'B' button, all records with lastnames that start with 'B' are shown.

Alphabet Buttons

 

'Alphabet' buttons showing 'hyperlink' style buttons.

 

 

'Alphabet'  buttons showing 'button' style buttons.

 

You can position the 'Alphabet' buttons inside the Grid, as shown in the above two images, or outside the Grid, as shown below.

'Alphabet' buttons showing how the buttons can be positioned outside the Grid.

 

You can configure your 'Alphabet' buttons to also show buttons for 0 through 9 by checking the 'Include numeric buttons' property.

You can configure your 'Alphabet' buttons to show as choices in a dropdown box rather than as a list of buttons or hyperlinks by setting the button style to 'Dropdown'.

'Alphabet' buttons configured to display as a dropdown.

 

Custom Buttons

You are not limited to a pre-defined list of buttons showing A through Z when you turn on the Alphabet buttons feature. You can completely customize the buttons that are shown in the button bar and the corresponding search that is performed when you click a button. To customize the buttons, select 'Custom Buttons' in the 'Search bar type' prompt. Then click the smart field in the 'Custom search definition' property. The following dialog will appear:

 

 

The button definition is to the left of the equal sign and the corresponding filter expression is to the right of the equal sign.

You can display arbitrary HTML as the button definition (as long as you set the button style to be button or hyperlink - not dropdown). This means (for example) that you can include images in the buttons.

 

Search Part - Query by Form Search Syntax

The Search Part in the Grid can be configured to allow Query by Form (QBF) syntax. QBF search now supports != operator. If you have configured the Search Part to allow QBF syntax, you can now use != to search for records that are not equal to a particular value. The complete list of QBF operators is shown below:

Operator Example Meaning
= =alpha equals 'alpha'
> >10 greater than 10
<= <= 12/18/1952 3:23 PM less than or equal to 12/18/1952
< <10 less than 10
<= <=23 less than or equal to 23
!= !=alpha not equal to 'alpha'
value1..value2 alpha..beta values that are >= 'alpha' and <= 'beta'. If the field you are searching is a time field (which has a date and time portion), and you omit the time part from value2, Alpha Five will automatically add a time part of 23:59:59 PM to the timer part.
..value2 ..12/1/2008 values that are less than or equal to 12/1/2008. Note: If the field you are searching is a time field, and you omit the time part, Alpha Five will automatically search for values less than or equal to '12/1/2008 23:59:59 pm'
value1.. 23.. values that are greater than or equal to 23
Is blank Is blank Values that are blank or null. (To omit null values use = '' instead of 'Is blank' )
Is not blank Is not blank Values that are not blank or null.
Is null Is null Values that are null (SQL databases only)
Is not null Is not null Values that are not null (SQL databases only)
value1,value2,value3 alpha,beta,gamma values that are 'alpha' or 'beta' or 'gamma'

 

Time Searches - Range Search

If you define a Search Part in a Grid and include a Time field in the Search Part and set the Time field to be a Range search, then if you enter a TO value that does not include a time part, a time part of "12:59:59 pm" is automatically added. This makes it easier to search for records in a date range.

For example, lets say you have 3 records with time values of '1/1/2009 10:00 am', '1/1/2009 3:15 pm' and '1/1/2009 6:45 pm'. Previously, if you entered a start time of '1/1/2009' and and end time of '1/1/2009' the search would have found 0 records. Now, it will return the 3 records on 1/1/2009.

Similarly, if you use the QBE syntax, and you enter a search value of 1/1/2009..1/1/2009, Alpha Five will convert that search to 1/1/2009..1/1/2009 12:59:59 pm.

 

Search Part - Labels for the 'Sort by' Dropdown

A new option allows you to use Grid column headings in the 'Sort by' dropdown box. By default, field names are shown in the dropdown box.

 

Page Navigator - Direct Page Navigation

Property name: 'Record navigator layout' ('Properties' pane)

You can now select the target page by typing the page number into an edit box and pressing Enter. The benefit of this method of page navigation is that it gives you direct access to any page in the Grid. By contrast, the V9 and earlier technique of providing page links can only allow you direct access to a limited number of pages that are close to the current page.

To turn on this feature, open the 'Record navigator layout' genie and check the 'Use type-in box for page navigation' checkbox.

 

Setting the page navigation style

 

Record navigator showing type-in box for page navigation

 

Record navigator showing V9 style page links.

 

Updateable Grids - Edit On Demand

Property name: 'Row edit style' ('Update Properties' pane)

Previously, if a Grid was updateable, then all of the rows in the Grid would be displayed using edit controls for each field (i.e. TextBoxes, TextAreas, etc.).

Now, there is a new option called 'Edit On Demand'. When you select this option, the Grid is shown as using labels for each control. You can then double click on a field, or click the Edit icon, to turn that row into edit mode. You can specify if more than one row at a time can be in edit mode. If only one row is allowed in edit mode at a time, then when you put another row into edit mode, the row that is currently in edit mode is turned back into view mode.

 

All rows are editable (V9 and older style)

 

 

Grid rows are editable on demand

 

 

Row 1 of the Grid has been put into edit mode

 

Action Javascript

The Grid Component allows you you to add JavaScript code to your Grid. There are a large number of events for which you can define Javascript event handlers.

In many cases, you can use Action Javascript to help you write the Javascript. For example, if you put a button in the Grid (by selecting the Insert... hyperlink underneath the list of fields), you can use Action Javascript to define the code to open a new Grid that is linked to the current row, or print a Report.

The image below shows the Javascript editor to define the Javascript for the 'click' event on a button.

You can define the code using either Action Javascript, or 'Text mode' - which switches the editor to a text area where you can type in any code that you want.

If you switch to Text mode after you have already defined actions using Action Javascript, the code for the Action Javascript is shown in the editor. This is an excellent way of using the Genie to get started and then enhancing the code with your own code.

 

To add a new action using the Action Javascript editor, click the 'Add New Action' button and make your selection from the list of actions (shown below).

 

You can right click on an action in the Action Javascript editor and select commands. One of the available commands is 'View Javascript' which shows you the Javascript that was automatically generated for you. Depending on the action, the Javascript might be divided into several pieces - some that is inserted directly into the control (e.g. in the control's onclick attribute) and some which is inserted into functions.

The list of actions from which you can choose include:

 

Message box Display a Javascript alert box on the screen.
Open a Grid component Open a Grid component in a pop-up window, or in a DIV on the current page. If the Grid is running inside a Tabbed UI component, can also open the target Grid in a new pane in the Tabbed UI. The target Grid is typically filtered using data from the current record.
Open a Report, Label or Letter layout Display a report, label or letter layout as a PDF file using the Acrobat PDF reader. The report is displayed in either a pop-up window, or in a DIV on the current page. If the Grid is running inside a Tabbed UI component, can also open the target Report in a new pane in the Tabbed UI.
Open a web page in a pop-up window or a DIV Open a web page (including .a5w pages, static .html pages, or any other web page, e.g. www.google.com) in a modal, or modeless pop-up window, or in a DIV on the page. This action also opens 'Supercontrols' - automatic links to Google Maps, Google Search, MSN Maps, etc.
Inline-Javascript Allows you to enter some hand-coded Javascript code.
Ajax Callback Define a user-defined ajax callback. The callback can be handled by an Xbasic function that is defined in the Grid component, by a separate .a5w page, or by another page (.e.g. .php, .asp, .aspx, etc.) page.
City, State Lookup from Zip Code For a given zip code, lookup the city and state on the USPS web site and fill in the city and state in the current record.
Zip Code Lookup from Address For a given address, lookup the Zip code on the USPS web site and fill in the Zip code field in the current record.
Lookup and Fill-in Fields Lookup values in a table and fill-in fields in the current row from fields in the Lookup Table. See below for more details.
Set Page Content Set the content in one or more page elements (i.e. 'divs', 'spans', form fields, etc.) to values obtained from fields in a Lookup Table. See below for more detaisl.

 

Lookup and Fill-in Action

The 'Lookup and Fill-in Values' allows you to perform an Ajax callback to find a matching record in a Lookup Table and then fill-in fields in the record you are editing with data from the Lookup Table. Features of this action include:

Examples of where it might make sense to use this action include the OnClick event of a button, or the OnBlur event of an input control.

'Set Page Content' Action

This action allows you to set the content of parts of a page (e.g. 'div', 'span', 'iframe' and other elements) with content that comes from a database. This action makes an Ajax callback to the server to find a record that is 'linked' to the current record in the Grid, and then it sends back the appropriate Javascript response to the browser to set the content of the specified page elements.

For example, say that the .a5w page in which you have placed a Grid has a div with an id of 'content1'. Every time you click on a different row in the Grid, you want to make an Ajax callback to the server to find the record in a lookup table that is linked to the current row in the Grid, and then you want to set the data in the 'content1' div to the value of the 'HTMLNotes' field in the lookup table. The 'Set Page Content' action can be used for this.

The 'Set Page Content' action can actually be used to set any Javascript property of any element on a page to a value that is computed on the server using data from the lookup table. For example, it could be used to set the src property of an IFrame, or the src and title property of an Image, or the style property of a div, etc.

When you select this action, the following builder is displayed:

 

This allows you to define the lookup table, and how it is linked to the data in the current record.

Once you have defined the lookup table, you can click the smart field for the 'Definition' to define the rules for what content gets filled-in. This dialog looks like this:

You can define as many rules as you want.

 

To define a new rule, click the 'Add Action' button. This dialog allows you to add a new action.

If you use 'Advanced' mode in the above dialog, then you can write an arbitrarily complex Xbasic script to generate the Ajax response that is sent to the server.

 

 

User Defined Ajax Callbacks

You can define Javascript event handlers at many levels in the Grid component (e.g. at the control level, at the row level). Your Javascript event handlers can make Ajax callbacks. The callbacks can submit data from the current row in the Grid. If you have turned on the 'checkbox' column, then data from the checkbox column is also returned. The callbacks can be handled by an Xbasic function that is defined in the Grid component, or by a separate page (could be an .a5w page, a PHP page, .ASP page, or any other type of page).

To have your Javascript function make an Ajax callback, you use the '.ajaxCallback()' method of the Grid object.

The syntax for this method is:

 

Handling the callback with a function defined in the Grid component:

<GridObject>.ajaxCallback(part, rowNumber, XbasicFunctionName)

If you want to pass back some data in the callback, you can do so using this syntax:

<GridObject>.ajaxCallback(part, rowNumber, XbasicFunctionName,'',OtherData)

 

 

Handling the callback with a separate page:

<GridObject>.ajaxCallback(part, rowNumber, ActionName, URL, OtherData)

 

Where:

part 'g' - if you want to submit data from the current row in the Grid part, or 'd' - if you want to submit data from the currently open DetailView record
rowNumber If part is 'g', the row number whose data you want to submit. If part is 'd' then must be 1. In the case where part is 'g', and the rowNumber is set to 'all', data from all of the rows in the grid is submitted. If rowNumber is set to 'none', no data will be submitted.
XbasicFunction The name of the Xbasic function that will handle the callback. This function is defined in the 'Xbasic function declarations' section. IMPORTANT: The 4th parameter (URL) must NOT be specified.
ActionName Applies only if the URL parameter is specified. See definition of URL.
URL The URL of the page that will handle the callback. A variable called '_action' is passed to the URL. The value of _action is set to ActionName.
OtherData Name value pairs of any other data you want to submit as part of the callback.

 

For example, assume that you have placed a button in a Grid column. When the user clicks the button, you want to make an Ajax callback, passing back the data in the current Grid row. Here is the Javascript that you would define for the button's onClick event:

{grid.object}.ajaxCallback('g',{grid.rowNumber},'function1');  

 

When the Grid is rendered, the {grid.object} placeholder will get replaced with the actual Grid object name (based on the Alias assigned to the Grid at run-time) and {gird.rowNumber} will be replaced with the row number. So, for example, if the Grid alias was set to 'Grid1' then the Javascript in the button on row 1 would be:

GRID1_GridObj.ajaxCallback('g',1,'function1');

 

If you wanted the callback to be handled by a separate .a5w page (called 'callbackpage.a5w'), you could use this Javascript in the button's onClick event:

{grid.object}.ajaxCallback('g',{grid.rowNumber},'myActionName','callbackpage.a5w');  

 

If you wanted the callback to be handled by a PHP page on a totally different server:

{grid.object}.ajaxCallback('g',{grid.rowNumber},'myActionName','http://www.mydomain.com/callbackpage.php');  

 

Specifying the Callback Function

In the case where the callback is handled by a function that is defined as part of the Grid, you must use the following prototype for the function:

function callbackfunctionName as c (e as p)

 

end function

 

The 'e' argument contains all of the data that is submitted on the callback. To see what's in 'e', use the Firebug addin for Firefox and examine the contents of the 'Post' tab in the Firebug window after a callback has occurred.

In addition to the data that was submitted on the callback, 'e' also contains:

 

In addition to the above, the 'e' object also has some additional data that are computed on the server before the Xbasic callback function is called:

 

e._currentRowDataOld A 'dot' variable that contains the data in the fields in the row before any edits were made to them. For example, if the Grid contains fields, 'firstname', and 'lastname', then you can reference the data in these fields using e._curentRowDataOld.firstname, and e._currentRowDataOld.lastname.

 

If the Grid is not editable then this variable does not have any sub properties.

 

Note: If the rowNumber parameter is set to 'None' this variable will not contain any sub-properties.

e._currentRowDataNew A 'dot' variable that contains the current data (i.e. edited data) in the fields in the row. For example, if the Grid contains fields, 'firstname', and 'lastname', then you can reference the data in these fields using e._curentRowDataNew.firstname, and e._currentRowDataNew.lastname.

 

If the Grid is not editable then this variable does not have any sub properties.

 

Note: If the rowNumber parameter is set to 'None' this variable will not contain any sub-properties.

e._currentRowKeys An array that contains the values for the primary key fields for the current row. In the case of a .dbf table this is usually the record number.

 

For example, in the case of a SQL table which has a primary key of 'lastname' and 'firstname', e._currentRowKeys[1] will contain the value of the 'firstname' field in the current row and e._currentRowKeys[2] will contain the vaue of the 'lastname' field in the current row.

 

Note: If the handler for your Ajax callback is a URL (as opposed to an Xbasic function), then the 'e' object will not be available to your code.

 

 

The function must return the Javascript that you want to execute on the client. For example:

 

Assume that each row in a Grid has a Div. (You would make a column in the Grid into a freeform edit region to insert the div). The Divs have ids that use the {grid.rownumber} placeholder, which ensures that each div has a unique id. For example:

<div id="R{grid.rownumber}_CONTENT">

So, the div on row 1 would be:

<div id="R1_CONTENT">

 

Assume that your callback function is called setContent() and it sets the value of the div on the row. Assume also, that the callback function is invoked from a button or event in the Grid row.

In this case, the row number of the row from which the event was invoked will be in e._currentRow (which you could determine by examining the 'Post' tab in Firebug). So the Xbasic function would be:

 

function setContent as c (e as p)
    setContent = "$('R"+e._currentRow+"A').innerHTML = '"+rand_string(10)+"';"
end function

 

 

The 'e' object converts the property assignments to Javascript using the a5GridHelper_generateAutoAjaxResponse() function. If you want to write the Javascript yourself, you can use this function as a great starting point. For example:

 

 

e._set.lastname.value = "smith"
e._set.lastname.style = "color: red;"
e._set.lastname.className = "foo"
e._set.firstname.value = "edward"
e._set.firstname.style.color = "red"
e._set.firstname.style.fontSize = "20"
e._setElement.div1.value = "this is a div"
e._setElement.div1.style = "color: red; font-size: 20pt;"
e._setElement.div1.className = "foo"
e._setGridElement.div2.value = "this s a grid element"
e._setRow1.lastname.value = "smith"
e._setRow2.lastname.value = "smith"
e._setRow_1.firstname.style.color = "blue"
e._set.city.style.color = "red"
txt = a5GridHelper_generateAutoAjaxResponse(e,"G","3")
showvar(txt)
 

 

The a5GridHelper_generateAutoAjaxResponse() takes 3 arguments: the 'e' object, the Grid Part ('G', 'D' or 'S' - for Grid, Detail View or Search part) and a row number.
 

The popup window will show this Javascript:


{grid.object}._setValue('G','LASTNAME',3,'' + 'smith',true);
$ss('{grid.componentname}.V.R' + 3 + '.LASTNAME','color: red;');
$('{grid.componentname}.V.R' + 3 + '.LASTNAME').className = 'foo';
{grid.object}._setValue('G','FIRSTNAME',3,'' + 'edward',true);
$ss('{grid.componentname}.V.R' + 3 + '.FIRSTNAME',{color: 'red', fontSize: '20'});
$ss('{grid.componentname}.V.R' + 3 + '.CITY',{color: 'red'});

{grid.object}._setValue('G','LASTNAME',1,'' + 'smith',true);

{grid.object}._setValue('G','LASTNAME',2,'' + 'smith',true);

$ss('{grid.componentname}.V.R' + -1 + '.FIRSTNAME',{color: 'blue'});

$svs('{grid.componentname}.DIV2','thisi s a grid element');;

$svs('DIV1','this is a div');;
$ss('DIV1','color: red; font-size: 20pt;');
$('DIV1').className = 'foo';
 

 

 

How to Get The Primary Key Values for the Current Row

It is often necessary to get the Primary Key value(s) for the current row in your Xbasic callback function.

The primary key data is included in the postback variables. The primary key value(s) are stored in an array (because a primary key can be based on multiple columns in the case of SQL tables).

For example, if you did a callback on row 3 for a Grid that was based on a table that has a composite primary key (i.e. a primary key based on more than one column - say PartNumber and OrderNumber), the postback data will include an array called KEYS.R3

Here is how you can write Xbasic to read the data in this variable:

dim arr as p

arr = eval("e.KEYS.R" + e._currentRow)

 

Now that you have created a local variables called 'arr', you can read the primary key values:

arr[1] - contains the PartNumber

arr[2] - contains the OrderNumber

 

Alternatively, if your are using an Xbasic function to handle the callback, you can simply use the 'e._currentRowKeys' variable. E.g.

e._currentRowKeys[1] - contains the PartNumber

e._currentRowKeys[2] - contains the OrderNumber

 

Checkbox Values

If you have turned on the 'Checkbox' column, the data about which rows were checked is also submitted on the callback. For example, assume that you had checked 3 rows in the Grid. The following data will be submitted on the callback:

 

checkboxRows.countChecked = 3
checkboxRows.rows[] = 3
checkboxRows.rows[] = 4
checkboxRows.rows[] = 5
checkedRows.key1[] = 00000004
checkedRows.key2[] = 00000005
checkedRows.key3[] = 00000006
 

 

Using AEX Files

The Xbasic function that handles the callback can be contained in an .aex file. You must specify the name of the .aex file in the 'Xbasic .aex files' property.

Submitting Data when making a Callback on a Read-only Grid

If you use Action Javascript to write the Ajax call function for you, you will notice that the Genie has a prompt that allows you to specify if data from the current row should be submitted when the callback takes place. If the row is a read-only row however, then data from the current row will not be submitted (even though the checkbox to submit data has been checked). The primary key values for the current row will however be submitted.

If you need to data from the current row in order to execute your callback function, you can instruct Alpha Five to use the primary key values that were submitted to get data for the current row. Alpha Five will do a query to find the record with the specified primary key and it will populate variables with the same name (e.g. V.R1.LASTNAME) as if the variables had been submitted from the browser.

In order to enable this feature, you must include this name/value pair in the OtherData parameter:

_getData=true

 

Setting Grid Properties in your Callback Handler using the e._set Object

The function or URL that handles the Ajax callback typically will send some Javascript code back to the Browser. This Javascript code can set properties of the Grid (e.g. set the value of a field to 'Paid', or set the color of a field to red).

More correctly stated, the Ajax callback can return Javascript to set any DOM (Document Object Model) property in the Browser.

As an alternative to generating Javascript code in your callback handler to set Grid properties, you can set properties of the special e._set object in your event handler function. Alpha Five will then automatically generate the appropriate Javascript.

For example, assume that the current row in the Grid contains a field called 'OrderTotal' and 'ShippingCharges'. You want to make a callback to the server, submitting the current value of 'OrderTotal', then compute the 'ShippingCharges' on the server and in your Ajax response, you would like to set the value of the 'ShippingCharges' field to the value that you computed on the server.

Here is what your Xbasic function might look like:

function computeShipping as c (e as p)

    dim orderTotal as N

    'get data from the e._currentRowDataNew object and convert it to numeric.

    orderTotal = val(e._currentRowDataNew.orderTotal)

    dim shippingCharges as N

    'execute code to compute the shipping charges.

    'dim formattedShippingCharge as c

    'execute code to format the shipping charges with currency symbol, etc.

    dim ajaxResponse as c

    'The ajax response will call the Grid object's .setValue() method. e._currentRow is the row number of the row that was submitted.

    ajaxResponse = "{grid.object}.setValue('G','SHIPPINGCHARGES'," + e._currentRow + ",'" + js_escape(formattedShippingCharges) + "');"

    computeShipping = ajaxResponse

end function

 

Clearly, the Javascript response that this function computes is non-trivial. Here is how this function can be greatly simplified by using the e._set object:

function computeShipping as c (e as p)

    dim orderTotal as N

    'get data from the e._currentRowDataNew object and convert it to numeric.

    orderTotal = val(e._currentRowDataNew.orderTotal)

    dim shippingCharges as N

    'execute code to compute the shipping charges.

    'dim formattedShippingCharge as c

    'execute code to format the shipping charges with currency symbol, etc.

    e._set.shippingCharges.value = formattedShippingCharge

    'if the shipping charges are above 100, set the font color to red.

    if shippingCharges > 100 then

        e._set.shippingCharges.style.color = "red"

    end if

end function

 

Note that now the function does not return any Javascript (although of course it could if you wanted it to). After the callback function has executed, Alpha Five examines the e._set object and it automatically generates the appropriate Javascript to set the properties that you specified in the e._set object. This computed Javascript is automatically appended to the Javascript response computed by your callback function.

 

You can set the following properties in the e._set object:

e._set.fieldname.value Sets the value of a field in the current row of the Grid. E.g.

 

e._set.lastname.value = js_escape("O'Hara")

 

Note: The value that you set must be processed by the js_escape() function to encode special characters, or else you will get a Javascript error.

e._set.fieldname.style Sets the style of a field in the current row. Style is a comple CSS string. Any existing style that has been applied to the field will be overwritten. E.g.

 

e._set.style.lastname.style = "color: red; font-size: 12pt"

 

e._set.fieldname.style.styleAttribute Sets an individual style attribute of a field in the current row. The existing style is preserved and only the specified styleAttribute is overwritten. E.g.

 

e._set.style.lastname.fontSize = "20pt"

 

Note: The styleAttribute is case-sensitive.

 

Contrast setting individual styleAttributes, with the previous command that sets the entire style CSS value in a single command.

e._set.fieldame.className Sets the class name of a field in the current row.

 

Setting Properties of Fields on Rows other than the Current Row

You can also set properties of other rows in the Grid (other than the current row) by using the special 'e._setRow<rowNumber>' object.

Where <rowNumber> is the row number of the row. In the case of new record rows, use and underscore in front of the row number.

For example:

e._setRow3.lastname.value = "Smit"

e._setRow_1.lastname.style.color = "Green"

 

 

Setting 'Grid Element' Properties

In some cases, you will want your Ajax callback to set properties of an object that is not in the current Grid row. For example you might have an element (e.g. a DIV or SPAN in a free-form edit region above the Grid).

It recommended practice to include the Grid alias in the name of the Id that you give to these elements so that if you have a page that contains more than one Grid component on it, the Ids of these elements are unique.

For example, in a free-form section of a Grid, when you defined the element, you might have entered:

<div id="{grid.componentname}.DIV1"></div>

rather than simply:

<div id="DIV1"></div>

At run-time, the {grid.componentname} placeholder would be replaced by the Grid's unique alias. So, if the Grid alias was 'GRID1', the actual Id of the DIV would be 'GRID1.DIV1'.

Any element that is named using the '{grid.componentname}.name' convention is called a 'Grid Element' (as opposed to simply an 'Element').

You can set the .value, .style and .className properties of Grid elements in the same way that you set the properties of fields in the current row. The only difference is that you use the e._setGridElement object.

For example, say that you have a Grid element named '{grid.componentname}.DIV1' and you want to set its 'value' and 'style' ('value' in this case would actually be the innerHTML property). You would use this command:

e._setGridElement.DIV1.value = js_escape("This is the contents of the div")

e._setGridElement.DIV1.style.color = "red"

 

Setting 'Element' Properties

Al 'Element' is essentially the same as a 'Grid Element' except that it does not include the '{Grid.componentname}' placeholder in the Id. You can use the e._setElement object to set properties of 'Elements'.

For example, a free-form section of the Grid might have this element:

<div id="ELEMENT1"></div>

You could execute this command to set properties of this element:

e._setElement.ELEMENT1.value = js_escape("This is the contents of element1")

Linked Content Sections

Linked Content Sections allow you to display linked data in your Grid.

The linked content is displayed in a Tab or Accordion control if the Linked Content Section links more than one object. Linked Content Sections essentially duplicate the functionality of the Tabbed Grid Linker component and the Grid Linker component (from V9 and prior version). But because Linked Content Sections use Ajax, they don't have the performance penalty that Tabbed Grid Linkers and Grid Linkers have. You can place as many Linked Content Sections on your Grid as you want. For example, you might have a Customer Grid with a Linked Content Section below the Grid that displays an Orders Grid (showing orders for the selected Customer) and a Payments Grid (showing payments received from the selected Customer). These two Grids would be displayed in a Tab or Accordion control. Then, you might have another Grid (displayed, say, to the right of the Customer Grid) showing a list of all documents/letters/proposals, etc. that have been sent to the selected customer. NOTE: At present, you can only place Grids in Linked Content Sections. We will add .a5w pages and other web pages in the future.

The image below shows the Customer Grid with a Linked Content Section showing the Orders Grid. This Grid, in-turn, has its own Linked Content Section which shows the Order Details Grid.

How to Place Linked Content In the Grid

To place Lined Content into the Grid, check the 'Has linked Grids or other content' checkbox and then click on the smart field. The following dialog is displayed.

You can add add many Linked Content sections as you want.

 

Click the 'Add Linked Content Section' button and give the section any arbitrary name that you want.

 

Then, click the 'Define Linked Content' button to define the linked content.

 

After you have defined the linked content, you must then specify where on the Grid the linked content should appear. You do this by placing a special placeholder in one of the Grid's freeform edit regions.

To place the linked content, click the 'Edit Freeform Edit Region' button and select which freeform edit region you want to use.

Then, insert the placeholder into the freeform html.

 

Embedded Linked Grids

When you are designing a Grid (Grid part), the 'Insert...' menu now has a new command. In addition to the usual objects (such as Tabs, Containers, Frames, Images, Buttons, etc.), there is now a new object that you can insert into the Grid - 'Linked Grid(s)'. If you specify more than one Grid, the linked grids will display in a tab or accordion control. The linked Grids are linked to one or more fields in the current row.

The image below shows a Customer grid. The last cell in the Grid contains an embedded, linked Grid showing the orders for that customer.

The embedded Grids are rendered by making subsequent Ajax callbacks after the parent Grid has rendered. This means that the embedded Grids do not slow down the initial rendering of the parent Grid.

 

 

Highlight Row on Hover

Property name: 'Highlight row on hover' ('Properties' pane)

It is sometimes difficult to immediately find the position of the cursor on a grid. Selecting this property will cause the style of a row to change when the mouse hovers over the row. This helps identify the current row that will be selected with a mouse click or double-click.

The row where the cursor is positioned is highlighted

Record Per Page Selector in Record Navigation bar

Property name: 'Has 'Records Per Page' selector' ('Properties' pane)

The number of rows to show on the grid when it first displays is set in the grid properties. Adding the 'Records Per Page' selector allows the user to change the number of rows displayed after the grid opens on a page. The selector is shown at the bottom of the page and has a dropdown list with the values specified in the 'Records Per Page' selector choices. When the user selects a new value, the grid refreshes and show the number of rows selected. This option allows the grid to initially open with a limited number of rows to take less space on a page, and still allow the user to decide how many rows they wish to view.

The Records Per Page selector

 

Query by Example

Property name: Query-by-Example row' ('Properties' pane)

Previously, the only way to find specific records was to use a search section or 'quick search'.

Now there is a new method to search individual columns using a sophisticated 'query by example' process. A link is shown at the bottom of the grid to show or hide a query row. The initial display of the row can be shown or hidden. Clicking the link either shows or hides the Query-by-Example row. It has a textbox for each row to allow the user to enter some search text. The user then clicks on the icon to the right of the textbox and a list of possible search criteria opens. The user can clear all filters on all columns, remove the filter on the current column with 'No filter'., or select specific criteria for the current row. The query runs as soon as the criteria is clicked. Additional queries can be run on other rows to further filter the data.

Link to Show / Hide Query by example

Grid showing Query By Example row

Query by example search criteria

 

Grid filtered on 2 columns queried with 'Starts with..'

 

Detail View

Property name: 'Detail View window position' ('Detail View-> Properties' pane)

There are new options for where the Detail View is shown. It can be shown in page (the same as previously), in the grid, in a popup modal window, or in a popup modeless window. The modal popup window will gray out the underlying grid and nothing on the grid can be selected. The modeless popup allows selecting records on the grid with the popup open. The popup windows have a 'drag' capability to allow them to be moved around on the page.

The Detail View includes a toolbar that allows you to navigate from record to record. When in enter mode, has a 'Save and Enter' button (Ctrl-F9)

Detail views can now be defined for 'Form' and 'Stacked' layouts. (Previously Detail View was only available for 'Grid' layout)

Detail view on page

Detail View in modal popup window

Detail View in grid

Detail View on columnar grid with modeless popup window

Row Expander

Property name: 'Has row expander' ('Properties' pane)

The row expander is another method to show information related to a record on a row. A column is added with a 'plus' icon that can be selected to 'expand the row'. A minus icon will be shown after the row is expanded that can be selected to close the expanded row. There are 2 row expander types.

The 'LinkedGrids' option allows selecting one or more grid components that can be linked to the current record in the row. The linked grids can be shown in tabs, or an accordion control.

The 'CustomEvent' will cause the grid event 'OnExpandRow' to fire. This event sets a number of properties such as e.html and e.javascript. The contents of the expanded row will be set to e.html. If the e.javascript is not null, the javascript contained in this property will be executed. There are other optional properties available to allow a developer to create a custom display that can be linked to the current record.

Multiple records can have their row expanded, allowing the user to view additional information about multiple records.

If the 'Mode' property is set to 'Single', then only one row can be expanded at a time. If a row is expanded and you expand another row, the currently expanded row will be collapsed.

Selecting the row expander icon to open the expanded section

Expanded row with 2 grids in a tabbed control with the tabs on top.

CustomEvent selected using the example code in the 'OnExpandRow' event

Master Templates

Property name: 'Use a master layout template' ('Grid Properties' pane)

Using a template allows you to layout the different parts of the Grid in the component definition, rather than on the page. Several different template styles are available, such as tabs and accordions. The Detail View includes a toolbar that allows you to navigate from record to record. The text on the tabs or labels can be specified, and the initial pane to show can be specified.

 

Grid in a master template layout with a Tab Container with tabs on top

 

Detail view in a master template layout with a Tab Container with tabs on top

Collapsible Grid

Property name: 'Can collapse grid?' ('Grid Properties' pane)

A feature has been added allow a user to click a minus icon to 'collapse' a grid to hide it and just show a simple title bar. The title bar has a plus icon to reopen the grid. This is similar to an accordion control and requires the grid to be placed in a master template.

Collapsible grid expanded with a grid in an accordion master template

 

Title bar with grid collapsed

Lookups

Property name: 'Lookup' ('Fields->Field Properties' pane)

A lookup defined for a field now opens in an Ajax window instead of a popup window. This provides a number of improvements.

Lookup opened with dynamic filter on state

Checkbox select column

Property name: 'Has checkbox select column' ('grid Properties' pane)

Selecting this option adds a column with a checkbox for each row to select one of more records, with a select / deselect all option. This feature is meant to be used in conjunction with custom Ajax callbacks (described elsewhere in this document).

Checkbox select column with all selected

 

Row Edit Style - AllRows and RowOnDemand

Property name: 'Row edit style' ('Update Settings' pane)

A updateable grid can open with all rows in edit mode by selecting the 'AllRows' option. Selecting the 'RowOnDemand' option will open the grid in view mode. The row can be placed into edit mode either by clicking the 'Edit row' icon, or by double clicking on a field. If you double click on a field, initial focus will be on the field.

One edit row at a time

A related option is the 'One edit row at a time' property. If this is checked, it will allow only one row at a time to be in edit mode. Multiple rows can be placed in edit mode if this is not selected.

RowOnDemand with one edit row not selected. Two rows are in edit mode and a change has been made in the first row.

Lazy edits

Property name: 'Lazy edits' ('Update Settings' pane)

The option for 'Lazy edits' is only displayed if the row edit style is 'RowOnDemand'

If 'Lazy edit' is selected, the database will not be queried to get current data when you put a row into edit mode. This makes it quicker to switch to edit mode. If it is not selected, the row will be refreshed when placed in edit mode to get the current data.

Refresh data on row dirty

Property name: 'Refresh data on row dirty' ('Update Settings' pane)

This option only applies if the row edit style is 'AllRows'

When this option is selected and a user begins editing in a row, a callback is executed to get the current data.

Allow individual rows to be saved

Property name: 'Allow individual rows to be saved' ('Update Settings' pane)

This option is only shown if the row edit style is 'AllRows' and allows saving an individual record instead of submitting all rows after an edit.

When it is selected, a 'Row Status' column is displayed. This column shows icons that allow you to perform actions specific to the row, such as 'Save Row', or 'Undo changes in row'.

Row refresh method after Edits

Property name: 'Row refresh method after edits' ('Update Settings' pane)

Previously you had to commit all edited rows at once. This option allows setting how the data in the Grid should be refreshed after data is updated, deleted or inserted.

If you redirect to another page after a successful update, then you must turn off updates to individual rows.

Error style

Property name: 'Error style name' ('Properties' pane)

Previously errors where shown on their section on a page. Now they are shown in the Grid itself.

The error style property determines how the error messages are displayed.

New Records Edit Style

Property name: 'New records edit style' ('Update Settings' pane)

This has two options

Conditional formatting (at the row and column level)

Property name: 'Conditional Style' ('Grid->Fields->Field Properties' pane)

Previously, the only way to change the look of a field based on a condition was to use a custom control. This option allows changing the CSS style class of a control based on a conditional expression. The style can be an inline style or a CSS style class name. The CSS styles can be loaded from an external CSS file.

Local CSS

Property name: 'Local CSS definitions' ('Properties' pane)

This provides the ability to define additional CSS classes that can be used in the Grid.

CSS linked files

Property name: 'CSS Linked files' ('Properties' pane)

This provides the ability to specify additional CSS files that should be linked on the page.

Additional Grid Styles

Property name: 'Additional Grid styles' ('Properties' pane)

This provides the ability to list additional Alpha Five styles to be included on the page. A comma delimited list of style names can be added.

Layout Controls

Property name: 'Insert Layout Command...' (Grid->Fields' pane)

The layout commands for 'stacked' layouts like columnar have a number of new features.

Modern style tabs, modern frame with collapse/expand and city state zip fields in a container.

Unbound controls (these are in the Layout Controls section)

There are a number of 'unbound' controls available in the Layout Controls section.

Image based on a value in the grid and unbound text

Keyboard shortcuts

The Ajax grid includes some built-in keyboard shortcuts

Link control

You can now specify that the link address type is 'Javascript'. Any Javascript function call or command can be added to the 'onclick' event. The Javascript will be executed when the link is clicked.

JavaScript link with onclick event opening an 'alert' box

Javascript

Property name: 'JavaScript' ('Grid Properties->Javascript - Row Events' and 'Grid Fields->Field properties->Javascript' panes)

 

Define Javascript event handlers at the control level and the row level. The Javascript can make an arbitrary ajax callback to validate data, obtain new data, populate a select box, etc. This provides the capability to create cascading lookups.

Common uses:

Javascript events supported for fields

Javascript Function Declarations

Property name: 'JavaScript function declarations' ('Grid Properties' pane)

This property allows allow you to define Javascript functions that can be called from Javascript events. These functions will be added to the page header and must contain valid Javascript syntax.

 

An example JavaScript function definition.

 

Javascript Linked Files

Property name: 'Javascript Linked files' ('Grid Properties' pane)

Additional Javascript files can be linked to the page. The files can contain JavaScript functions used by event handlers on fields or rows or other client side actions.

Xbasic Function Declarations

Property name: 'Xbasic function declarations' ('Grid Properties' pane)

Allow you to define Xbasic functions that can be called from Xbasic event handlers. These functions are called by server side actions defined in the grid 'Events'.

Field level Xbasic data validation

Property name: 'Validation Xbasic' ('Grid Fields->Field Properties' pane)

You can now write your own Xbasic code to validate fields. This validation code runs on the server when a record is submitted.

AlphaDAO Grids - Updateable - Write Conflict Checking

If you have a Grid based on an AlphaDAO data source, and you have 'Check for write conflicts' turned on, you can turn off write conflict checking at the individual field level. This was added because certain field types (e.g. the 'ntext' type in SQL Server) cannot be used in a WHERE clause with an = operator - which is what is required in order to use a field in a write conflict check.

Now, when you select certain fields in the Grid, if their data type precludes them from being used in a WHERE clause with an = operator, they are automatically excluded from the list of fields for which write conflicts will be checked.

New Record Rows Position

Property name 'New record rows position'  ('Update Settings' pane)

You can now specify if the empty rows, used to add new records to an editable grid, should be positioned above, or below the existing records. Previously, the new record rows were always shown below the existing records.

Grid showing new record rows positioned above existing rows.

 

 

Opening a Detail View

In previous versions, the Detail View was opened by clicking on a hyperlink field in the Grid. Now, you can set the method for opening the Detail View. The options are:

If you choose method 2 or 3, there is no need to set the style of one of the Grid columns to a hyperlink. If you choose the first method and you do not define the hyperlink field, Alpha Five will automatically set the first non-hidden field to be the hyperlink (previously it gave an error and forced you to choose a field) .

Detail View Toolbar - Customize Icons and Bubble Help

 You can customize the icons and bubble help that are displayed in the Detail View toolbar. To bring up the customization dialog, click the smart field in the 'Customize the toolbar icons' property. For some of the icons, you can specify the disabled icon as well.

 

Javascript Dialogs - Customization

 You can customize the messages and icons used in the the Javascript dialogs. For example, the Delete Record confirmation dialog shown below has been customized:

To customize the Javascript dialogs, click the smart field for the 'Javascript windows' prompt in the 'Customization' section in the Grid Properties pane.

 

Date Formats - Internationalization Issues

You can now more easily deal with situations where the date format that a user wants to use is different than Regional Settings date format for your server. For example, assume that your server is on a machine in the US where the date format is 'MM/dd/yy'. Your users in the US who want to see and enter dates using the 'MM/dd/yy' format. However, your users in the rest of the world want to use the 'dd/MM/yy' format to display and enter date values.

This is now easily accomplished.

1. There is a new property called 'Date Format' in the 'Miscellaneous' section on the 'Grid Properties' pane. The default for this property is 'MM/dd/yy', but you can select a different value. You can override this property at runtime in Override Settings by setting the clientSideDateFormat property. For example

tmpl.clientSideDateFormat = "dd/MM/yy"

You can also override this property at runtime by setting the special session.__protected__clientSideDateFormat variable. This is the more likely scenario as you can set this variable for each user when they log into your application.

2. When you configure the date picker for date and time fields, you will notice that the default value for the 'Format' property has been changed from "mm/dd/yy" to "<Default>". This indicates that the date picker format will be inherited from the global date format (set by the clientSideDateFormat property discussed above).

3. When you select a date or time field in the Grid or Detail View part, a default format is defined. The format is:

time("{grid.clientSideDateFormat}",<value>)

 

{grid.clientSideDateFormat} is a special placeholder that gets replaced at runtime with the value of the Grid's clientSideDateFormat property.

Assume that User1 logs on from New York. When User1 logs on, you set the special session.__protected__clientSideDateFormat variable to "MM/dd/yy". All dates in the Grid will appear in the MM/dd/yy format. When the user makes a selection from the Date Picker, the date will be entered in the MM/dd/yy format.

Assume that User2 logs on from London. When User2 logs on, you set the special session.__protected__clientSideDateFormat variable to "dd/MM/yy". All dates in the Grid will appear in the dd/MM/yy format. When the user makes a selection from the Date Picker, the date will be entered in the dd/MM/yy format.

When User1 or User2 submits data to the server, the date values are automatically converted to the format required by the Regional Settings of the machine on which the server is running.

This will all happen seamlessly, without requiring you to make any modifications to your Grid component.

As a result of this change, the old 'Date format on server does not match client' property in the Grid has been removed.

 

Note: If you are outside the US, you will probably want to change the default value for the Date Format to 'dd/MM/yy' for each new Grid that you build.

 

Client-Side Properties

You can now define several 'client-side' properties for a Grid. These are:

Calculated Fields

Client-side calculated fields are computed using Javascript. The calculation is performed as soon as any of the operands in the calculated expression are changed.

Warning: If you have defined a formatting expression for a field that also has a client-side calculation, the formatting expression will be overwritten by the result of the client-side calculation. You must therefore put the the formatting logic into your client-side calculated expression.

Show/hide Fields

Any field, or Container can by dynamically shown/hidden. If you want to show/hide multiple fields at once, wrap the fields in a Container control (Form layout mode) and set the show/hide expression for the container.

Enable Expression

You can enable/disable an input control.

Conditional Styles

You can define conditional styles. The conditions are evaluated in the Browser using Javascript. This is an extremely powerful feature as it allows you to dynamically style controls without having to make Ajax callbacks. For example, if a user types in a value into a Quantity field that is too large, you can immediately display the field in red. Contrast 'client-side' conditional styles with 'server-side' conditional styles (also supported). With 'server-side' conditional styles, the conditions are expressed using Xbasic expressions and the conditions are evaluated on the server.

Client-side Formatting

You can define masks for character fields. For example, a US Phone number: (    )     -

For numeric fields, you can define number formats.

 

User Defined Watch Events

The client-side Calculated fields, Show/hide fields, Enable expressions and Conditional styles are all implemented using 'watch' events. For example, if you examine the source in the Browser for a page the defines a calculated field for 'extendedtotal' using the expression 'round(price * quantity,2)', you will see the following Watch event has been defined automatically:

 

GRID1_GridObj._gridRowWatches['CALC_G_EXTENSION'] = {
watch: ['PRICE','QUANTITY'],
onChange: function(data) {
var PRICE = $u.s.toNum($gvs('GRID1.V.R' + data.rowNumber + '.PRICE'));
var QUANTITY = $u.s.toNum($gvs('GRID1.V.R' + data.rowNumber + '.QUANTITY'));
GRID1_GridObj._setValue('G','EXTENSION',data.rowNumber,'' + $u.n.round((PRICE*QUANTITY),2));
}
}

The above Javascript adds a new watch event (called 'CALC_G_EXTENSION'). It watches the PRICE and QUANTITY fields. The onChange event gets passed an object called 'data' that has the rowNumber of the row in which the change takes place. It then gets to local variables, PRICE and QUANTITY which are the values in the corresponding controls in the Grid part. Finally, it uses the ._setValue() method to set the value of the EXTENSION field to the result of the expression.

You can define your own custom Watch events if the automatically generated watch events (defined when you create a client-side calculated field, etc.) do not do exactly what you want. In most cases you should not need to use custom Watch events, but for power users, its nice to have this capability. You can define Custom Watch events for the Search part, Grid part and Detail View part. Go to the 'Javascript- Other' section in the appropriate properties page and click the builder for 'Watch events'.

You can create as many watch events as you want. For each watch event, you specify a unique (arbitrary) name to identify the event, the names of the fields you want to watch and the javascript to execute when the value in any of the watched fields is changed.

When you define the watch event, you can (optionally) use special 'helper' functions to simplify your javascript. For example the helper function *$('quantity') expands to:

$gvs('GRID1.V.R' + data.rowNumber + '.QUANTITY').

The above example Watch event could be written using 'helper' functions as follows:

GRID1_GridObj._gridRowWatches['CALC_G_EXTENSION'] = {
        watch: ['PRICE','QUANTITY'],

        onChange: function(data) {

        var PRICE = *gvn('PRICE');
        var QUANTITY = *gvn('QUANTITY');
        *svs('Extension',$u.n.round((PRICE*QUANTITY),2));

        }

}

 

(Note: 'Helper' functions can only be used when you create custom watch events. The 'helper' functions all start with * and are documented in the Watch Event builder.)

Example - How to Dynamically Set a Field Label

The generic Javascript Watch events make it very easy to dynamically set a control's label at run-time.

For example, say that your Grid has a field called 'COUNTRY'. If the value in COUNTRY is 'USA', you want to set the label on the ZIP field to 'Zip code', otherwise you want to set it to 'Postal Code'.

NOTE: This example assumes that the Grid is set to display data in Form mode.

 

Here is how you would do it:

  1. Create a new Javascript Watch event (Properties pane, Javascript section, Watch event) and give it a name (any name will do).
  2. Set the type to 'Other'.
  3. Specify that the field you want to watch is COMPANY (this means that whenever the value in the COMPANY field changes, the Javascript that sets the label value will execute).
  4. Enter this code for the Watch event:

 

var COMPANY = *gv('COMPANY');
var labelValue = 'Zip code';
if( COMPANY != 'USA') labelValue = 'Postal Code';
$('{grid.componentname}.LBL.R' + data.rowNumber + '.'+'ZIP'+'').innerHTML = labelValue;

 

 

 

 

DBF Table Field Rules

If you have built Grids on .dbf files in V9 and earlier, a major deficiency has been that the Grid did not honor most Field Rules. That meant that you had to code validation rules manually to mimic the rules you had defined in Field Rules.

Now, rules defined in Field Rules are automatically enforced in the Grid. You do not need to manually add any validation logic to your Grid.

Support for Multiple Languages

You can tag any text in the Grid definition so that it becomes replaceable, depending on the selected language.

To tag text, you enclose it in <a5:r> and </a5:r> tags. For example, you might tag the heading for the Lastname column as:

<a5:r>Lastname</a5:r>

To open the Language Definition dialog see the 'Language Definitions' property in the 'Miscellaneous' section of the 'Properties' pane.

You can define as many language definitions as you want. 

Each language definition is a set of name=value pairs (values must not include line breaks). For example, assume you tagged the following strings in your Grid definition:

<a5:r>First Name</a5:r>

<a5:r>Last Name</a5:r>

<a5:r>City</a5:r>

Your language definition for the <Default> language might be:

First Name=First Name

Last Name=Last Name

City=City

The language definition for French might be:

First Name=Prénom

Last Name=Nom de Famille

City=Ville


Using Expressions in the Replacement Strings

You can use expressions in the replacement strings by prefixing the expression with 'expn;'. For example, the language definition below uses expression that reference a session variable and a variables that might have been defined in the OnGridInitialize event.

First Name=Prénom

Last Name=Nom de Famille

City=Ville

Company=expn:session.companyName

WelcomeMessage=expn:rtc._myvariables.welcomeMessage


Setting the Active Language

If you don't specify an active language, the <Default> language is assumed. To set the active language, you set the 'ActiveLanguage' property. You can set this property in the 'Override Settings' section in the .A5W page that loads the Grid, or in the Grid component's OnGridInitialize event.

For example, to set the ActiveLanguage in the OnGridInitialize event:

e.tmpl.ActiveLanguage = "French"

 

A second way to set the active language is by using the special protected session variable, session.__protected__activeLanguage. For example:

session.__protected__activeLanguage = "French"

If you set both the session.__protected__activeLanguage and the 'ActiveLanguage' property in Override Settings or OnGridInitialize, the session.__protected__activeLanguage property is honored.

Using External Language Definitions

You can pass in an external language definition to the Grid at run-time by setting the 'languageDefinition' property in Override Settings or the OnGridInitialize event. If you pass in an external language definition which defines a replacement value that is also defined in the language definition that is defined in the Grid itself, the external language definition will be used.

The example below shows how to define an external language definition. Note that 'Surname' and 'Postal Code' are literal values and =date() is an Xbasic expression.

tmpl.languageDefinition = <<%txt%

<a5:r>lastname</a5:r>="Surname"

<a5:r>zip</a5:r>="Postal Code"

<a5:r>date</a5:r>=date()

%txt%

 

 

Using AEX Files in your Grids

If you have defined a lot of Xbasic event handlers in your Grid components, it might make sense to move the bulk of the Xbasic code outside the Grid component and into global Functions (defined in the Code tab of the main Control Panel).

You can then compile your functions into an .AEX file and add a reference in your Grid component to the .AEX files that it needs to link in.

Note: To create an .AEX file with your Global Functions, simply right click on white space in the Code tab of the main Control Panel).

Note: Functions that are defined in .AEX file can be used in event handlers in the Grid. They cannot be used in calculated field definitions. (Calculated fields are only available for Grids based on .dbf. For Grids based on SQL, the 'calculated' fields are defined in the SQL Select statement).

 

Customize the Grid Toolbar

The Grid has always allowed you to customize the layout of the record navigator, but now, you can customize the entire Grid Toolbar and you can add your own custom buttons to perform actions that you define.

 

For example, this image shows how we have added 3 custom buttons to the toolbar.

 

 

To customize the toolbar, click the smart field for the 'Customize Grid toolbar template' property.

 

 

The Genie lets you customize the toolbar for when the Grid is read-only and when it is editable. You can make modifications to the HTML template. The placeholders in curly brackets are used for the different parts of the toolbar.

To get started, click the hyperlink to insert the default template.

 

 

Live Preview using any Installed Browser

When doing a Live Preview from the Grid, Page Layout, and Tabbed UI builder, you can use any installed browser. You are not limited to your default browser.


 

Dropdown Controls - Group Headings

You can now insert group headings in the data displayed in a Dropdown control. For example:

The above list was entered into the choices for the Dropdown control as follows:

[[[General Motors]]]
Camaro
Cadilac
GMC
[[[Ford]]]
Mustang
Lincoln
Focus
[[[BMW]]]
3 Series
5 Series
7 Series

 

 

Freeform Edit Regions

The editor for freeform regions has been changed slightly. Now, you can insert placeholders for the controls in your grid (e.g. {lastname}) or for the data that is in the control (e.g. {data.lastname}).

If you have used a freeform edit region in a Grid created in V9 or earlier, you might need to change some of your placeholders to use the 'data.' prefix.

The reason is as follows:

In V10, a label control is now automatically wrapped in a span tag. In V9 and earlier, a label control was not wrapped in a span, and so the {lastname} placeholder, for example, would have been replaced with 'Smith'. But in V10, this placeholder will be replaced with '<span>Smith</span>

If your component was not expecting the <span> to be in the replacement value, it might break your component. Changing the placeholder to use the 'data.' prefix will get you back to the V9 behavior.

In the example shown below, if the {lastname} placeholder had been used, the image name would not have resolved correctly.

 

Server-side System Events

The number of server-side system events that the Grid exposes has been substantially expanded.

The full list of server-side system events is shown below:

 

Customizing the Search Part Behavior

 

The new OnSearchPartFilterCompute function allows you to create a customized Search Part where you (and not Alpha Five) are responsible for converting the data submitted by the Search Part into a search filter.

This event allows you to modify the search part filter before it is executed. You can take the data submitted when the user clicks the Search Button on the Search Part and compute your own filter expression, rather than allowing Alpha Five to compute the grid filter.

The 'e' object that is passed into the event handler includes these properties:

e.rtc.Filter_SearchPart  -- filter computed from submitted data in the Search Part
e.rtc.Parameters_SearchPart --  parameter values for arguments in the filter.
e.SearchDataSubmitted -- Search data submitted
 

You can modify this. So, for example, in the event handler you might execute this code:

 

e.rtc.filter_searchPart = "lastname = \"smith\""

 

Now, when search is executed, it will search for records with lastname = "smith",  regardless of what the user entered into the Search Part.

 

This feature is often used in conjunction with putting variables into the Search Part form.

 

To put a variable into the Search Part, set one of the search fields to be a 'freeform edit region' and then enter HTML similar to this (this example if for a variable called 'myvar1'):

 

<input id="{grid.componentname}.S.MYVAR1" size="40" maxlength="200" class="GlassOliveInput" type="text" name="S.MYVAR1" value="" />

 

In your event handler, you can refer to this value in Myvar1 as

e.SearchDataSubmitted.myvar1

 

Client-side System Events

The Grid Object exposes a very rich system of client-side events that you can use to customize the Grid behavior. Event handlers for client-side system events are coded using Javascript.

Below is a list of client-side events that are exposed to the developer:

In order to define a client-side event expand the 'Javascript - System Events' property and then click on the smart field.

 

 

The Client-side Grid System Events dialog is opened. It shows all of the possible events and gives a short description of each event. If the event makes any data available to the executing Javascript code, the 'Parameters' section shows the names of the parameters.

You can use the 'Filter' box to filter the list of events to help you find the event you are looking for. You can also use the 'Defined events only' checkbox to quickly find the events for which you have defined code.

 

 

Inserting Placeholders and Grid Methods

When you write the Javascript event handlers, you might want to use certain placeholders in your Javascript. These placeholders get replaced by actual values when the Grid is rendered.

For example, the {Grid.componentName} placeholder gets replaced with the actual Grid alias at run-time.

To insert a placeholder in your code, click the 'Insert placeholder...' hyperlink.

You Javascript code can call any of the methods that the Grid object exposes. To see a list of the methods, click the 'Insert Grid method...' placeholder.

 

 

Example of How to Use Client-Side Events

Say you wanted to put up a dialog that said 'Searching. Please wait..' while your Grid component was performing a search. As soon as the search completed, you want to remove the message.

To do this you would add code to the 'canSearchSubmit' event to show the message.

 

A5.msgBox.show('Searching...','<div style=\'padding: 20px;\'>Please wait while we search for the records.</div>','none',function() {});

 

Then in the 'afterSearchSubmit' event, you would clear the message.

 

A5.msgBox.hide();

 

 

Keyboard shortcuts

The Grid component now implements many of the same keyboard shortcuts used in Alpha Five desktop forms. These are:

 

Up Move focus to the previous row in the Grid part
Down Move focus to the next row in the Grid part
F9 Save the current record
Shift+F9 Save all of the records (in a Grid that allows multiple records to be edited at once)
Ctrl+F9 In the Detail View - save the current record and start entering a new record.
Enter Puts the field with focus into edit mode
Page Up Moves to the previous page of records
Page Down Moves to the next page of records
Ctrl+D Delete current record
F2 Open the lookup window for the current field.
Esc Abandon edits made to the current field.

 

 

Override Settings in A5W Page

The way in which an .a5w page that runs components is constructed has been changed in V10.

 

In V9, if you examine an .a5w page after you have inserted a component into the page, you will see an Xbasic code block that looks similar to this

 

with tmpl

    componentname = "GRID1"

end with

 

The Xbasic between the opening 'with tmpl' and the closing 'end with' could be used to override any of the Grid settings. So for example, if you wanted to change the Grid style to a value that was set by a session variable called session.style, you would have:

with tmpl

    componentname = "GRID1"

    style_name = session.style

end with

 

In V10, when you place a component on a page, the Xbasic code block in the .a5w page where you override settings is slightly different. It now looks like this:

 

tmpl.override_settings = <<%override_settings%

    componentname = "GRID1"

    style_name = session.style

%override_settings%

a5w_resolveVariablesInOverrideSettings(tmpl,session,local_variables())

 

 

The a5w_resolveVariablesInOverrideSettings() function resolves page and session variables in the override_settings string. So, after this function has been executed, the tmpl.override_settings property will contain this value (assuming that session.style has a value of 'Airport':

tmpl.override_settings = <<%override_settings%

    componentname = "GRID1"

    style_name = "Airport"

%override_settings%

 

 

When you publish an existing .a5w page (created in V9), the Xbasic in the .a5w code is automatically converted to the new V10 pattern.

Why Was it Necessary to Make this Change?

The reason that is was necessary to change the code pattern is that with the code pattern used in V9 and earlier, there is way to know exactly which properties where changed in the override settings section of the code. This was not a problem in V9 and earlier as there was no need to know which properties had been overridden.

However, in an Ajax Grid, it is essential that we know which properties have been overridden so that this information can be stored in a hidden field in the Grid. This is  necessary because after the Grid has been displayed initially, all further callbacks are not handled by the original .a5w page (that contains the override settings code), but are handled by a special page called __a5RunGrid.a5w (which is published automatically every time you publish any component).

Since the Ajax callbacks are processed using __a5RunGrid.a5w, (which is a generic page with no override settings code in it), the override settings are read from the hidden field in the Grid.

 

Referencing Local Variables in the Override Settings String

If you want to refer to local variables in the override_settings string, you must prefix the local variable with 'pageVar' and you must put the local variable in the special 'pageVar' variable frame.

For example:

dim rows as n

rows = 23

dim pageVars as p

pageVars.rows = rows

tmpl.override_settings = <<%override_settings%

    componentname = "GRID1"

    style_name = session.style

    rows = pageVars.rows

%override_settings%

a5w_resolveVariablesInOverrideSettings(tmpl,session,local_variables())

 

 

Naming Conventions for Fields/Objects Used In Ajax Grid

In an Ajax Grid, there is a precise naming convention used for form fields.

The ID of a field object in the Grid part is:

    {Grid.ComponentName}.V.R{Grid.RowNumber}.FIELDNAME

 

Examples:

GRID1.V.R3.LASTNAME

MYGRID.V.R-2.FIRSTNAME

 

 

The ID of a field object in the Detail View part is:

    {Grid.ComponentName}.D.V.R{Grid.RowNumber}.FIELDNAME

 

Examples:

GRID1.D.V.R1.LASTNAME

MYGRID.D.V.R-1.FIRSTNAME

 

 

 

The Name of a field object for both Grid part and Detail View part is the same. (Since you can't have an editable Grid part and an editable Detail View part in a Grid, there is no need to use different control names for fields in the Grid and Detail View part).

The Name of a field in the Grid Part and Detail View part is:

V.R{Grid.RowNumber}.FIELDNAME

 

Examples:

V.R3.LASTNAME

V.R-2.FIRSTNAME

 

Where:

{Grid.componentname} is the alias of the Grid component. The alias is set in the override settings sections in the .a5w page that runs the Grid. Every component that is placed on an .a5w page has to have a unique alias. The alias in the object name is always uppercase.

{Grid.RowNumber} is the row number in the Grid. New record rows have negative row number. E.g. the 2nd new record row has a row number of -2. In the case of a Detail View field, existing rows always have a row  number of 1 and new record rows have a row number of -1.

FIELDNAME is the fieldname of the field. In the case of SQL databases, it is possible for fieldnames to include spaces and other special characters. FIELDNAME replaces spaces and special characters with an underscore. E.g. 'LAST NAME' becomes 'LAST_NAME'.

 

Variable Names

When data is submitted from the server for a new record, the minus sign in the field name is converted to an underscore in the variable name that is created by the Application Server. For example, say that data is submitted from the 2nd new row in a Grid. If you were to examine the list of variables that Firebug reported were submitted to the server, you would see names like these:

 

V.R-2.LASTNAME

The corresponding variable created by the Application Server (in Request.Variables) is:

V.R_2.LASTNAME

 

CurrentGridFilter() and CurrentGridOrder() Functions  

When you define Action Javascript to open a Grid or print a Report, you are prompted for a filter and order expression to apply to the target Grid or Report. If you want the target Grid or Report to inherit the filter and order from the parent Grid, you can use CurrentGridFilter() in in the filter expression. You can actually combine currentGridFilter() with additional filter criteria.

Example

 

'For a SQL Grid

currentGridFilter() and hasShipped = false  

 

'For a .dbf Grid

currentGridFilter() .and. hasShipped  = .f.

 

The currentGridOrder() expression cannot be combined with any values.

 

'Working Preview' Pane in the Grid Builder

Both the 'Live Preview' and 'Working Preview' let you test how your Grid component works. But unlike the 'Live Preview', the 'Working Preview' does not use the Application Server, or even require that the Application Server be running. The benefit of this is slightly better performance because the overhead of the Application Server is eliminated.

When you go to the 'Live Preview' pane, you are essentially viewing a live web page in Internet Explorer. When you go to the 'Working Preview' pane, Internet Explorer is talking to Alpha Five directly using a special protocol that bypasses the 'http' protocol used when you are running in a browser.

Limitations of Working Preview

If your Grid contains Javascript events that open Alpha Five reports, or other .a5w pages in pop-up windows, or in DIVs on the Grid, these actions will not work in the Working Preview.

Debugging Server-side Event Handlers

A significant benefit of a Working Preview is that is allows you to easily debug your Xbasic event handlers. Because the Working Preview runs in the foreground thread, you can include debug(1) commands in your Xbasic event handlers to trace into the execution of your scripts.

Turning the Working Preview Pane Off/On

You can control whether the Working Preview pane is shown in the Grid Builder by selecting the Options, Preferences menu.

 

Grids with Javascript Function Declarations and Custom CSS Definitions

When you define a Grid component, you can define Javascript functions and as part of the Grid definition. You can also define custom CSS as part of the Grid. You can also define linked Javascript and CSS files.

For example, you might define the following (trivial) Javascript function in the Grid's 'Javascript function declarations' section:

function sayHello() {

alert('Hello');

}

You might then define a button in the Grid and set the Button's onClick event to:

sayHello();

 

When you run this Grid and click the button, you get the pop-up message box, as you would expect.

However, if you were to run this Grid in the following scenarios, clicking on the button would not work and you would get a Javascript error:

The reason that the Javascript fails is that it needs to be declared in the .a5w page that loads the 'parent' component. So, for example, in the case of the TabbedUI component, the function 'sayHello' needs to be be defined in the TabbedUI component. But this would mean that you have to duplicate the definition of the sayHello function. You need to define it in the Grid component itself for those situations where the Grid is run by itself. And then you need to define it in the TabbedUI component for those situations where the Grid is run in the TabbedUI component. This is clearly inefficient.

To get around this problem, the TabbedUI, PageLayout and Grid components all have property called 'Linked Resources' that allow you to specify that names of Grid components that contain Javascript and CSS definitions that you want to automatically include when the component is rendered.

 

 

 

 

 

Grid Component - 'How To' Topics

This section has miscellaneous topics describing how to perform certain advanced actions with the Grid.

How to Base a Grid on a Stored Procedure

The Grid component does not allow you to base a Grid on a stored procedure. You must specify a SQL Select statement. You can however work around this limitation to a limited degree if your Grid is readonly.

  1. Create a passive link table that is based on the stored procedure.
  2. Create a grid using the native .dbf table (i.e. the passive link table)
  3. In the Grid onGridInitialize event add code to refresh the passive link table.

 

dim tableName as c

tableName = "[PathAlias.ADB_Path]\pir_report.dbf"

pr =a5_RefreshPassiveLinkTable(tableName,.f.,.f.)

 

 

How to Define Dynamic Content for a Tab/Accordion Control Pane

Advanced uses might want to use the Tab and Accordion control's onDynamicLoad property to define a Javascript event that will fire when the particular tab/accordion pane gets focus for the first time. This allows you to load dynamic content into the tab/accordion pane only when the pane is visited. If the pane is never visited, then you do not waste time and server resources computing content that will not be seen.

As the image below shows, the third pane (labeled 'DynamicLoad') does not have any controls in it. When the user visits the tab pane, the onDynamicLoad function will fire and it will be set the tab pane content.

 

 

This example shows how you can use the onDynamicLoad event for a tab pane to load a Grid component into the tab pane (the Javascript code shown here was copied from an Action Javascript that opened a Grid).

In the example, the target grid is linked on the 'bill_state_region' field using the value from the 'BILL_STATE_REGION' field in the Detail View.

As you can see in the line highlighted in red, the linking value is read (using the _getValue() javascript function) from the Detail View (1st argument of _GetValue())

 

Code for the onDynamicLoad Function

var go = new Object();
go.gridDiv = 'dv1';
go.gridName = 'Customer';
go.alias = '{Grid.componentname}_Cust_ybvr';
go.submitCurrentFieldValues = true;
go.sourceGridPart = 'D';
go.sourceGridRowNumber = '1';
go.workingMessage = '<img src=\'CSS/A5System/images/wait.gif\' />Working...';
go.userFilter = '';
go.baseFilter = '';
go.arguments = '';
go.linkDefinition = 'Bill_state_region(C:[[[data.Bill_state_region]]])';
go.placeHolderValues = 'Bill_state_region =' +{Grid.object}._getValue('D','BILL_STATE_REGION');

go.userOrder = '';
go.overrideSettings = 'Style_name = `{Grid.style}`';
go.a5_default_path = '{grid.defaultPath}';

go.flagTimer = 'F';
go.flagQueryEcho = 'F';
go.flagDebugMode = 'F';

{grid.Object}.openChildGrid(go);

 

If you want to reset the pane so that it is automatically refreshed when the user visits that pane again, you can execute this javascript:

 

$('elementId').innerHTML = '';
window['tabObject'].reset();

 

Where elementId is the Id of the Div in which the pane content is rendered. (Use Firebug in Firefox to examine the HTML to see what the elementId is.

And tabObject is the name of the tab object in which the Pane with the OnDynamicContent function is displayed. Again, use Firebug to examine the code to determine the object name. An example tabObject name is:

GRID1_DVTAB_1R_1Obj

Where 'GRID1' is the Grid Alias, 'R_1' is row 1, and 'DVTAB_1' is the first tab object in the Detail View.

 

 

How to Create an Arbitrary Window and Put Content in It

This topic describes how you can write Javascript to open an arbitrary window on the page and put content into the window.

For example, the following Javascript will open a window:

currWindowObject = A5.PageWindows.createWindow('myWindowId','modeless');
$(currWindowObject.getWindowId('body')).innerHTML = 'this is my window contents';
currWindowObject.show();

 

In this example 'currWindowObject' is an arbitrarily named window object,  'myWindowId' is the window name and 'modeless' is the window style. The options for the window style are:

If you call the command multiple times with the same window name, the second and subsequent calls return a pointer to the previously created window.

This means that internally, we are not creating a lot of windows - just one window that gets constantly reused.

It does mean however, that once 'myWindowId' has been created initially, you can't change its type or other property on a subsequent .createWindow() call.

 

To close the window you execute this Javascript:

 

currWindowObject.hide();

 

Where 'currWindowObject' matches the name of the window object in the .createWindow() command above.

 

Special Window Styles

The window styles described above can be qualified with the following keywords:

For example:

If you specify the 'url' keyword, then instead of setting the window's innerHTML property, you can set its src property. You would use this option when you want to set the window contents to another .a5w page, or an external page.

For example:

 

Create a modeless, resizable URL window and display Google.com

win = GRID1_GridObj.createWindow('window2','modeless-resizable-url');

$(win.getWindowId('body')).src = 'http://www.google.com';

 

 

Create a modal, resizable URL window and display another .a5w page from the current project

win = GRID1_GridObj.createWindow('window3','modal-resizable-url');

$(win.getWindowId('body')).src = 'page2.a5w?var1=somevarvalue';

 

 

 

 

 

How to Put Up a Wait Dialog While The Grid is Performing an Ajax Callback

If you Grid does a callback that takes some time (e.g. searching a large database), you might want to put up a custom 'working...' message.

This example shows how you can do this for a search, but there are client side events that would enable you to put up custom messages for many different types of actions, including sorting, page navigation, saving data, etc.

 

Put this in the canSearchSubmit event

A5.msgBox.show('Searching...','<div style=\'padding: 20px;\'>Please wait while we search for the records.</div>','none',function() {});

 

Put this in the afterSearchSubmit event
 

A5.msgBox.hide();

 

 

 

How to Perform Client Side Calculations - Non US Number Formats

If you have defined a client-side calculation involving decimal  numbers, and your regional settings define a decimal character other than a period (for example, many countries use a comma as a decimal separator - e.g. 2,5), you will need to make the following adjustments in order to get the calculations to display correctly.

The example below assumes that you have fields called Price, Quantity and Total. You want to define a calculated field for Total using the expression Price * Quantity

 

1. In the Javascript Declarations Section, add this code:

 

//Specify the character for the thousands separator

$u.comma = ' ';

//Specify the character for the decimal separator

$u.decimal = ',';

 

2. Set the 'Display Format' for the Price and Quantity field:

(This is necessary so that the initial display of the data uses a comma as the decimal point. We don't need to set the Display Format for the Total field because the calculation will set the correctly formatted value. )

alltrim(str(<value>,250,2,","))

 

3. Edit the Calculated field expression and change it to use the str() function which will apply the appropriate number formatting to the result:

alltrim(str(Price * Quantity,250,2,','))

 

 

How to Use a Grid Component Instead of a Dialog Component

The Dialog Component has not been updated for this release of V10. Since the Grid Component now supports many new features that are not available in the Dialog Component, you might want to use a Grid component instead of a Dialog component in certain cases.

Here is how you can do it:

 

Create a dummy table with the same fields that you would have had in your Dialog component.

  1. Create a Grid component based on this dummy table.
  2. Set the Grid to be a 'Form' layout.
  3. Select the  'Add records only' mode.
  4. Set the number of new records to show to 1.
  5. In the AfterInsertRecord event, you can execute the code that you would have done in the Dialog's AfterValidate event.

How to Dynamically Set a Field Label

The generic Javascript Watch events make it very easy to dynamically set a control's label at run-time.

For example, say that your Grid has a field called 'COUNTRY'. If the value in COUNTRY is 'USA', you want to set the label on the ZIP field to 'Zip code', otherwise you want to set it to 'Postal Code'.

NOTE: This example assumes that the Grid is set to display data in Form mode.

 

Here is how you would do it:

  1. Create a new Javascript Watch event (Properties pane, Javascript section, Watch event) and give it a name (any name will do).
  2. Set the type to 'Other'.
  3. Specify that the field you want to watch is COMPANY (this means that whenever the value in the COMPANY field changes, the Javascript that sets the label value will execute).
  4. Enter this code for the Watch event:

 

var COMPANY = *gv('COMPANY');
var labelValue = 'Zip code';
if( COMPANY != 'USA') labelValue = 'Postal Code';
$('{grid.componentname}.LBL.R' + data.rowNumber + '.'+'ZIP'+'').innerHTML = labelValue;

 

 

How to Set Default Value for a New Record to The Values of the Previously Entered Record

In some applications, you might want to set the default value for a field in a new record to be the same as the value in the previously entered field. Here is how you can to this:

This example shows how you can make the lastname field in a new record use the previously entered lastname as a default. Obviously, when you adapt this for your own use, you could define defaults for as many fields as you wanted.

 

In the AfterInsertRecord event in the Grid builder, define this code:

function AfterInsertRecord as v (e as p)
e.rtc.mydata.lastname = e.datasubmitted.lastname
end function
 

 

In the OnIntialValueCalculate event, define this code:

function onInitialValueCalculate as v (e as p)
dim e.rtc.mydata.lastname as c = default ""
if e.rtc.mydata.lastname <> "" then
    e.newvalues.lastname = e.rtc.mydata.lastname
end if
end function
 

 

How to Refresh the Grid

In some applications you might we adding or editing data in the table that a Grid is based in another Grid or in some custom Xbasic code. You may want to refresh the Grid that is currently being displayed so that it shows the changes and/or new records that were added in the external process. The Grid object supports three different refresh methods:

 

For example:

GRID1_GridObj.refreshRow(1)

 

Where 'GRID1' is the Grid component alias. It must be upper case.

 

How to Debug Image File Reference Images Not Displaying Correctly

If you have built a Grid that contains Image File Reference fields, and the images are not displaying when you run the Grid, this topic can help you find the problem.

Normally, for an Image File Reference field, the display format in the Field Properties is set to <Image File Reference Field>.

To special display formats are supported to help you debug. These are

In the image shown below, the display format is set to <Image File Reference Filename Raw>

This shows the raw (un-encoded) filename for the image.

As you can see only the first record has an alias name in the image.

 

In this next example, the display format is set to <Image File Reference Filename>

This shows the decoded filename for each image.

Only the image in the first row was found. That's because the image name used an alias ([FlowerPhotos]) and this alias was defined in the Web Publishing Profile.

Because the image filenames in records 2 and onwards did not use an alias, the filename was decoded at runtime somewhat randomly and the decoded file does not exists.

 

 

In order to get this example to work, the image filenames need to be fixed. An xbasic program can be written to loop through all of the records and 'fix' the filenames by using a filename that  is encoded with an alias.

 

t = table.open("flowers")

dim fn as c

while .not. t.fetch_eof()

    fn = t.picture

    if atc("[FlowerPhotos",fn) = 0 then

        fn = word(fn,2,"\"")

        fn = "[FlowerPhotos]" + chr(92) + file.filename_parse(fn,"ne")

        fn = "=filename_decode(" + quote(fn) +")"

        t.change_begin()

        t.picture = fn

        t.change_end(.t.)

    end if

    t.fetch_next()

end while

t.close()

 

Debugging Image File Reference Fields in a Report

Say your Image File Reference Field name is 'image'.

Create two calculated fields as follows:

folder = image

fn = eval(substr(image,2))

 

Place these calculated fields on your report and make sure that you set the display width of the field to be large enough to display the full size of the field.

The 'calc->folder' calculated field will show the encoded filename of the image. The 'calc->fn' calculated field will show the actual (un-encoded) filename.


 

How to Override Certain Settings in the .a5w page, or in the OnGridExecute event

In V9 you could override any setting of the grid in the Override Settings section in the Xbasic code that loaded the Grid (in the .a5w page).

In V10, this is no longer possible (at least by default). That's because many of the grid template html and other settings are now computed from the Grid properties at design-time, rather than at runtime.

Many properties can still be set at run-time, but some properties cannot (by default). Typically properties that control the layout of the HTML, control definitions, update settings cannot be set at run-time because Alpha Five has already 'processed' these properties.

You can however force A5 to re-calculate certain parts of the Grid  (that are normally computed at design-time) at run-time by setting properties of the Grid.

 

For example, say you want to override a column heading at run-time with this code

 

tmpl.field_info[3].Column.Heading = "....here is my column heading...."
 

This will not work because the column headings were computed at run-time,

 

However, it will work add this property:

tmpl.flagMustRecalculateGridLayoutAndControls = .t.
tmpl.field_info[3].Column.Heading = "....here is my column heading...."
 

 

 

Note: In the above example, if your Grid is set to use a Form view, you can use the slightly faster tmpl.flagMustRecalcGridLayout property. e.g.

tmpl.flagMustRecalcGridLayout = .t.
tmpl.field_info[3].Column.Heading = "....here is my column heading...."
 

You can set the tmpl.flagMustRecalculateAllProperties property. This forces A5 to re-calculate all aspects of the Grid at run-time. This can be quite slow and should be avoided if possible. (It will delay the initial rendering of the Grid. Once the Grid is rendered, interacting with it will be back to normal speed. There will also be a similar delay when you interact with the Grid if your session expires and a new session needs to be instantiated.)

 

 

List of all flags

tmpl.flagMustRecalcGridLayout

tmpl.flagMustRecalcSearchLayout

tmpl.flagMustRecalcDetailViewLayout

tmpl.flagMustRecalculateGridLayoutAndControls

tmpl.flagMustRecalculateDetailViewLayoutAndControls
tmpl.flagMustRecalculateSearchLayoutAndControls

 

tmpl.flagMustRecalculateAllProperties

 

 

 

How to Change the Grid Base Filter using Automation

The Grid Object has a method that allows you to set the Base Filter for the Grid.

The base filter is normally set in the Grid component. It defines the filter that is always in place. When the user does searches, the search filters are additive to the base filter.

The Grid Object exposes a method to change the base filter.

{Grid.Object}.gridBaseFilterSet(filterExpression [,orderExpression [,parameters]]])

 

You may want to disable this method to prevent a malicious user from changing the Grid's base filter.

You can do this by setting these Grid properties in the 'Advanced' section on the Grid, Properties pane in the Grid builder:

 

tmpl.allowBaseFilterSet  = .t./.f.   'determines if the base filter can be changed at run-time

tmpl.BaseFilterSetPassword  = "mypassword"

 

If tmpl.BaseFilterSetPassword is not null then the filterExpression in the .gridBaseFilterSet() method must be encrypted (using the a5_encrypt_string() Xbasic function).

When the .gridBaseFilterSet() method is called, the server will use the password to decrypt the filter.

 

How to Include User Defined Controls in a Grid

Advanced developers will sometimes insert their own HTML controls in a freeform section for a Grid column. In order to ensure that these user-defined controls get submitted when other controls in the Grid are submitted, you must follow a special naming convention for the controls that you create. The controls must have an ID that matches this pattern:

 

{Grid.componentname}.YouControlId

 

For example:

<input id="{grid.componentname}.MYNEWCONTROL" name="MYNEWCONTROL"/>

 

The control name can be anything you want. If you have a Grid with multiple rows, you will likely want to make the ID unique to each row. For example:

<input id="{grid.componentname}.R{grid.rownumber}.MYNEWCONTROL" name="MYNEWCONTROL"/>

 

How to Pass Information to a Redirect Page

Say you have a Grid component and when the user saves a new record you want to redirect to another page and pass information to that page (such as data values that the user just entered).

Let's assume that the redirect page is called 'Page2.a5w' and you want to pass a variable to this page called EmailAddress which contains the email address just entered by the user.

 

First, define an 'AfterInsertRecord' event. In this event, add this code:

e.rtc.mydata.emailaddress = e.datasubmitted.emailaddress

 

The 'rtc' (short for 'run-time calculation') variable is automatically made available to all of the server-side event handlers. Therefore, if you add you own variable to this dot variable, you can pass information from this event handler to another event handler.

 

Next, define an 'OnPageRedirect' event handler. Add this code:

e.url = "page2.a5w?emailaddress=" + e.rtc.mydata.emailaddress

 

 

Note: Since you are handling the redirect by an event, you need to set the 'Target Page' property to '<event>'.
 

How to use Custom Controls in a Grid Component

This topic discusses an advanced use of a Custom Control in a Grid component.

The image below shows a grid based on the Invoice_header table from Alphasports. The last column on the Grid shows the line-items (from the Invoice_items table) for the current invoice.

This data in this column is a custom control.

 

Here is how this was achieved:

1. Create a dummy calculated field. Does not matter what the calculated field is called.

The image below shows how you can do this for .dbf tables.

 

 

In the case of SQL tables, you would create a custom SQL Select statement. For example:

SELECT invoice_number, customer_id, date, sales_rep, delivery_by, '' as LinkedItems from Invoice_header

 

2. Add the calculated field to the Grid and set its control type to the 'Custom'

 

3. In the 'Custom Control Definition' add this Xbasic:

 

function Linkeditems_render as c (data as p, args as p, PageVars as p)
with PageVars

on error goto Linkeditems_xbasicError
linkeditems_render = linkedRecords(Data.Invoice_number,"GlassBlue")
end

Linkeditems_xbasicError:
Linkeditems_render = "Error in custom control xbasic: " + error_text_get()
end with
end function
 

4. In the 'Xbasic function declarations' section, define the linkedRecords() function.

 

Here is a version of this function for the case where you are working with DBF files. An example for SQL tables follows below.


function linkedRecords as c (invNo as c, style as c )

dim tbl as p
tbl = table.open("[PathAlias.ADB_Path]\invoice_items")
dim itbl as p
itbl = tbl.query_create("","invoice_number = " + s_quote(invNo))

if itbl.records_get() = 0 then
linkedRecords = "No records found"
exit function
end if


dim htmlTemplate as c
htmlTemplate = <<%html%
<tr>
<td class="{grid.style}DataTD">{a5_html_label(js_escape(tbl.data("product_id")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(tbl.data("price")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(tbl.data("quantity")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(tbl.data("extension")))}</td>
</tr>
%html%

htmlTemplate = stritran(htmlTemplate,"{grid.style}",style)

dim html as c = ""
while .not. tbl.fetch_eof()
*concat(html, evaluate_string(htmlTemplate) + crlf())
tbl.fetch_next()
end while


dim titles as c
titles = <<%html%

<tr>
<th class="{grid.style}SorterLink">Product Id</th>
<th class="{grid.style}SorterLink">Price</th>
<th class="{grid.style}SorterLink">Quantity</th>
<th class="{grid.style}SorterLink">Extension</th>
<th></th>
</tr>
%html%

html = "<table>" + crlf() + titles + crlf() + html + crlf() + "</table>"

html = <<%html%
<fieldset style="-moz-border-radius-topleft: 8px; -moz-border-radius-topright: 8px; -moz-border-radius-bottomright: 8px; -moz-border-radius-bottomleft: 8px; display: inline;" class="" >
<legend style="color: Blue;" class="">Invoice Items</legend>
%html% + html + "</fieldset>"


tbl.close()

linkedRecords = html


end function

 

Here is an example for SQL tables:

 

function linkedRecords as c (invNo as n, style as c )

dim cn as sql::connection
dim flag as l
flag = cn.open("::name::alphasports")
if flag = .f. then
    linkedRecords = "Error opening connection"
exit function
end if

dim sql as c
sql = "select * from invoice_items where Invoice_number = :whatInvNo"

dim args as sql::arguments
args.add("whatInvNo",convert_type(invno,"N"))
flag = cn.Execute(sql,args)
if flag = .f. then
    linkedRecords = "Error executing query"
    exit function
end if

dim rs as sql::resultset
rs = cn.ResultSet

if rs.nextrow() = .f. then
    linkedRecords = "No records found."
    exit function
end if

dim htmlTemplate as c
htmlTemplate = <<%html%
<tr>
<td class="{grid.style}DataTD">{a5_html_label(js_escape(rs.data("product_id")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(rs.data("price")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(rs.data("quantity")))}</td>
<td class="{grid.style}DataTD" style="text-align:right;">{a5_html_label(js_escape(rs.data("extension")))}</td>
</tr>
%html%

htmlTemplate = stritran(htmlTemplate,"{grid.style}",style)

dim html as c = ""
dim flagRecordsFound as l = .t.
while flagRecordsFound
    *concat(html, evaluate_string(htmlTemplate) + crlf())
    flagRecordsFound = rs.nextrow()
end while

dim titles as c
titles = <<%html%
<tr>
<th class="{grid.style}SorterLink">Product Id</th>
<th class="{grid.style}SorterLink">Price</th>
<th class="{grid.style}SorterLink">Quantity</th>
<th class="{grid.style}SorterLink">Extension</th>
<th></th>
</tr>
%html%

html = "<table>" + crlf() + titles + crlf() + html + crlf() + "</table>"
html = <<%html%
<fieldset style="-moz-border-radius-topleft: 8px; -moz-border-radius-topright: 8px; -moz-border-radius-bottomright: 8px; -moz-border-radius-bottomleft: 8px; display: inline;" class="" >
<legend style="color: Blue;" class="">Invoice Items</legend>
%html% + html + "</fieldset>"

cn.FreeResult()
cn.close()

linkedRecords = html

end function

 

How to Use Security Framework Functions in a Grid's Server-Side Event Handlers

The Security Framework exposes several functions (listed below for convenience). Some of these functions all implicitly assume that the 'Request', 'Session' and 'Response' server variables will be available. On an a5w page, these variables are available. But in a server-side event handler in a Grid component, you will need to execute a small amount of Xbasic code to make the variables available.

The list below shows which variables each function assumes will be available.

 

a5ws_add_group() - Request
a5ws_delete_group() - Request
a5ws_delete_user() - Request
a5ws_get_group_assignments() - Request
a5ws_get_groups() - Request
a5ws_get_guid_from_group() - Request
a5ws_get_guid_from_ulink() - Request
a5ws_get_guid_from_user() - Request
a5ws_get_page_list() - Request
a5ws_get_security_ques() - Request
a5ws_get_user_assignments() - Request
a5ws_get_user_from_guid() - Request
a5ws_get_user_values() - Request
a5ws_get_webuser_values() -
a5ws_get_users() - Request
a5ws_lockoutuserrelease() - Request
a5ws_lockoutuserset() Request
a5ws_lockoutuserstatus() - Request
a5ws_login_user() - Request,Session,Response
a5ws_logged_in_user_values() - Request,Session
a5ws_logoutuser() - Session,Request,Response
a5ws_save_webuser_values() - Request
a5ws_securityactive() - Request
a5ws_user_file_field_list() - Request
a5ws_Get_WebUser_Values() - Request
a5ws_Get_WebUser_Values() - Request
a5ws_Save_WebUser_Values() - Request
a5ws_Validate_WebUser_Values() - Request
a5ws_WebUser_Exists() - Request

 

If the server side event you are using passes in the 'e' object, you will need to add this code to your event handler:

dim request as p

dim session as

dim response as p

request = e.tmpl.request

session = e.rv.session

response = e.tmpl.response

 

If the server side event you are using passes in 'Args' and 'PageVariables', you will need to add this code to your event handler:

dim request as pp

dim session as

dim response as p

request = args.GridDefinition.request

session = PageVariables.session

response = args.GridDefinition.response

 

How to Print a Report Showing Currently Selected Records

With Action Javascript, it is easy to put a button on a Grid that prints a report. You can easily link the report to data in the current Grid row. For example, if the value of the State field in the current grid row is 'MA', you can easily define a filter for the report that shows all states with a value of 'MA'.

But rather than filter the report based on data in the current row, you might simply want the report to show all of the records that are currently selected in the Grid.

You can easily do this by using the special currentGridFilter() and currentGridOrder() functions in the filter and order expression of your Grid.

 

How to Set the Base Filter/Order, User Filter/Order or Link Definition Programmatically in 'Override Settings'

The 'Base' filter is the filter that is defined in the Grid component. The user cannot remove this filter by doing a 'Show All'. All searches that the user does are in addition to the base filter. The user filter on the other hand is similar to the filter that the user can apply by performing a search, quick search, alphabet button search, etc. When the user clicks the 'Clear search' hyperlink in the Search Part, the filter set by tmpl.filter_initial is removed.

You can set the base filter and user filter in override settings using these properties:

Examples

'For a SQL database

tmpl.base_filter = "orderdate = {2009-12-31}"

tmpl.base_filter = "quantity > 500"

tmpl.base_filter = "state = 'ma'"

 

'For a .dbf database

tmpl.base_filter = "orderdate = {12-31-2009}"

tmpl.base_filter = "quantity > 500"

tmpl.base_filter = "state = \"ma\""

 

Notice that the date/time format for a SQL database is {yyyy-mm-dd} or {yyyy-mm-dd hh:mm:ss}

Using Arguments in the Filter

You can use arguments in the tmpl.base_filter and tmpl.filter_initial properties by specifying a value for the tmpl.argumentValues property.

The syntax for the tmpl.argumentValues property is a CRLF delimited list of argument values defined using this syntax: argumentName|argumentType|argumentValue

Example

'Example 1

tmpl.base_filter = "bill_state_region = :state"
tmpl.argumentValues = "state|c|ca"
 

'Example 2

tmpl.base_filter = "bill_state_region = :state .and. order_date = :orderDate"
tmpl.argumentValues = "state|c|ca" + crlf() + "orderDate|d|12/1/07"
 

 

 

Specifying a Link Programmatically

You can also specify a Link definition programmatically. A link is similar to a base filter, in that the records are filtered on the link fields, but in addition, when a user enters new records into the Grid, the link fields are automatically set to the linking values. For example, if you link the 'Invoice_Items' Grid on the invoice_number field with a value for invoice_number of '1023', then any new records that are entered into the 'invoice_items' Grid will automatically have their 'invoice_number' field set to '1023'.

To set the link definition, you set the tmpl.linkDefinition property.

The syntax for the linkDefinition is a comma delimited list of link definitions in this format: linkField(type:linkValue)

Examples:

tmpl.linkDefinition = "invoice_number(N:1023)"

tmpl.linkDefinition = "first_name(c:john),lastname(c:smith)"

 

How to Show a Control on Only Certain Grid Rows

This topic describes how you can use System Javascript events to show a control on only certain Grid rows. The example we describe here shows a button on row 1 of the Grid only.

To do this, we define an onRowRender System Javascript event that shows the button if we have just rendered row 1 and hides the button is we have rendered any other row.

The following onRowRender event is defined:

 

var ele = $('{Grid.ComponentName}.V.R' + e.rowNumber + '._UNBOUND_BUTTON_1');

if(e.rowNumber == ) {

    ele.style.display = '';

} else {

    ele.style.display = 'none';

}

 

 

The script gets a pointer to the button on the row that was just rendered, and if the row that was just rendered was row 1, it sets the display style to a null string (which makes the button visible), else, it sets the button's display style to 'none', which hides the button.

How to Create a Dynamic Title for a Detail View in a Pop-up Ajax Window

The Detail View can be shown in a popup Ajax window. This topic shows how you can define a dynamic title for the window.

In this example, the Detail View is linked to the customer_id field which is displayed in each row of the Grid. We want the Detail View window title to show 'Detail View for Customer - {customer_id}' (where {customer_id} will be dynamically populated).

To do this, define an event handler for the afterDetailViewOpen event and add this code:



row = {grid.object}._detailViewRow
var x = {grid.object}.getValue('G','CUSTOMER_ID',row);
{grid.object}._dvFloatingWindow.setTitle('Detail View for Customer - ' + x);


 

How to Close a Pop-up Ajax Window

Using Action Javascript, it is easy to open a Grid or A5W page in a pop-up window. Typically, the window is closed by clicking on the X icon in the window title bar.

However, there may be times where you want a button in the Grid, or an event in the Grid to close the window. The Alpha Five Javascript library provides two functions that allow you to close a pop-up window:

The closeParentA5Window() function takes 'ele' as an argument. 'Ele' is the id of any element in the window. For example, say you would like to have a button to close the current window. Here is how the button would be defined:


<button id="mybutton" onClick="closeParentA5Window(this)">Close this popup window</button>

 

The closeLastOpenedA5Window() takes no arguments and closes the most recently opened pop-up window.

The use of these functions is more complicated if the pop-up window contains an IFrame and the content in the window is inside the IFrame. This will be the case if the pop-up window contains an .a5w page.

In this case you will have to do the following:

1. Give the window a unique ID by putting the window title in a <span> tag that assigns an ID. For exmaple

<span id="WINDOWX">My Window Title</span>

2. Use the following Javascript to close the window:

window.parent.closeParentA5Window('WINDOWX');

 

The 'window.parent' syntax is used to refer to the IFrame's parent window which contains the window you want to close.

How to Dynamically Show/Hide the Alphabet Buttons Search Bar

The Alphabet Buttons search bar is a useful addition to your Grid if your Grid is displaying a large number of records, but if there are only a few records in the Grid (perhaps because the last search that was run only returned a few records), you might want to hide the Alphabet Buttons search bar.

The following Javascript can be used to dynamically show/hide the Alphabet Buttons Search Bar:

If there are fewer than 5 records in the Grid, the Alphabet Buttons Search Bar will be  hidden.

records = {Grid.object}._totalRecordsInGrid;
ele = $('{Grid.ComponentName}.ALPHABETBUTTONS');

minRecords = 5;
if(ele) {
    if(records < minRecords ) ele.style.display = 'none';
    else ele.style.display = '';
}

 

This code should be added to the 'afterAjaxCallbackComplete' event in the Javascript - System Events category.


 

How to Get a Pointer to a Grid's Parent Object

The Grid object exposes many methods that you can call from Javascript event handlers in your Grid components. Typically, your Javascript looks like this:

{grid.object}.methodName();

 

'{grid.object}' is a placeholder that gets replaced with the Grid object alias at run-time.

 

There are situations where a Grid is opened as a child of a parent Grid and you want to execute a method on the the Grid's parent Grid. In this case, you can't use the {Grid.object} placeholder. You will need to get a pointer to the Grid's parent Grid object in your Javascript code.

For example, say that you want to put a button on a Grid that will cause its parent Grid to refresh. Here is how you can do this:

 

//Get a pointer to the parent Grid

var po = {Grid.object}.getParentObject();

//If this Grid is not a child Grid, then po will be false. Only call the .refresh() method if po is not false.

if(po) po.refresh();

 

Note: You can get the name of the parent Grid's alias from the Grid object's .parentGridAlias property. For example, try putting this Javascript on a button in a Grid.

 

var myParent = {grid.object}.parentGridAlias;

var me = {grid.object}.gridID;

var message = 'My alias: ' + me + '\nMy parent alias: ' + myParent;

alert(message);

 

How to Use the JQuery Javascript Library with Alpha Five

JQuery is a popular open-source Javascript Library that can be used to add client-side functionality to your web applications. In order to use JQuery with Alpha Five it is necessary to configure JQuery to not use the $ character as the JQuery object name. This is because the $ character is used in the Alpha Five Javascript function libraries. The Alpha Five Javascript function $() is used as a shorthand for the Javascript .getElementById() method.

The following Javascript can be added to the page just after the JQuery library is loaded:

 

<script type="text/javascript">

var $j = jQuery.noConflict();

</script>