Using Zen Components
Zen Forms
|
|
Forms permit the user to enter data. A Zen
control is a component that displays application data and allows the user to edit this data. A Zen
form is a specialized group component designed to contain control components. Zen forms have the same style and layout attributes as any Zen group. Also, because they are groups, forms may contain any other type of Zen component.
Like all Zen components, a Zen form must be the child of a Zen page object. This means that if you want to provide a form for a Zen application, you must create a Zen page class that includes a form component inside the <page> container. Two components are available:
-
<form> A Zen group that contains a specific list of control components. These controls may or may not take their values from a data controller, but their layout is entirely determined by the <form> definition in XData Contents.
-
<dynaForm> An extension of <form> that dynamically injects control components into a group (or groups) on the Zen page. The list of controls may be determined by the properties of an associated data controller, or by a callback method that generates a list of controls. Layout is automatic, determined by code internal to the <dynaForm>.
The Zen library includes a number of controls for use in forms. Many of these controls are wrappers for the standard HTML controls, while others offer additional functionality. The following figure displays a form that contains a number of controls, including text fields and radio buttons. This is the sample form generated by the class
ZENDemo.FormDemo in the
SAMPLES namespace.
Class Inheritance Among Form and Control Components
The basic interaction between a Zen application user and a Zen form is as follows:
-
A user interacts with controls on the form
-
Zen may validate the data as it is entered
-
A user action indicates that it is time to submit the form
-
Zen may validate the data prior to attempting the submit
-
Zen interacts with the user to handle any errors it finds
-
When all is well, Zen submits data from the form
-
Any of the following might happen next:
-
Data from the form may be written to the server
-
The same Zen page may redisplay
-
A different Zen page may display
-
The same Zen page may display, but with components added or changed
Form Component Attributes
Attribute |
Description |
Zen group attributes |
A form has the same style and layout attributes as any Zen group. For descriptions, see Group Layout and Style Attributes in the Zen Layout chapter of Using Zen. |
action |
Specifies a HTML action for the form. Setting the action attribute overrides the default behavior of Zen forms so that Zen does not execute its normal submit logic. InterSystems recommends you do not use the action attribute except in special cases where direct control of the HTML action attribute is required. This could be the case for certain custom login forms. |
autocomplete |
Indicates whether controls in this form can have their values automatically completed by default by the browser. Elements belonging to the form can override this setting by setting an autocomplete attribute. |
autoValidate |
If true (the default), automatically invoke this form’s validate method whenever this form is submitted. |
controllerId |
If this form is associated with a data controller, the controllerId attribute identifies the controller that provides the data for this form. The controllerId value must match the id value provided for that <dataController>. See the chapter Model View Controller. |
enctype |
Specifies a HTML enctype for the form, such as "multipart/form-data" |
invalidMessage |
Message text that the form validate method displays in an alert box when the contents of this form are invalid. The default is: |
key |
If a <form> or <dynaForm> specifies a key, the OnLoadForm callback uses this model ID to load initial values into the form. However, if this form is connected to a <dataController>, the key value is ignored. |
method |
Specifies a HTML method for the form. Setting the method attribute overrides the default behavior of Zen forms so that Zen does not execute its normal submit logic. InterSystems recommends you do not use the method attribute except in special cases where direct control of the HTML method attribute is required. This could be the case for certain custom login forms. |
nextPage |
URI of the page to display after this form is successfully submitted. This URI may be overwritten by a specific <submit> button on the form. |
onchange |
|
ondefault |
Client-side JavaScript expression that Zen invokes when the user performs an action that triggers the default action for a form. Typically this is when the user presses the Enter key within a control within the form. |
oninvalid |
Client-side JavaScript expression that Zen invokes when this form’s validate method determines that the contents of this form are invalid. This provides the application with a chance to display a custom message. |
OnLoadForm |
Name of a server-side callback method in the Zen page class. Find further information following this table. |
onnotifyView |
|
onreset |
Client-side JavaScript expression that Zen invokes when this form is about to be reset. Generally this expression invokes a client-side JavaScript method. |
OnSubmitForm |
Name of a server-side callback method in the Zen page class. This method takes a set of actions that is appropriate upon form submit. Use of OnSubmitForm is limited to providing an alternative to the built-in mechanisms that a form provides for detecting changes, validating values, and submitting the form. It should not be used to perform other types of general-purpose processing. The next several sections describe the build-in mechanisms provided by form submit. The callback must return a %Status data type. The following is a valid signature for this callback: |
onsubmit |
Client-side JavaScript expression that Zen invokes when this form is about to be submitted. Generally this expression invokes a client-side JavaScript method with a Boolean return value. Invoking this method gives Zen a chance to perform client-side validation of values within the form. If the method returns false, the pending submit operation does not occur. Note that unlike the HTML onsubmit event, the onsubmit callback is always called whenever the form is submitted. |
onvalidate |
Client-side JavaScript expression that Zen invokes when this form’s validate method is called. Generally this expression invokes a client-side JavaScript method that performs validation. |
readOnlyMessage |
Message text that the form validate method displays in an alert box when the user makes an attempt to save a form bound to a read-only data model. The default readOnlyMessage text is: |
The
OnLoadForm method retrieves the values that appear on the form when it first displays. It can get values from the object whose model ID is provided by the
key attribute for the form, or it can assign literal values. The method must then place these values into the input array, subscripted by the
name attribute for the corresponding control on the form. It is this
name (and not the
id) that associates a control with a value. Zen invokes this method when it first draws the form, automatically passing it the following parameters:
The callback must return a
%Status data type. The following example shows a valid method signature and use of parameters:
Method LoadForm(pKey As %String,
ByRef pValues As %String) As %Status
{
Set emp = ##class(ZENDemo.Data.Employee).%OpenId(pKey)
If ($IsObject(emp)) {
Set pValues("ID") = emp.%Id()
Set pValues("Name") = emp.Name
Set pValues("SSN") = emp.SSN
}
Quit $$$OK
}
To use the above method as the callback, the developer would set
OnLoadForm="LoadForm" for the <form> or <dynaForm>.
Providing Values for a Form
A form can initially display with blank fields, or you can provide data for some of the fields. Providing data for a field that the user sees means setting the
value property for the associated Zen control component, before you ask Zen to display the form. There are several ways to do this:
-
Set the
value attribute while adding each control to XData Contents.
-
Set the
onLoadForm attribute while adding the form to XData Contents.
-
-
On the client side, call the
setValue method for each control.
Presumably, once the user begins editing the form, any initial values may change.
Detecting Modifications to the Form
A control’s
isModified method returns true if the current logical value of the control (the
value property) is different from its original logical value (the
originalValue property). With each successive submit operation, the
originalValue for each control acquires its previous
value, so that this answer is always current with respect to the current state of the form.
When you call a form’s
isModified method, it invokes
isModified for each control on the form, and if any control returns true,
isModified returns true for the form.
Note:
The <textarea> control returns an accurate
isModified status when it contains fewer than 50 characters. When the <textarea> value contains 50 characters or more, the control does not compute an
isModified status.
Each Zen form has a
validate method whose purpose is to validate the values of controls on the form. If the form’s
autoValidate property is true,
validate is called automatically each time the form is submitted. Otherwise,
validate may be called explicitly by the application.
validate does the following:
-
Calls a form-specific
onvalidate event handler, if defined. If this event returns false, Zen declares the form invalid and no further testing occurs.
-
Resets the
invalid property of all the form’s controls to false, then tests each control by calling the control’s
validationHandler method. This method, in turn, does the following:
-
-
If the control’s
required property is true and the control does not have a value (its value is ""), return false.
-
If the control defines an
onvalidate event, execute it and returns its value. Otherwise, call the control’s
isValid method.
isValid can be overridden by subclasses that wish to provide built-in validation (such as the
dateText control).
-
As the
validate method tests each control, the form builds a local array of invalid controls.
-
After the
validate method is finished testing the controls, it returns true if the form is valid.
-
If the form contains one or more controls with invalid values, it is invalid.
validate performs one of the following additional steps to handle this case:
-
If the form defines an
oninvalid event handler:
Execute the handler. This provides the form with a chance to handle the error conditions. The value returned by the
oninvalid event is then returned by the form’s
validate method. The
oninvalid handler has an argument named
invalidList that receives a JavaScript array containing the list of invalid controls. For example:
<form oninvalid="return zenPage.formInvalid(zenThis,invalidList);" />
ClientMethod formInvalid(form,list) [ Language = javascript ]
{
return false;
}
-
When the form has no
oninvalid event handler:
validate sets the
invalid property to true for each invalid control (which changes their style to zenInvalid); gives focus to the first invalid control; and displays an error message within an alert box. The message displayed in the alert box is built from a combination of the form’s
invalidMessage property along with the value returned from each invalid control’s
getInvalidReason method.
Note:
It is standard practice not to invoke validation logic for null values.
Errors and Invalid Values
Should an error occur while a form is being submitted, or should the form fail validation, Zen redisplays the page containing the form. The user has the opportunity to re-enter any incorrect values and submit the page again. All of this is extremely easy to set up when adding the <form> or <dynaForm> component to the Zen page.
-
-
Where 57772 is the web server port number that you have assigned to Caché.
-
Ensure that the
Name field is empty.
-
-
-
The form’s
validate method detects the invalid fields and highlights them with pink.
-
The following alert message displays in the browser.
To generate this message, the form has assembled the following snippets of text. Zen offers default values for these items, so there is no need for you to do anything for the default message to appear. However, if you wish you can customize them to any extent:
-
-
For each control that has its
required attribute set to true, but contains no entry, the message lists the control’s
label followed by the control’s
requiredMessage text.
-
For each control that contains an invalid value, the message lists the control’s
label followed by the control’s
invalidMessage text.
-
Click
OK to dismiss the alert message box.
-
The invalid controls remain highlighted until the user edits them and resubmits the form.
The request to submit the contents of a form can be triggered in one of two ways:
-
-
The application calls the
submit method of the form object in response to a user event:
When a form is submitted, the values of the controls in the form are sent to the server and the
%OnSubmit callback method of the page containing the form is called. Note that the
%OnSubmit callback method is that of the page that contains the form, not of the form itself or of any component on the form.
%OnSubmit receives an instance of a special
%ZEN.Submit object that contains all the submitted values. Note that there is no page object available during submit processing. Zen automatically handles the full details of the submit operation, including invoking server callbacks and error processing. All forms are submitted using the HTTP POST submission method.
Note that using the setting ENCODED=2 disables the <form> component, because ENCODED=2 removes all unencrypted parameters from the url.
If you are interested in details of how Zen executes a submit operation, the following table lists the internal events in sequence, organized by user viewpoint, browser-based execution, and server-side execution. Most of the communication details are handled by the CSP technology underlying Zen. For background information, see the
Zen Client and Server chapter in
Using Zen.
Form Submit Sequence
|
User Viewpoint |
In the Browser |
On the Server |
1 |
User clicks a button to invoke form submit |
|
|
2 |
|
Post control values to the server via the HTTP POST mechanism |
|
3 |
|
|
Deserialize data from the client |
4 |
|
|
Reconstruct DOM based on new control values |
5 |
|
|
Run the server-side code for the page |
6 |
|
|
Update server-side DOM |
7 |
|
|
Generate new HTML page |
8 |
|
|
Send new HTML page as response to HTTP POST |
9 |
|
Render the HTML received in HTTP POST response |
|
10 |
|
Update client-side DOM to reflect changes made on the server |
|
11 |
User sees new page |
|
|
A <dynaForm> is a specialized type of form that dynamically injects control components into a group (or groups) on the Zen page. Layout is determined automatically by code internal to the <dynaForm>. The list of controls may be determined by the properties of an associated data controller, or by a callback method that generates a list of controls.
<dynaForm> has the following attributes:
The callback method identified by the
OnGetPropertyInfo attribute prepares additional controls to inject onto the form when it is displayed. If this method is defined in the page class, Zen invokes it when it first draws the form, automatically passing it the following parameters:
-
%Integer the next index number to apply to a control on the generated form. As the callback method injects additional controls on the form, it must increment this index value, as shown in the example below.
-
-
%String the current data model ID, for cases where the contents of a dynamic form vary by instance of the data model object. The method can get values from this object, or it can assign literal values.
To define additional controls, the method must place values into the input array, using two-part subscripts as follows:
-
The first subscript is the value of the
name attribute that was assigned to the corresponding control on the form. It is this
name (and not the
id) that identifies the control and associates it with a value. For example, the following array position stores the 1based index of the control’s ordinal position on the form:
-
The second subscript is the name of a property on the control object.
%type is a control property whose value identifies the type of the control. The names of other properties are listed in the
Zen Controls chapter, either in the
Control Attributes section or in topics about specific controls. For example, the following array position stores the value for the
attr attribute of the
name control:
The callback must return a
%Status data type. The following example shows a valid method signature and use of parameters and array subscripts:
Method GetInfo(pIndex As %Integer,
ByRef pInfo As %String,
pModelId As %String) As %Status
{
Set pInfo("Field1") = pIndex
Set pInfo("Field1","%type") = "textarea"
Set pInfo("Field2") = pIndex + 1
Set pInfo("Field2","label") = "Field 2"
Quit $$$OK
}
If the last control on the generated form comes from an embedded property with
n fields, your callback must increment past these generated controls by adding
n to the index number at the beginning of the method, before assigning the index to any controls. This convention is not necessary when the last generated control on the form comes from a simple data type, such as
%String,
%Boolean, or
%Numeric. The previous example shows the simple case, in which the method uses and increments the index provided.