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:
- Default value defined in column attributes (wic_jdic_colattr.col_defval).
- Javascript form reset event (wic_jrep_form_data.form_js_before_input), executed once when form reset was executed.
- 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.
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:
function reset_order () { var m_order = executeQueryValue("GET_ORDEN", [ getParentFieldValue("Invoice.InvoiceId") ]); setFieldValue("InvoiceLine.order", m_order + 2); }
- Using a reset event in txmanager
- 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:
function reset_InvoiceEmployeeId () { setFieldValue("Invoice.InvoiceEmployeeId", getGlobalString("Employee.EmployeeId")); }
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:
function reset_DateStart () { setFieldValue("InvoiceLine.DateStart", getParentValue("Invoice.DateStart")); } function reset_DateEnd () { setFieldValue("InvoiceLine.DateEnd", getParentValue("Invoice.DateEnd")); }
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:
function reset_InvoiceEmployeeId () { var empId = getGlobalString("Employee.EmployeeId"); if (empId == null || empId.length == 0) empId = "000000"; setFieldValue("Invoice.InvoiceEmployeeId", empId); }
wic_jdic_colptions(tab_name, col_name, expr_default) VALUES ("Invoice", "InvoiceEmployeeId", "${Employee.EmployeeId} != '' ? ${Employee.EmployeeId} : '000000'")
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.
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.
// 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); }
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.
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.
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:
SELECT COUNT(*) FROM myconftable WHERE user = $USER AND canedit_price != 0
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:
!isOnUpdate()
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.
// 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); }
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.
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:
function after_Quantity () { if (getFieldValue("InvoiceLine.Quantity") == 0) setFieldError("InvoiceLine.Quantity", "Quantity should different from zero."); }
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:
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."); }
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.