Table Concepts
What is the
relationship between a table and an external resource?
What events
are supported for tables?
FPL script
commands for table processing
Issuing
messages from FPL scripts
Displaying
the same table many times in the same form
Copying
component fields into tables
See also:
A table represents an array of data values that can be
displayed in a tabular format as shown in the example below.

The main features of tables are:
A table consists of a number of columns, each one of which
is an Ebase form field and has the same properties as non-table form fields.
The field label text (which is the field name without the table prefix) is used
as the column header text.
A table can optionally be 'backed' by an external resource and this backing resource is specified as a property of the table (Please note that in this version of Ebase, only database and custom resources are supported.) Data is initially loaded from the external resource by using the fetchtable FPL command. To save data to the external resource, the updatetable FPL command is issued. The updatetable command takes care of all amendments that have been made to the table including updates, deletions and insertions. For example, the table shown above consists of the following elements:
|
Table: |
CUSTOMER_TABLE |
|
Table Prefix: |
CUSTOMER_TABLE |
|
Backing resource: |
Database
resource CUSTOMERS |
Data is loaded using FPL command:
fetchtable CUSTOMER_TABLE;
And saved using FPL command:
updatetable CUSTOMER_TABLE;
In this example, the CUSTOMERS database resource has been
configured to return all records from the database. Please note that a backing
resource is normally expected to return multiple records; this is in contrast
to database resources used for the fetch,
update, delete and insert
FPL commands which are assumed to represent single records. For this reason,
database resources used to back tables should not be used for non-table
purposes i.e. they should not be used with fetch,
update, delete and insert
FPL commands.
The relationship between a table column (i.e. a form field)
and a resource field is maintained using a field mapping in exactly the
same way as for non-table fields. These mappings can be displayed and
maintained by clicking the mappings icon on the form toolbar.
It is also possible to include fields in a table which are
not backed by an external resource. For example, the employees
database table may contain a department number, but the requirement is to display
the corresponding department name. Any number of such non-resource fields can
be included in a table. In fact, it is possible to construct a table which is
not associated with a backing resource and all rows are created
programmatically using the FPL insertrow
script command.
Any database resource to be used for backing a table MUST be
declared as a special table resource.
(See Working with
Databases for more information)
A number of built-in functions can be selected covering
common aspects of table behaviour. These features are activated by selecting
the appropriate table property and are intended to make it very easy to quickly
produce functional applications. The features include:
More details on these features are covered later in this
document. While this built-in behaviour meets the requirements of many
applications, there will always be cases when different behaviour is needed. To
meet these requirements, it is possible to add additional table columns
containing checkboxes and buttons to the table rows which equate with application
functions to be performed on a specific table row, and then write FPL scripts
to process the end-user selections. Similarly, buttons could be added at the
bottom of a table to perform explicit functions on selected rows.
There are three events specific to table processing: before
table event, after table event and add row event:
The before table event is fired when the page on
which it appears is first prepared for processing. It can be used to prepare
the table for display for the first time. For example, data could be loaded
from the database using fetchtable, certain columns could be hidden or
made visible or totals fields calculated etc. This event is only fired when the
user moves forwards to the page containing the table using the next page button
or as a result of a goto page FPL command. It is not fired when the page
is re-displayed or when the previous page button is clicked.
The after table event is fired after information has been
received by the user and when all field validation events for table cells have
completed successfully. This event is not fired if the user clicks on a
scroll icon, a sort icon or clicks the add row button.
The add row event is fired when the user clicks the
supplied add row button. This event is provided to allow the application to
supply values for the new row. (See Adding
rows)
The sequence of events before displaying the page for
the first time is:
The sequence of events after receiving user input is:
The system maintains a current row for each table and
all references to field names within a table from FPL script commands are
interpreted as referring to the value of the field on the current row. The
current row is set by the system as follows:
Note that the current row can also be set using the settablerow()
function. An example
of using this function to set the current row from a dropdown list is shown below.
When a table is empty e.g. before fetchtable is
issued, there is no current row and therefore any reference to a table cell
field is interpreted as referring to the value of the field outside of the
table context. For example, the following script, where field CUSTOMER_ID is a
column in table CUSTOMERS:
set CUSTOMER_TABLE-CUSTOMER_ID =
9999;
//
table CUSTOMERS is empty at this point - no current row
log 'CUSTOMER_ID is: ' + tostring(CUSTOMER_TABLE-CUSTOMER_ID);
fetchtable CUSTOMERS;
// table CUSTOMERS is no longer empty -
current row is the first row
log 'CUSTOMER_ID is: ' + tostring(CUSTOMER_TABLE-CUSTOMER_ID);
...will produce output:
CUSTOMER_ID
is: 9999
CUSTOMER_ID
is: 100 (100 corresponds to the first row in
the table after fetchtable)
In general, you should avoid referring to a table field
when the table is empty.
Difficulties can be encountered when the same field is
defined as both a table column and a standalone field. In this situation, only
one copy of the field should be made enterable on any page and all other copies
on the same page should be made display only. Failure to follow this rule can
result in unexpected data values. For example, the following scenario should be
avoided:

This type of application should be implemented using two
distinct fields e.g., the standalone field could be named STATE_SEARCH and the
WHERE clause of the database resource backing the table would then contain
STATE=&&STATE_SEARCH. Resource field STATE_SEARCH would also need to be
defined as non-persistent and mapped to the form's STATE_SEARCH field.
Here are some examples of script processing using the
current row concept:
if [CUSTOMER_TABLE-CREDIT_LIMIT > 10000 ]
message 'Credit limit
exceeds maximum value of 10,000';
endif
The script is specified as a field validation event
for field CREDIT_LIMIT which is a table column. It is executed for each row
visible to the end user. If an error message is issued, it is displayed above
the row in error.
set ORDER_ITEMS-ORDER_TOTAL = 0;
loop at table ORDER_ITEMS
if [ $ROW_DELETED != 'Y' ]
set ORDER_ITEMS-ORDER_TOTAL =
ORDER_ITEMS-ORDER_TOTAL + ORDER_ITEMS-ITEM_AMOUNT;
endif
endloop
where ITEM_AMOUNT is a column in the
table and the table prefix is
ORDER_ITEMS.
goto page CUSTOMER_DETAIL_DISPLAY;
Page CUSTOMER_DETAIL_DISPLAY can
contain any or all of the fields included in the CUSTOMERS table as columns.
When this page is displayed it will contain values from the table's current row
i.e. the row on which the user clicked the link. This list à perform action on selected item is a
common programming construct: the table is loaded with all needed columns, but
only a subset of these (possibly just an id) is initially displayed to the user
in a table; all other columns are declared as hidden. The user then makes a
selection and detailed processing is performed on that particular item - in
this example, the processing is to display a detail page of the selected item.
With Ebase tables, this type of processing can be achieved with hyperlinks,
action buttons displayed as table column cells, or by using the optional select checkbox column and then adding one or
more action buttons at the bottom of the table to process the user selection(s)
and perform specific application functions on these selections.
This last example illustrates that the current row concept
applies even when the page displayed to the user does not contain the table.
This makes it easy to develop applications where the user makes a selection
from a table and then clicks a button to invoke specific processing on the
selected item.
The following FPL script commands can be used when working
with tables:
loop at table tablename
...
...
endloop
Loops through all rows in the table
changing the current row for each pass through the loop. Note that all
rows in the table are presented to the loop, not just the rows that are visible
to the user. Here is an example of a script:
set ORDER_ITEMS-ORDER_TOTAL = 0;
loop at table ORDER_ITEMS
if [ $ROW_DELETED != 'Y' ]
set
ORDER_ITEMS-ORDER_TOTAL = ORDER_ITEMS-ORDER_TOTAL + ORDER_ITEMS-ITEM_AMOUNT;
endif
endloop
As each successive pass through the loop begins, the system
sets the current row to the appropriate table row. This current row value is
maintained for all processing included within the scope of the loop; this
includes additional nested loops, goto page commands, call form/URL
commands etc. If the loop is terminated with a break command or the loop
terminates normally (all rows have been processed), the current row is returned
to its original status before the loop at table. If the loop is
interrupted by a FPL command that immediately terminates processing e.g. goto
page, the current row from the loop at table is maintained until the
page containing the table is re-displayed to the user, whereupon it is returned
to its original status before the loop at table.
Within the loop, it is advisable not to issue commands that
set the current row e.g. fetchtable, updatetable, insertrow, sort.
fetchtable tablename;
This command loads the table with data retrieved from the
backing external resource associated with the table, and sets the current row
pointer to point to the first row in the table. This command should not be
issued within a loop at table construct.
updatetable tablename;
This command updates the backing external resource with the
table data, and sets the current row pointer to point to the first row in the
table. Deleted, inserted, and updated rows are handled automatically. Any empty
rows are ignored and are not written to the external resource. (See Adding rows)
This command should not be issued within a loop at table
construct.
Note: Optimistic locking processing is not currently
available for table operations, therefore no checks are made if the table data
has been changed by external systems since a fetchtable
was issued.
copytable SOURCE_TABLE [to] TARGET_TABLE;
This command copies the contents of the source table to the target table. This is particularly useful for transferring table data from one resource to another resource. e.g. the requirement might be to read data from a database and write it to part of an XML document. This could be achieved by associating T1 with a database resource, T2 with an XML resource and using copytable to transfer the data between the two tables.
sort tablename by COL1, COL2 DESCENDING,
.....;
Provides a programmatic means of sorting table data. Any
number of sort columns can be specified with any mixture of ascending and
descending sort order.
hide/show tablename;
This command can be used to hide or show the entire table
dynamically. It’s longer form set/unset tablename
hidden can also be used.
deleterow;
deleterow
deletes the current row within the current table. This will normally be issued
within a loop at table construct or in an after field event (validation,
on click or on change) for a table cell or an after table event. Note that rows
deleted using this command are immediately deleted from the table and are not
available for further processing. This is in contrast to the optional delete
checkbox displayed to the user which, if clicked, simply marks the row for
deletion but does not remove it from the table.
insertrow tablename [EMPTY];
inserts a row into the specified
table. Fields will be set to their default values or null if no default value
has been specified. The current row pointer is moved to the inserted row. This
command should not be issued within a loop at table construct. The
optional EMPTY indicates the system should treat the new row as empty until at
least one field has been entered by the user. (See Adding rows)
highlight row style;
This
command is used to apply the specified presentation style to all table cells on
the current row of the current table. For example the background colour could
be changed and/or the text could be displayed as bold etc. (See Working with presentation
templates)
unhighlight row;
Removes a highlighting style from the current row. Command unhighlight
all can be used to remove all highlighting styles on the current page.
setrow/unsetrow SELECTED | DELETED | EMPTY;
These two
commands provide programmatic control over the status of a row, and they are
always applied to the current row. For example, setrow SELECTED results
in the select checkbox being ticked for the current row and the $ROW_SELECTED
system variable being set to value Y. (See User
row selection, Deleting rows and Adding rows)
These
commands provide dynamic control over the attributes of entire columns.
set/unset column columnname [in table tablename]
DISPLAYONLY | MANDATORY | HIDDEN;
hide column columnname [in table tablename];
show column columnname [in table tablename];
Hiding a
column (hide or set hidden) removes the column from the displayed
table; similarly showing a column (show or unset hidden) adds the
column to the displayed table.
set/unset columnname [in table tablename]
DISPLAYONLY | MANDATORY | HIDDEN;
hide columnname [in table tablename];
show columnname [in table tablename];
These commands provide dynamic control over the attributes
of each individual table cell. Hiding a table cell displays white space instead
of the cell value. These commands are the same as those used to control non-table
fields.
In addition, all FPL commands that refer to form fields can
be used. When applied to a table field, these commands are interpreted as
referring to the named field on the current row. For example the following
script will insert 10 rows into the EXPENSES table with the EXPENSES-ITEM
column having values 1 to 10. The insertrow command changes the current
row pointer to the new row and the set command then applies to this row.
(See Current row concept)
set EXPENSES-ITEM = 0;
loop [ EXPENSES-ITEM <= 10 ]
insertrow EXPENSES empty;
set EXPENSES-ITEM = EXPENSES-ITEM + 1;
endloop
highlight tablecell columnname style;
This
command is used to apply the specified presentation style to the named table cell
on the current row of the current table. For example the background colour
could be changed and/or the text could be displayed as bold etc. (See Working with Presentation
Templates)
unhighlight tablecell columnname;
Removes a highlighting style from the named table cell on the
current row. Command unhighlight all can be used to remove all
highlighting styles on the current page.
Table appearance is extremely flexible and is customized
using the presentation template sheet associated with the table. The table
attributes can be maintained by clicking the Tables... button in the
presentation template editor. The diagram below shows the different areas of a
displayed table and the name of the corresponding template attributes used to
customize them.

Column order can be changed by clicking on a column's header
and dragging it to the required position.
The number of visible rows displayed on each page is a
property of the table and can be changed as required.
A number of the displayed texts are system texts e.g.
'Select', 'Delete', 'Add row', 'No records to display' etc. Table system texts
are numbered from 370 to 379 and these can be edited using (Tools à System Texts Editor). In addition,
the images used for scrolling and sorting are displayed with alternate texts
taken from system texts 389 to 397.
The row information text e.g. Displaying 1...5 of 56 records
can be suppressed via the Display no. records info option on the table
properties.
To assist non-visual users who may be employing screen reading technology, the following facilities are provided:
Whereas almost all presentational aspects of a table are
controlled using presentation templates, widths are an exception to this rule,
and are controlled using the forms editor. The relative width of each table
column is adjusted by changing the widths of the table cell headers. The width
of the entire table is a table property and is specified as a percentage of the
available width (the full width of the page excluding any JSPs or the width of
the column in a multi-column display). By default, the table will occupy 100%
of the available width.
Designers should be aware that there may be occasions when
the relative widths specified in the designer are not honoured. The reason for
this is that in certain circumstances browsers can decide to ignore or change
the widths specified in HTML - this can occur when the browser decides it does
not have sufficient space to accommodate everything. This is particularly
noticeable for editable fields where most browsers give priority to the field
length setting over the table cell width. If this problem occurs, the length
setting for the field in question should be reduced (the maximum length should
not be changed).
Optionally, the system can be requested to insert an
additional Select checkbox column at the beginning of each row as shown
in the example below. This is requested by setting the rows are selectable
table property.

The user selection can then be processed in a FPL script by
checking the $ROW_SELECTED system variable. For example, the on click script
for the 'Edit selected customer' button might look like this:
loop at table CUSTOMERS
if [ $ROW_SELECTED = 'Y' ]
goto page CUSTOMER_DETAIL;
endif
endloop
User selections can be set and cleared using the setrow/unsetrow
SELECTED FPL commands. These commands also set the $ROW_SELECTED
system variable.
An alternative technique that is very effective when there
is only one function required for each selection (e.g. display or edit) is to
use a hyperlink. An example of this is shown at the top of this document. The
on click FPL script for the hyperlink field would be simply:
goto page CUSTOMER_DETAIL;
In both cases, the current row in the CUSTOMERS table is set
to the row selected by the user and any references to individual table fields
from the CUSTOMER_DETAIL page or subsequent pages are interpreted as referring
to this row.
A table can optionally be configured to allow deletion of
rows by end users. This is requested by setting the table supports deleting
rows table property. If this option is selected, a Delete checkbox
column is added to the far right of the display as shown in the example below.
Rows selected by the user for deletion are not removed from the table until an updatetable
tablename FPL script command is issued. When the updatetable command
is issued, the rows are removed from the table, are removed from the display
presented to the user, and are removed from the backing resource e.g. database
resource, if one exists. Until this point, the user has the option to change
his/her mind by removing the deletion flag. For each row marked for deletion by
the user, system variable $ROW_DELETED is set to 'Y' and can be checked by a
FPL script if necessary.
The marked for deletion indicator can be set and cleared
using the setrow/unsetrow DELETED FPL commands. These commands also
set the $ROW_DELETED system variable.
When a row is marked for deletion, any data entered by the
end user is ignored and all validation for the row is disabled. Specifically,
client-side validation of mandatory input and checking for numeric and date
formats is disabled, and server-side field validation events are also disabled.
However, hyperlink and button on click events for the row are still processed.

Rows can also be deleted programmatically using the FPL deleterow
command which deletes the current row from the current table. Rows removed
using the deleterow command are not shown to the user and are not
processed by a loop at table FPL construct - this is in contrast to the
delete checkbox described in the preceding paragraph. For example, an action
button could be added at the bottom of the table to delete any selected rows.
The script fired by the button could be:
loop at table EMPLOYEES
if [
$ROW_DELETED = 'Y' ]
deleterow;
endif
endloop
Rows can be added to a table in one of two ways:
When the add row button is clicked, the add row event is
triggered and this can be used to assign values to fields in the new row.
A new row is always inserted at the bottom of the table and
may therefore not always be visible to the user. Field values are set to null
or a default value if one exists. For each row inserted, system variable
$ROW_INSERTED is set to 'Y' and can be checked by a FPL script if necessary.
$ROW_INSERTED is set both for rows added using the add row button and with the insertrow
command.
Additionally, a new row may be configured as empty:
rows added by the user with the add row button are always empty, rows added
using insertrow can optionally be configured as empty by adding the word
EMPTY to the insertrow statetment. A row loses its empty status when at
least one value is entered in the row by the end user - setting values in other
ways e.g. using FPL commands does not affect the empty status. Empty rows in a
table differ from other rows in the following respects:
The empty status can be set and cleared using the setrow/unsetrow
EMPTY FPL commands. These commands also set the $ROW_EMPTY system
variable.
Adding rows by the end user
When the user clicks the add row button, the add row event
is fired and the current row pointer is changed to point to the new row. Here
is an example of an add row script that sets a unique id for the new row:
set MAX_ITEM_NO = MAX_ITEM_NO + 1;
set ORDER_ITEMS-ITEM_NO = MAX_ITEM_NO;
where ORDER_ITEMS-ITEM_NO is column
in the table (which may or may not be hidden) and MAX_ITEM_NO is a form field
not included in the table.
Adding rows programmatically
Rows can also be inserted programmatically using the FPL insertrow
command. When this command is issued, the current row pointer is moved to the
new row so that any subsequent SET commands assign values in the new row. e.g.
insertrow EMPLOYEES;
sequence EMPLOYEES;
set EMPLOYEES-EMPLOYEE_ID = $NEXT_SEQUENCE_ID;
set ...
In some circumstances, it may be useful to treat the new row
as empty e.g. an expenses form where you would like to prime the table with a
few empty rows e.g.
insertrow EXPENSES empty;
set EXPENSES-EXPENSE_ID = 1;
insertrow EXPENSES empty;
set EXPENSES-EXPENSE_ID = 2;
The $ROW_INSERTED system variable is not set by the insertrow
command, in contrast to rows inserted by the user.
Each column can be declared as sortable by selecting
the appropriate property for the table column. When a column is sortable, sort
icons are added to the right of the column header text as shown in the example
below. Initially the unsorted icon
is shown to indicate
that the column is sortable but has not yet been sorted. When the user clicks
on this icon, the table is sorted in ascending order. Thereafter, the system
toggles between an ascending and descending sort and the appropriate icon
or
is displayed to show
the next available sort direction.

Tables can be scrolled both horizontally and
vertically.
Horizontal scrolling is activated automatically when
the table has more than one horizontal page. When the system detects that
horizontal scrolling is applicable, scrolling icons
and
are inserted
on the right-hand side at the top of the table. One or more columns can be fixed,
and these columns are always displayed as the leftmost columns regardless of
which horizontal page is displayed.
Vertical scrolling is activated when the number of
rows in the table is greater than the number of rows to be displayed. The
scrolling attributes can be maintained by clicking the Tables... button
in the presentation template editor, then clicking Table Scrolling. A large number of options are available to
configure the display of the scrolling control; a preview is provided within
the configuration dialog.
User requests to sort, scroll or add a row are treated as table
internal events. When one of these events occurs, all data is first
validated by running the appropriate field validation event scripts if any have
been specified. If an error or warning message is issued by one of these
scripts, the user request is not honoured.
If an empty table is displayed to the user, message 'No
records to display' replaces the usual text 'displaying n to nn
of nnn records'. In this circumstance, the only option available to the
user is to click the add row button. Alternatively, the table could be
primed with a number of empty rows using the insertrow
script command as shown in the example below:
insertrow EXPENSES;
//
set initial values for the first row
set EXPENSES-START_DATE = $SYSTEM_DATE;
set EXPENSES-DESCRIPTION = 'First empty row';
insertrow EXPENSES;
//
set initial values for the second row
set EXPENSES-START_DATE = $SYSTEM_DATE;
set EXPENSES-DESCRIPTION = 'Second empty row';
The insertrow
command changes the current row pointer to the inserted row, so any subsequent
FPL commands operate against that row.
Empty tables are visible if either the tables supports adding rows button or Display no. records info options are selected. If just Display no. records info is selected then only the text 'No records to display' is shown. If required, this text could be supressed for empty tables by setting the table’s displayInfo property to false e.g.:
if [ MYTABLE.rowCount = 0 ]
set table MYTABLE.displayInfo
= false;
else
set table MYTABLE.displayInfo = true;
endif
See set table
command for further information.
An error or warning message issued during a field
level event for a field within a table will be displayed immediately above the
row containing the field in question. Messages issued at a before or after table
event will be displayed immediately above the table.
A table column can be configured as either a static or
dynamic list allowing the user to select from a pulldown list. If a dynamic
list is used, then the following additional features are also possible:
Sometimes there is a requirement to extract a column from a
table and display this as a dropdown list. In this case, the table would probably
not be displayed to the user. This is achieved by using the buildlistfromtable()
function. In addition, the settablerow()
function can be used to set the current row for the table based on the user
selection.
Function buildlistfromtable takes four parameters as
follows:
·
name of the field to which the list is attached
·
name of the table
·
name of the table column to be displayed in the
list
·
name of the table column to be returned when a
value is selected
The last two parameters can both refer to the same column if
required.
Here is an example of using these functions:
We have a table CUST with columns CUST-ID, CUST-NAME and
CUST-CREDIT_RATING where CUST-ID is a unique integer and CUST-NAME is the name
of the customer. We want to display a dropdown list containing all customer
names in alphabetical order. This can be achieved with a script like this:
fetchtable CUST;
sort CUST by CUST-NAME;
set NUM_CUSTOMERS = buildlistfromtable(' CUSTLIST', 'CUST',
'CUST-NAME', 'CUST-ID';
CUSTLIST is the field name of the dropdown list, and this
must have a display type set to Drop Down.
NUM_CUSTOMERS is an INTEGER field and is set to contain the
number of entries in the list.
Note that CUST-ID is set as the return field for the list.
This is important for the next section where we set the current row of the
table based on the user selection. The user selection could then be used to
display additional table column values for the selected customer - in this
example we only have one, CUST_CREDIT_RATING. This could be displayed by the
following script run as an immediate validation event for the list field
CUSTLIST.
set STATUS = settablerow( 'CUST', 'CUST-ID',
CUSTLIST );
show CUST-CREDIT_RATING;
Field STATUS will receive the value 'OK' if the table row was
set or 'NOT SET' if the value could not be matched. We don't need to check this
in our example as we know that the table contains all customer ids in the list.
The system processes this command by looping through all
rows in table CUST and comparing the CUST-ID column with the value of field
CUSTLIST (this will contain the unique customer identification number). When a
match is found, the table current row is set.
You can display the same table many times in the same form
or even on the same page. To do this, select the existing table option
from the add table dialog and then choose the table from the list. When a table
has multiple views, each view (i.e. the table as seen by the user) can have different
properties e.g. one might be enterable, the next display only, or different
columns could be displayed etc. However, the underlying table data - the values
of the table cells - is shared between all views. This means that a data change
made using one table view is automatically reflected in all other table views.
When column fields are added to a table, it is possible to
specify that existing form fields should be copied. When non-component
fields are specified, the fields are simply copied and all field attributes can
be changed on the new column field. However, when a component field is
selected, a linkage between the component field and the newly created table
column field is maintained, and most attributes of the new column field cannot
be changed. If the component is then re-deployed, any changes made to the
copied fields are deployed to both the instance of the component fields in the
form and also any copies that have been included in tables.
This feature makes it possible to create fields-only
components that represent data structures, deploy these to forms, then copy the component fields into tables. When changes are
made to the underlying component, these changes are propagated to the copied
table column fields when the component is deployed.
Tables Tutorial contains a
worked example where you build a form containing a table.