|
||||||||||
| HomePage :: Categories :: PageIndex :: RecentChanges :: RecentlyCommented :: Login/Register |
| Syntax | Behavior |
| ${mypackage.MyClass.myMethod(args...)} | to invoke a static method |
| ${mypackage.MyClass[].myMethod(args...)} | to create a new instance of the class on each evaluation |
| ${mypackage.MyClass[referenceName].myMethod(args...)} | for a named object instance |
| ${myMethod[referenceName](args...)} | for a method contained within the invoking page |
| ${[referenceName].myMethod(args...)} | for a method contained within the class instance referred to by the reference name. |
| Binding | Usage |
| XLabelBinding | A simple binding that is used for read-only Label components |
| XTextBinding | Bind a TextComponent to a data model value/node. The binding allows a model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model. This binding is designed to be used by components such as Edit fields, TextComponents or TextFields |
| XListBinding | Bind a list to a data model value/node. The binding allows a list model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model. This binding is designed to be used by list like components such as comboboxes or drop down lists. |
| XStateBinding | Bind a component's state to a data model value/node. The binding allows a model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model.This binding is designed to be used by components such as Checkboxes.This state change does not affect the content displayed by the component |




The data source configuration reference in the startup file The configuration file is loaded by the application and processed as it contains a list of data sources. There may be one or more data sources depending on the needs of your application, but again this two stage configuration adds flexibility by allowing otherwise disparate data sources to be cleanly mapped into the data model. For examples, the specification required for database access differs considerably from the simple setup required for static data. The example below shows one such very simple configuration file.
The data source configuration file (##simpledataset.xml##) The file simply points of the another file which contains the static data. In a more complete application there may be several datasources of varying types and each would be listed in the data sources configuration file as a ##DataSource## entry. The actual data file is also relatively simple. The important attributes to note are the id attribute and the value attribute.
The static data file (##simpledata.xml##) The id field is important as it is this attribute that is used to identify a node in the model. The path used to access an individual node is just the list of all the node ids back to the root node separated by the / character. This concept should be familiar to anyone who has used a filesystem being vary like the paths that operating systems use. As mentioned above, these configuration files are setup by Carousel and Carousel also provides editing facilities so you will rarely need to interact with the files directly. The files and paths to the configuration files can also be chosen as part of the project settings. **How the bindings work** The data bindings work on the simple principle that any change made by the user to the user interface component will cause the associated model node to be updated and made consistent. Similarly any change to the model will be propagated back to any user interface components that are bound to the model node. Carousel uses some extra steps to eliminate unnecessary work and unnecessary updates but the key update occurs during page transitions and these are discussed in a later section (“Update on page display” on page 143). When the model is updated one possibility would be to dynamically update the user interface to reflect the latest data, however this would quickly get out of hand if multiple nodes were updated. Since there is no obvious point at which we can say that an internal (to the application) is complete the update from the model side is not as aggressive as the saving of user interface data and more is left to the discretion of the programmer. From the user interface side the bindings listen for any user input or change in state. Each binding is aware of the type of input events that affect its data and add the appropriate listeners. As these listeners are triggered they save the data to the model. To accommodate the differences between user interface components and the types of updates they require Carousel includes a range of binding types and adapters that can act as intermediaries between bindings and the various types of model node. All of these bindings share a common superclass and form a hierarchy. Carousel constructs the appropriate bindings by mapping the model data node or data source to the target user interface component. To reiterate the way in which bindings are setup In XML we again show a binding for an edit field:
A simple data binding for an edit field For more complex data types a one to one relationship may not exist between the data type and the user interface component. Indeed there may not be a single data binding type that can perform such binding so Carousel allows chaining of data bindings and the use of adapters. For example, in the case of a type such as a table it would not be realistic to try and display a table in an edit field yet we might want to display a particular field value. With the aforementioned chaining Carousel can handle such situations and fortunately it can even set up these bindings for you automatically. The point of all of this is that in using bindings you are not constrained to using simple types or simple relationships, you can build and use a wide variety of data. **Separating data from state** We started by considering the binding of static data as read-only data. Since the data source is read-only it is not possible to save the modified data to the same node and therefore Carousel creates a new node for the data by appending the source path to the ##‘xui_state’## node. Thus where the above example sourced its data from the ‘person/name’ node the result is saved to ##‘xui_state/person/name’##. Some controls such as drop-down lists produce selection information (such as the index of the selected item) that do not fit well with the input data (the items it the list), particularly if the input data is considered static or read-only. Again this data is saved to the ‘xui_state’ node. For the most part you need not be aware of the output node as it is an internal detail of the bindings. In the above example the output path was not specified as Carousel automatically configures the path by appending the source path to the ##xui_state## node to give an output path of ##xui_state/person/name## in the case of the last example. Normally the output values and state information (e.g. the selection index in a list) associated with a data bound component are saved to the ##xui_state## node. The output path can be specified explicitly in the binding or XUI can create it automatically by appending the source path to the path ##/xui_state##, note however that this does not occur if the source path begins with a forward slash (##/##). Thus in the example above if the source path had been ##‘/person/name’##, instead of ‘person/name’, then the output path would be ##‘/person/name’## and the binding would save the user data back to the same node in the model. **Setting up a binding** Setting up a binding in XML is pretty straightforward as has been shown above. The bindings are specified in the Data section of the page:
Some more bindings While Carousel setups the appropriate binding if a page is constructed from XML the story in Java is a little more complicated as the type of binding must be chosen explicitly:
Adding a binding in Java In this example we know that the bound user-interface components are edit fields and therefore we use the XTextBinding binding type. Some of the bindings provided by Carousel are: Binding Usage XLabelBinding A simple binding that is used for read-only Label components XTextBinding Bind a TextComponent to a data model value/node. The binding allows a model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model. This binding is designed to be used by components such as Edit fields, TextComponents or TextFields XListBinding Bind a list to a data model value/node. The binding allows a list model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model. This binding is designed to be used by list like components such as comboboxes or drop down lists. XStateBinding Bind a component's state to a data model value/node. The binding allows a model node to linked to a UI component so that it can be refreshed when new data is written to the model or conversely when the UI component needs to write data to the model. This binding is designed to be used by components such as Checkboxes. This state change does not affect the content displayed by the component Some data binding types Happily once the bindings have been constructed there is no difference between bindings constructed via Java or via XML. Carousel contains other binding types some of which support features such as localization of lists, conversion of physical dimensions and filtering of data. Please refer to the API documentation for further details. **Update on page display** Carousel tries to ensure that the data visible on screen is always consistent with what is stored in the model. One of the most important times for this is during page transition. When a page is shown, its data must be updated and equally if any page had been visible its data must also be saved. When switching pages Carousel goes through a number of steps to ensure that the displayed data is consistent with the model state. The steps are as follows: 1) The current page's data is saved by calling ##saveBoundComponentValues()##. 2) The current page is marked as deactivated and ##pageDeactivated()## is called. 3) The new page is added to the target container. 4) The new page's bindings are updated by calling ##updateBindings##. This method will evaluate each binding's source and output attributes and invoke any callback methods. This gives the page the opportunity to modify its bindings prior to display. 5) The new page's values are updated by invoking the ##updateBoundComponentValues## method 6) The new page is marked as activated and ##pageActivated()## is called. You can interact with the update by implementing the pageActivated() and pageDeactivated() methods, or you can invoke the other methods to update the model at any point in the life of the application. In most cases however the data bindings take care of all the work needed to ensure the displayed data is up to date. **Saving values** As mentioned above a page's data is saved upon page transitions but this is not always sufficient and it may be necessary to explicitly save the data at some point. This can be accomplished by calling the page's saveBoundComponentValues() method. This method iterates all the data bindings on a page and updates the associated model nodes. **Updating values** Just as you may want explicit control of saving you may want to force updates to a page's data. Updates can be forced via the updateBoundComponentValues() method. This method can be invoked at just about any time and you may need to do so anytime you have a calculation of a piece of business logic that writes (or loads) data to the model. Source and output nodes Each data binding has a data source and optionally an output node. The role of the source node is to provide the data to be displayed by the bound component whereas the output node provides a place to save the user value or selection state. In some cases it would not be desirable to save a user value to the same node as the input as this would either destroy the original value or modify the input dataset. By default the output node defaults to the source node such that its path is 'xui_state/<source_node>'. Furthermore all output nodes are appended to the 'xui_state' node. The distinction between source and output nodes is a little gray. In some cases like a read only list it would not make sense to write selection information back to the list source so clearly in this the source and output should be maintained separate. In the case of an edit field things may not be so clear as the selection state (the caret position) is rarely of interest and one would therefore expect the input and output nodes to be the same. Carousel can handle both these situations but ultimately you remain in control and can override the default behavior by explicitly naming the nodes. **Callbacks** Consider for a moment the case of reusable forms, say for example the case of a contact details form contain names, addresses and phone numbers. Such a form is pretty simple and from the above documentation you should be able to setup bindings for such a form without too much difficulty. However, things start to get a little more interesting if the form is reused (as is often the case for something as ubiquitous as an address form). If say in the case of a financial application you had joint application for a mortgage then each person would have to fill out and address form. Now we could accomplish this by duplicating the form or by showing the form, capturing the data and then moving it to the right place but it would be a lot of work for little gain. In Carousel there is another approach. Carousel supports dynamic bindings that can be updated during the life of an application. At the heart of a dynamic binding is the callback. The syntax for the callbacks is:
An embedded callback method where myMethod is the name of a public method in the page's class. The method can be argumentless or it can have String or integer arguments. The path can also contain multiple expressions and fixed elements, for example
A callback substituting a path element where getUserName evaluates to some sort of user ID that exists (or will exist) in the model. The callback syntax is loosely based on expression language syntax and is explained more fully in“Evaluated attributes and helpers” on page 237. **Dynamic bindings** Using the above technique it is possible to do things like switching users when showing user details on a page. All that needs to be done is have the getCurrentUser return a different ID and invoke the updateBindings method (which is invoked implicitly during page transitions anyhow). Thus, as you process one applicant for the aforementioned joint mortgage application you can set the appropriate customer/user ID and then as the application process progresses you can begin the data capture process for the second user by updating the ID and redisplaying the form. Since the evaluated path has changed by the time the form is redisplayed the components on the form will be bound to different locations. **Adapters** Sometimes it is not possible to have a direct correlation between the model's data structure and a binding’s use of that data. In such cases an intermediate adaptor is used. Normally the data factory takes care of the instantiation of adapters, but in some circumstances, for example when coding a specific feature in Java, it may be necessary to construct an adaptor. The role of the adaptor is to allow the specification of bindings so that only the target component and the data source need be specified, i.e. the endpoints. The binding factory can then take care of all the rest. Adapters are frequently used where a complex model node such as a table or list node are being mapped to a simple output type like an edit field. In most cases you need not be aware of the adapter’s role in a binding but in some circumstances you may want to modify some of the adapter’s properties. To do this you must use Java as the XML interface does not support such properties. **Binding tables** Using a databse table in a UI component such as a JTable is straightforward, here are some examples:
Some sample table bindings For now the output values can be ignored, they are used to save the state data of the bindings (the index of the selected record). **Selecting tables** For more complex queries it is possible to dynamically query a database, but to do this you need to use Java code and setup both the model node and the binding yourself. A new database table can be configured as follows:
Select DISTINCT values from a table Here the code starts by retrieving the basic 'Voltages' table and then sets some additional attributes to order the table by the 'ID' field and sets it to retrieve only the distinct rows. The data is not pulled from the database till the retrieve method is called. It is worth noting that of course once the node is in the model you do not need to repeat the process and can instead just bind components to the node as needed. Sometimes it is not desirable to predefine a table and in such cases a completely new database model node can be prepared in Java code.
Setup a database query The fields to retrieve and the where clause are specified with this approach. As an alternative the complete SQL statement can also be specified using the setSqlStatement method. Once the tables has been retrieved it can be used in a UI component by updating the component's bindings
Set and refresh a table control **Linking components** To build a form using multiple UI components bound to a database table we can use the output attribute of the bindings. The output attribute is used to save the state data of the bindings. For components such as list bindings these attributes include the selected item in the list. When displaying a list the binding will try to have the list display the last selected item (the value pointed to by the output node). Tables and other components that use the database bindings similarly save their state to the output node. The table binding in particular saves (by default) the current row index of the table. Therefore by changing the selected row on a bound table the selected row on the underlying database table is updated. Then if the UI components bind to the same output path they should all refer to the same table row. An example of this is the page described below:
A complete example of table usage In the above example three tabs are shown, on the third a table an edit field and a drop down list are all bound to the same table node and each outputs to the same path. Changing the selection on the table causes the selection on the edit field and combo box to be updated. This update occurs because the table handles the 'ListSelection' event and in doing so causes the 'updateBoundComponentValues' method to be called. This method updates all the UI components bound to the model. The output attribute specifies the path within the model to which the selection attributes are saved. These attributes include the row selection index of a table control. Normally the output of a Carousel model is saved to a specific subpath in the model, the 'xui_state' node and whenever an output path is specified it is automatically appended to this node. In some cases it is desirable to refer to another source for this selection state. By specifying the absolute path within the model it is possible to address such paths rather than just the children of the 'xui_state' node. In the case of a master-child setup it would be possible to link table selections using such a technique, the child table's output would be set to the master table's source path in such a scenario, e.g.
Example linking of bindings Finally, Carousel as a Java based system is by default case sensitive. This case sensitivity also applies to database look-ups. SQL in contrast can be configured to be case in-sensitive. To help support this we allow look-up of fields in both case sensitive and case in-sensitive modes. The case sensitivity is set with a startup parameter in the startup.properties file
Flag case sensitivity **Advanced attribute evaluation and libraries** One of the goals XUI is to help promote an MVC architecture. The Data Binding and Event Binding helps make this clean separation by putting the UI declaration in XML, separate from the business logic which is implemented in Java. One limitation of this mechanism is that the custom logic had to be routed through event handlers in classes derived from the XPage component. This dependency on a UI component was undesirable in some cases and made it a little more difficult to implement libraries of reusable functions than we would have liked. So, as of version 2.0 we have extended the attribute and event bindings to solve this problem. **Evaluated attributes** Attributes within a XUI page can be specified dynamically, for example
Basic attribute evaluation
The code ${getContent()} is an expression that is evaluated at runtime each time the expression is encountered. For a page component declaration the expression is evaluated when the page is loaded but expressions can be used in other locations such as within the data model, the data bindings, the validations or the event bindings.
An evaluated attribute's implementing method is by default in the owner page such that a reference like ${myMethod()},which would evaluate to a method in the current page with a signature like:Method signature
In XUI 2.0 The attributes can also be defined in classes other than the current page or classes derived from XPage. The syntax for such expressions is as follows:
Syntax Behavior
${mypackage.MyClass.myMethod(args...)} to invoke a static method
${mypackage.MyClass[].myMethod(args...)} to create a new instance of the class on each evaluation
${mypackage.MyClass[referenceName].myMethod(args...)} for a named object instance
${myMethod[referenceName](args...)} for a method contained within the invoking page
${[referenceName].myMethod(args...)} for a method contained within the class instance referred to by the reference name.
Extended attribute declarations
where mypackage is the name of the Java package containing the class MyClass. The value of referenceName is a user defined value that identifies the instance of the class. The application instantiates an instance of the class when the expression is first encountered and thereafter maintains the instance with each subsequent call retrieving the same instance of the class. As in early versions, the method call can also contain zero or more arguments.
What this means in practice is that the class or classes implementing an applications business logic no longer need be derived from XPage. In this way it is possible to build libraries of reusable functions. Lets look at an example: