ShowTable of Contents
Introduction
This article is part of the
XPages Extensibility API Developers Guide.
A Client Simple Action is an easy way for Developers to code a reusable piece of business logic (written in JavaScript) in an XPages application to be executed in the Web Browser when the associated event on a user interface component is fired.
Simple Actions are available in Domino Designer from a drop down list in the events tab for an XPages applications. There are Server and Client events. Server events execute when as request is made to the Server and is the actions associated with components are processed by the XPages Runtime, for example, an onclick event for a Submit button, or a PostQuerySave event on a Data Source. Client events execute in the Web Browser.
In addition, any properties that are configurable for the Client Simple Action can be set in a property sheet for the Simple Action.
Background
In XPages (and JavaServer Faces) a Method Binding is an object that can be used to call a method on an instance of a Class that is identified by evaluating the leading portion of a method binding expression (for example #{customerList.data} - where customerList is a reference to an instance of a managed bean (MyCustomerList) that contains a list of customers, and data, is mapped to the getData() method.
For XPages Client Simple Actions, the method should return the JavaScript code that represents the piece of business logic is to be executed in response to an event in the Web Browser.
There are 3 key methods in for a method binding :-
- getExpressionString() return the expression String from which this MethodBinding was built
- getType(FacesContext context) the Java class representing the return type from the method identified by this method binding
- invoke(FacesContext context, java.lang.Object[] params) the return value resulting from a call to the method identified by this method binding expression, passing it the specified parameters, relative to the specified FacesContext.
The XPages Extensibility API provides a Class to support building Client Side Action extensions.
com.ibm.xsp.actions.client.AbstractClientSimpleAction
Since Client Simple Actions return a String of JavaScript, getType() return String, the getType() method in this abstract class overrides getType() and returns String by default, so there is no need to override it in any class that extends it. getExpressionString() is also overridden to simply return the empty string, as we are not really interested in overriding that method since the resulkt of the invoke() method that we do want to implement will return the JavaScript for the method.
A Dojo Effect Client Side Logic
As an example, the piece of JavaScript business logic is a Dojo Fade Effect, in this case, there will be two, fadeIn and fadeOut. The hand-coded JavaScript would be something similar to,
var _id = dojo.byId("#{id:image1}");
var fadeArgs = {
node: _id
};
dojo.fadeIn(fadeArgs).play();
where node is the Web Browser DOM node to fade in. The fade out effect is almost identical, except that the dojo funciton name is fadeOut. Also, there are other argument for the faded effect that can be set, duration - how long the fade effect should take, and easing, the animation effect, i.e start fading slowly and then speed up, or vice versa.
Getting Started
Perform this work in the Java perspective on Domino Designer (follow the steps in
Creating_an_XPages_Library. At the end of the article, you should have a project layout similar to Figure 1 below.
Figure 1. XPages extension Library layout for a Simple Action
Create the Simple Action Classes
Start be creating an Abstract Class to represent the Simple Action that extends AbstractClientSimpleAction. This is an abstract class that will be extended by the two classes that will represent the Client Simple Actions, fadeIn and fadeOut which will simply provide the name of the dojo fade effect function.
public abstract class AbstractFadeClientAction extends AbstractClientSimpleAction {
Then create variables to store the parameters the of the Client Simple action that will store values that can be uses as parameters for the JavaScript function.
private String _node; // The domNode or node id to fade
private Integer _duration; // How long, in milliseconds, should the fade take
private String _easing; // An easing function to apply to the effect
Create getters and setters for each of the properties - this example shows the node property.
public String getNode() {
if (_node == null) {
ValueBinding vb = getValueBinding("node");
if (vb != null) {
return (String) vb.getValue(FacesContext.getCurrentInstance());
}
}
return _node;
}
public void setNode(String node) {
_node = node;
}
Do the same for duration and easing.
Specify the two methods that the Client Simple Actions classes must override. Note that the opacity is used to reset the image opacity at the start of the actions, so the action can be repeatedly run (without requiring an explicti fade in, for the purposes of demonstration).
public abstract String getFadeAction();
public abstract int getStartingOpacity();
Override invoke()
Now add the method that will generate the JavaScript that is to be executed in the Web Browser when the simple action is called. When the page is rendered, XPages will take the JavaScript returned by this method and add it to a JavaScript function that will be attached to the onclick event for the button.
@Override
public Object invoke(FacesContext context, Object[] params)
throws EvaluationException, MethodNotFoundException {
StringBuilder b = new StringBuilder(256);
String id = getNodeClientId(context,getNode());
//dojo.style("#{id:image1}", "opacity", "0");
b.append("dojo.style(\"");
JSUtil.appendJavaScriptString(b, id); // #{id:<id>}
b.append("\", \"opacity\", \"");
b.append(Integer.toString(this.getStartingOpacity()));
b.append("\");\n");
//var _id = dojo.byId("#{id:image1}");
b.append("var _id = dojo.byId(\"");
JSUtil.appendJavaScriptString(b, id); //#{id:image1}
b.append("\");\n");
b.append("var fadeArgs = {\n");
b.append("node: _id\n");
b.append("};\n");
b.append("dojo." + this.getFadeAction() + "(fadeArgs).play();");
return b.toString();
}
Add a helper method to get the Client ID that will be generated for the node that will the target of the Client Simple Action.
//Return the client id for a JSF component or generate an exception if it doesn't exist
protected String getNodeClientId(FacesContext context, String componentId) {
if(null != componentId && "" != componentId) {
// Look for a component in the JSF hierarchy
UIComponent c = FacesUtil.getComponentFor(getComponent(), componentId);
if(c!=null) {
return c.getClientId(context);
}
}
throw new FacesExceptionEx(
StringUtil.format("Unknown component id {0} in client side simple action",
componentId));
}
}
Now create the class for the Client Simple Action that will perform the fade in effect.
package com.ibm.xsp.example;
public class DojoFadeIn extends AbstractFadeClientAction {
public String getFadeAction(){
return "fadeIn";
}
public int getStartingOpacity(){
return 0;
}
}
And similarly for the fade out effect.
package com.ibm.xsp.example;
public class DojoFadeOut extends AbstractFadeClientAction {
public String getFadeAction(){
return "fadeOut";
}
public int getStartingOpacity(){
return 100;
}
}
The last piece of code it the XPages Library extension. Agian, see the appropriate steps in
Creating_an_XPages_Library for how to do this.
package com.ibm.xsp.example;
import com.ibm.xsp.library.AbstractXspLibrary;
public class SimpleActionExampleLibrary extends AbstractXspLibrary {
public String getLibraryId() {
return "com.ibm.xsp.example.SimpleActionExampleLibrary.library";
}
@Override
public String[] getFacesConfigFiles() {
return super.getFacesConfigFiles();
}
@Override
public String getPluginId() {
return "com.ibm.xsp.simpleactionexample";
}
@Override
public String getTagVersion() {
return "1.0.0";
}
@Override
public String[] getXspConfigFiles() {
// TODO Auto-generated method stub
return new String[] {"META-INF/example-actions.xsp-config"};
}
}
Create the xsp-config File
Finally, create the xsp-config that describes the Client Simple Action and save it in the META-INF folder under the src directory.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<!--
Define a new namespace for Demos.
-->
<faces-config-extension>
<namespace-uri>http://www.ibm.com/xsp/demo</namespace-uri>
<default-prefix>demo</default-prefix>
</faces-config-extension>
<group>
<group-type>com.ibm.xsp.example.simpleaction.client.dojo</group-type>
<property>
<description>Reference to the component</description>
<display-name>Node</display-name>
<property-name>node</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<description>Easing</description>
<display-name>Easing</display-name>
<property-name>easing</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<description>Duration</description>
<display-name>Duration</display-name>
<property-name>duration</property-name>
<property-class>int</property-class>
<property-extension>
<default-value>-1</default-value>
</property-extension>
</property>
</group>
<complex-type>
<description>Apply a Dojo fade out effect to a component.</description>
<display-name>Dojo fade out effect</display-name>
<complex-class>com.ibm.xsp.example.DojoFadeOut</complex-class>
<complex-id>com.ibm.xsp.example.FadeOut</complex-id>
<group-type-ref>com.ibm.xsp.example.simpleaction.client.dojo</group-type-ref>
<property>
<description>Ignore this Property</description>
<display-name>Ignore</display-name>
<property-name>ignore</property-name>
<property-class>int</property-class>
<property-extension>
<default-value>-1</default-value>
</property-extension>
</property>
<complex-extension>
<base-complex-id>simpleActionInterface</base-complex-id>
<tag-name>dojoFadeOut</tag-name>
<designer-extension>
<action-type>client</action-type>
<category>Demo Dojo Effects</category>
</designer-extension>
</complex-extension>
</complex-type>
<complex-type>
<description>Apply a Dojo fade in effect to a component.</description>
<display-name>Dojo fade in effect</display-name>
<complex-class>com.ibm.xsp.example.DojoFadeIn</complex-class>
<complex-id>com.ibm.xsp.example.DojoFadeIn</complex-id>
<group-type-ref>com.ibm.xsp.example.simpleaction.client.dojo</group-type-ref>
<property>
<description>Ignore this Property</description>
<display-name>Ignore</display-name>
<property-name>ignore</property-name>
<property-class>int</property-class>
<property-extension>
<default-value>-1</default-value>
</property-extension>
</property>
<complex-extension>
<base-complex-id>simpleActionInterface</base-complex-id>
<tag-name>dojoFadeIn</tag-name>
<designer-extension>
<action-type>client</action-type>
<category>Demo Dojo Effects</category>
</designer-extension>
</complex-extension>
</complex-type>
</faces-config>
Deploy
First, build an Feature based on the Plugin just created, and then create an UpdateSite based on the Feature, see
Creating_an_XPages_Library .
Deploy the library to Designer, see
Installing_an_XPages_Library_into_Designer
Deploy the library to your Domino Server, see
Deploying_XPage_Libraries
Build Application
Create a simple XPage with an image and two buttons.
Add dojo effect to each of the buttons by choosing the Events -> Client tab and selecting Add Action. Enter the name of the image (image1 in this case) as the target node of
Note that you may have to add the library to the application for the new Client Simple Actions to appear in the Designer menu. Goto Application Properties -> Advanced and select the ClientSimpleActionLibrary library.
Test
Run your XPage application and when you click on the Out button, you will see the target image fade befor your eyes.
Conclusion
While tis tutorial covered a very simple use case for client-side JavaScript based business logic, Client Simple Actions can provide a very convenient and consistent way for Application Developer teams to implement and deploy client side business logic.