New version of Axional Studio 2017.3 enables some dictionary structure and functionalities introducing new mechanisms for defining column editable settings, such as, default values, column nullability, client validation, etc. Those functionatities were traditionally achieved by using Javascript code in objects definition, which were difficult to develop and maintain, were a source of errors and the code can not to be reused in other views or components.

So, broadly new column editable features provides:

  • Simplification by replacing complex Javascript codification of function calls and events handling by simple expressions.
  • Anywhere applicable, as they are defined as general settings they could be applied to forms, SQLTables, channels, etc.
  • Code reuse, centralizing column editable settings allow applying them to different objects or components.
  • Minimize errors by decreasing programing code.
  • Decrease development time by using simple expressions instead of Javascript programing.
  • Traceability, by using expressions instead of Javascript programing, the column properties can be analyzed and reported.

1 Default value

The concept default value references the initial value for a column when executing an insert operation.

1.1 Old implementation

There were three elements, which determined the initial value for a field in a document. In order as they were applied are:

  1. Default value defined in column attributes (wic_jdic_colattr.col_defval).
  2. Javascript form reset event (wic_jrep_form_data.form_js_before_input), executed once when form reset was executed.
  3. Javascript field reset event (wic_jrep_form_cols.evt_reset), executed for each field when form reset was executed.

The main issues of this implementation was: the use of complex Javascript code for simple operations such us dynamic default values; and code fragmentation, which increased the difficulty of implementation and maintenance, and promoted performing multiple server connections when getting default values, with the corresponding performance issues.

1.2 New implementation

In order to solve the issues listed before, the new implementation for default values includes:

  • Replace the definition of default value in column attributes (wic_jdic_colattr.col_defval), which only allowed one value for column, by a new table which allows more than value and includes an application expression to allow apply default values dynamically.
  • Boost default value expression to allow referencing global and parent values
  • Add a new event Reset for object transaction manager which might execute and script returning a map with the default values.

Considerations

  • Default values defined by column attributes will be moved into the new structure via conversion.
  • Javascript code for form reset event will be keep operative in order to execute custom client side operations, such us displaying notes, showing/hiding element, etc. Anyway, it is not advisable to modify form values in that event, as it was performed in old implementation, to prevent altering reset execution flow.

Code revision required

Javascript code for field reset event will be removed. The system will maintain the data as backup but the code will be no longer executed. As it could hold complex Javacript code that should be converted to defaults application expressions or XSQL-Script code it is not possible to define a conversion, so those implementations must be translated manually.

1.2.1 Tables structure

TO DO

This section is incomplete and will be concluded as soon as possible.

1.3 Explanation cases

The following cases tries to show the typical situations for defining default values and compare how was configured using the old implementation with the one.

1.3.1 Use constant as default value

A common case is to set an initial value for a numeric column. For example, we want to define the default value 1 for column InvoiceLine.Quantity.

The old implementation consisted on defining the default value in the column attributes parameterization.

The new implementation is basically the same, just using the new configuration table.

1.3.2 Use system expression as default value

It exists some system expressions that are translated into a default value for an specific column. Common cases are the use of date expressions such as TODAY or CURRENT for date columns. This example shows how to set the current date for the column Invoice.InvoiceDate.

The old implementation consisted on defining the default value in the column attributes parameterization and using the constant TODAY as default value.

Explain new implementation

1.3.3 Get default value from server

Another usual situation is the need of executing some query in the server for obtaining the initial value of a column. For example, the following sample consist on increasing by two the field order of the sample InvoiceLine table.

With the old implementation this situation was achieved by using Javascript code, adding a query execution on the before_input or the reset_field event. For example:

Copy
function reset_order () {
    var m_order = executeQueryValue("GET_ORDEN", [
        getParentFieldValue("Invoice.InvoiceId")
    ]);

    setFieldValue("InvoiceLine.order", m_order + 2);
}
Explain new implementation: It might be implement by two ways:
  1. Using a reset event in txmanager
  2. Allow server expressions as default value:
    wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("InvoiceLine", "order", "SELECT NVL(MAX(order), 0)+2 FROM InvoiceLine WHERE InvoiceId = ${Invoice.InvoiceId}")

1.3.4 Referenceing global variable in default value

Referencing a global variable is another common situation. For example, it allows loading the Employee information related to the current user and apply it to a certain form without adding a join to the main cursor statement. In the following sample, we assume that we have loaded the information of Employee.EmployeeId as a global variable and it will be used as default value for the column Invoice.InvoiceEmployeeId.

This is another situation which used to be done by adding Javascript code:

Copy
function reset_InvoiceEmployeeId () {
    setFieldValue("Invoice.InvoiceEmployeeId", getGlobalString("Employee.EmployeeId"));
}
Explain new implementation: Allow server expressions as default value:
wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("Invoice", "InvoiceEmployeeId", "${Employee.EmployeeId}")

1.3.5 Referenceing parent variable in default value

It is also useful to handle parent values to determine the initial value of a column. For example, when having a range of dates in the header of a document (Invoice.DateStart, Invoice.DateEnd) and a more specific ones at the document lines (InvoiceLine.DateStart, InvoiceLine.DateEnd), it is sometimes necessary to propose the range of dates from the header as default values for the line. it allows loading the Employee information related to the current user and apply it to a certain form without adding a join to the main cursor statement. In the following sample, we asume that we have loaded the information of Employee.EmployeeId as a global variable and it will be used as default value for the column Invoice.InvoiceEmployeeId.

This implementation was achieved in the old implementation by adding Javascript code:

Copy
function reset_DateStart () {
    setFieldValue("InvoiceLine.DateStart", getParentValue("Invoice.DateStart"));
}
function reset_DateEnd () {
    setFieldValue("InvoiceLine.DateEnd", getParentValue("Invoice.DateEnd"));
}
Explain new implementation: Allow server expressions as default value:
wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("InvoiceLine", "DateStart", "${Invoice.DateStart}")
wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("InvoiceLine", "DateEnd", "${Invoice.DateEnd}")

1.3.6 Dynamic default value

Sometimes, the default value depends on some application logic. For example, having various default values applicable to a column with a certain priority. In the following example, if the current user is defined as an Employee (via the Employee global variable) it will apply the corresponding Employee.EmployeeId; otherwise, it will set the default value 000000.

This implementation was achieved in the old implementation by adding Javascript code:

Copy
function reset_InvoiceEmployeeId () {
    var empId = getGlobalString("Employee.EmployeeId");
    if (empId == null || empId.length == 0)
        empId = "000000";

    setFieldValue("Invoice.InvoiceEmployeeId", empId);
}
Explain new implementation: Allow server expressions as default value:
wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("Invoice", "InvoiceEmployeeId", "${Employee.EmployeeId} != '' ? ${Employee.EmployeeId} : '000000'")
Consider default types of attributes: If null, Always, On insert, Always (Backend), On insert (Backend)

See also

Appart from dictionary configuration for column default values, it might be defined a default value by user ROLE, via the Database Security Roles. This value will prevail over the dictionary settings.

2 Nullability

The nullability of a column is related to the possibility of letting a field blank in a form. When this requirement is fixed it is advisable to define the physical column as required, when defining the physical dictionary. But sometimes the requirement of letting a column blank includes some application logic, so it must be defined as not required in the physical dictionary and some code must be added to express the nullability requirements.

Configure dynamic logic to determine the nullability of a column might also be done in server-size by using physical check constraints; which is highly recommended in order to preserve database integrity. Anyway, client-side nullability configuration complements server-side restricctions by guiding the user during data entry.

2.1 Old implementation

It didn't exist any parameterization structure to configure dynamic nullability, so the only way to achieve it was by using the Javascript user function setFieldNullable, in the object Javascript programing code. The main issues of this implementation are complexity of using Javascript code and the difficulty of reuse the code in other objects or components.

2.2 New implementation

In order to solve the issues mentioned before the new implementation includes a new table for defining nullability client-side configuration. This configuration will be evaluated by the system to enable/disable fields nullability in objects and components.

2.2.1 Tables structure

TO DO

This section is incomplete and will be concluded as soon as possible.

2.3 Explanation cases

The following cases tries to show the typical situations for defining dynamic columns nullability, and compare how was configured using the old implementation with the one.

2.3.1 Change the nullability state of a column dynamically

The most common case is when a column value is related to previous column; so, it is only valid when the preceding column has an specific value. For example, imagine that the value of Employee.City is not required, but it should be required in case that Employee.Address is set.

In the old implementation this functionality was implementing adding Javascript code.

Copy
// Ensure the nullability state when changes the Address
function after_Address () {
    setFieldNullable("Employee.City", getFieldValue("Employee.Address").length == 0);
}

// Ensure the nullability state when loads the document
function document_onload () {
    setFieldNullable("Employee.City", getFieldValue("Employee.Address").length == 0);
}
Explain new implementation: Allow server expressions as default value:
wic_jdic_colptions(tab_name, col_name, expr_nullable) VALUES ("Employee", "City", "${Employee.Address} == '')

3 Editable configuration

Editable configuration handles when a field representing a column is editable or not. When the editable configuration is fixed the kind of field in a form or the column used in an SQLTable its enough. But when a field editable condition is dynamic is necessary to add some application logic which handles this situation.

3.1 Old implementation

There were three ways for defining the field editable state in a document:

  • Input field editable server condition (wic_jrep_box_formdata.col_server_input_expr).
  • Input field editable client condition (wic_jrep_box_formdata.col_client_input_expr).
  • Using the Javascript user function setFieldNoentry, in the object Javascript programing code.
The main issues of this implementation are the complexity of using Javascript code and the difficulty of reuse the expression and code in other objects or components.

3.2 New implementation

In order to solve the issues mentioned before the new implementation of column editable configuration includes:

  • Generalize server and client expression by moving the expressions from wic_jrep_box_formdata to a new table linked to a table and column instead to an object.
  • Client expression will be evaluated every time the fields used in the expression changes.
  • Boost expressions referencing global and parent values.

Server and client expressions defined by form data input field (wic_jrep_box_formdata) will be moved into the new structure via conversion.
Javascript code using setFieldNoentry function cannot be defined as conversion, so this must be translated manually.

3.2.1 Tables structure

TO DO

This section is incomplete and will be concluded as soon as possible.

3.3 Explanation cases

The following cases tries to show the typical situations for defining enable/disable column editable configuration, and compare how was configured using the old implementation with the one.

3.3.1 Editable status depending on a server condition

It allows using an SQL statement to verify configuration tables for enabling/disabling editable condition for a field. For example, if it would exist a configuration table which determines if the user is authorized to modifying prices (myconftable.canedit_price), and the editable state of InvoiceLine.UnitPrice depends on that value.

Using the old implementation this functionality was implemented by defining the proper SQL statement in the server condition for enabling field edition (wic_jrep_box_formdata.col_server_input_expr) associated to a field in form:

Copy
SELECT COUNT(*) FROM myconftable WHERE user = $USER AND canedit_price != 0
Explain new implementation:
wic_jdic_colptions(tab_name, col_name, expr_editable) VALUES ("InvoiceLine", "UnitPrice", "SELECT COUNT(*) FROM myconftable WHERE user = $USER AND canedit_price != 0")

3.3.2 Editable status depending on a client condition

It allows using simple javascript expressions for enabling/disabling editable field status. It is often used when the editable state depends on the entry mode (Insert/Update), or when depends on other non editable columns (Recall that client expression in old implementation was not reactive, so it didn't update field status when changes the fields). For example, a column Employee.EmployeeId is only editable for insert.

Using the old implementation this functionality was implemented by defining the proper Javascript expression in the client condition for enabling field edition (wic_jrep_box_formdata.col_client_input_expr) associated to a field in form:

Copy
!isOnUpdate()
Explain new implementation:
wic_jdic_colptions(tab_name, col_name, expr_editable) VALUES ("Employee", "EmployeeId", "!isOnUpdate()")

3.3.3 Editable status depending on a dynamic client condition

It allows using expressions for enabling/disabling editable field status, involving other columns that should refresh the editable status while changing their value in form. It is often used when a column value depends on a previous column. Recovering the situation of the nullability state, the value of Employee.City should be editable only in case that Employee.Address have some data.

Recall that client expression defined by the client condition for enabling field edition (wic_jrep_box_formdata.col_client_input_expr) associated to a field in form didn't recalculate the editable status when the columns used in the expression changes. So, this functionality had to be done adding some Javascript code to the object.

Copy
// Ensure the editable state when changes the Address
function after_Address () {
    setFieldNoentry("Employee.City", getFieldValue("Employee.Address").length == 0);
}

// Ensure the editable state when loads the document
function document_onload () {
    setFieldNoentry("Employee.City", getFieldValue("Employee.Address").length == 0);
}
Explain new implementation:
wic_jdic_colptions(tab_name, col_name, expr_editable) VALUES ("Employee", "City", "${Address} != ''")

4 Client-side validation

Client-side validation provides better user experience by responding as quicker as possible when the user is introducing an incorrect value during data entry.

The system also try to evaluate some physical check constraints on client-side. However, depending on how are those checks defined evaluation is not possible. Besides, the moment at they are evaluated and the resultant message sometimes is not clear enough.

4.1 Old implementation

Until the current version, client-side validation was performed mainly by adding Javascript code to the object, using the user function setFieldError in the object events before_insert, before_update and after_field. As occurs in previous cases, the main issues of this implementation is the complexity of using Javascript code and the difficulty of reuse the code in other objects or components.

4.2 New implementation

In order to solve the issues mentioned before the new implementation of column client-side validation consist on adding a new table for implementing a validation expression and a label which must be shown in case that the expression returns false. The expression should be evaluated on client-side every time the defined column or any column referenced in the expressions changes.

4.2.1 Tables structure

TO DO

This section is incomplete and will be concluded as soon as possible.

4.3 Explanation cases

The following cases tries to show the typical situations for defining client-side field validation, and compare how was configured using the old implementation with the one.

4.3.1 Apply a simple validate expression

Allows verifying the input data with a simple javascript expression and showing a warning message to the user in case of the introduced value would be wrong, just after abandoning the field in form. For example, to ensure that the column InvoiceLine.Quantity has a value different from zero.

Using the old implementation this functionality had to be implemented by adding some Javascript code to the object:

Copy
function after_Quantity () {
    if (getFieldValue("InvoiceLine.Quantity") == 0)
        setFieldError("InvoiceLine.Quantity", "Quantity should different from zero.");
}
Explain new implementation:
wic_jdic_colptions(tab_name, col_name, expr_validate, validate_lbl) VALUES ("InvoiceLine", "Quantity", "${Quantity} != 0", "LBL_QUANTITY_ZERO")

4.3.2 Apply multiple validate expressions

In some cases it is better to emit different warning message in order to report the user the best warning message. For example, in case that it is not allowed the zero value for the column InvoiceLine.Quantity, and neither having negative numbers.

Using the old implementation this functionality had to be implemented by adding some Javascript code to the object:

Copy
function after_Quantity () {
    if (getFieldValue("InvoiceLine.Quantity") == 0)
        setFieldError("InvoiceLine.Quantity", "Quantity should different from zero.");
    else if (getFieldValue("InvoiceLine.Quantity") < 0)
        setFieldError("InvoiceLine.Quantity", "Quantity should be a positive number.");
}
Explain new implementation:
wic_jdic_colptions(tab_name, col_name, expr_validate, validate_lbl) VALUES ("InvoiceLine", "Quantity", "${Quantity} != 0", "LBL_QUANTITY_ZERO")
wic_jdic_colptions(tab_name, col_name, expr_validate, validate_lbl) VALUES ("InvoiceLine", "Quantity", "${Quantity} >= 0", "LBL_QUANTITY_NEGATIVE")

5 Summary

In conclusion, the pack of structure and functionality changes for implementing the new column settings are:

  • New table for defining default values.
  • Boost default value expressions.
  • New event Reset for object transaction manager.
  • New table for defining client-side column nullability configuration.
  • New table for defining column editable configuration.
  • Reactive evaluation of editable client-side expressions.
  • Boost column editable expressions.
  • New table for defining client-side column validation.