Please note: the following example reflects latest changes to Echo3, so please use the latest build from Echo3Go.
Below is an example which should guide you through the process of creating an simple interactive Echo3-component.
How to create a Spinner-Component for Echo3?
To use the following component, please create a package jfix.echo.spinner in your project and store the files below within it (exception is the last file, which needs to go into /META-INF/... of your classpath).
Please note: Depending on your IDE / build-process, ALL (compiled) files mentioned below must end up in directories below /WEB-INF/classes/.
1. Create a Java-Component (/jfix/echo/spinner/Spinner.java)
package jfix.echo.spinner;
import nextapp.echo.app.Component;
public class Spinner extends Component {
private int value;
public Spinner() {
this(0);
}
public Spinner(int initialValue) {
setValue(initialValue);
}
public int getValue() {
return value;
}
public void setValue(int newValue) {
int oldValue = value;
value = newValue;
firePropertyChange("value", oldValue, newValue);
}
public void processInput(String inputName, Object inputValue) {
super.processInput(inputName, inputValue);
if ("value".equals(inputName)) {
setValue((Integer) inputValue);
}
}
}
2. Create a server-side-peer for the component, which synchronizes the state of the component to the client-side (/jfix/echo/spinner/SpinnerPeer.java)
package jfix.echo.spinner;
import nextapp.echo.app.Component;
import nextapp.echo.app.update.ClientUpdateManager;
import nextapp.echo.app.util.Context;
import nextapp.echo.webcontainer.AbstractComponentSynchronizePeer;
import nextapp.echo.webcontainer.ServerMessage;
import nextapp.echo.webcontainer.Service;
import nextapp.echo.webcontainer.WebContainerServlet;
import nextapp.echo.webcontainer.service.JavaScriptService;
public class SpinnerPeer extends AbstractComponentSynchronizePeer {
private static final Service SPIN_BUTTON_SERVICE = JavaScriptService
.forResource("JFixSpinner", "jfix/echo/spinner/Spinner.js");
static {
WebContainerServlet.getServiceRegistry().add(SPIN_BUTTON_SERVICE);
}
public SpinnerPeer() {
addOutputProperty("value");
}
public void init(Context context, Component component) {
super.init(context, component);
ServerMessage serverMessage = (ServerMessage) context
.get(ServerMessage.class);
serverMessage.addLibrary(SPIN_BUTTON_SERVICE.getId());
}
public String getClientComponentType(boolean shortType) {
return "JFixSpinner";
}
public Class getComponentClass() {
return Spinner.class;
}
public Object getOutputProperty(Context context, Component component,
String propertyName, int propertyIndex) {
if ("value".equals(propertyName)) {
return ((Spinner) component).getValue();
}
return super.getOutputProperty(context, component, propertyName,
propertyIndex);
}
public Class getInputPropertyClass(String propertyName) {
if ("value".equals(propertyName)) {
return Integer.class;
}
return super.getInputPropertyClass(propertyName);
}
public void storeInputProperty(Context context, Component component,
String propertyName, int propertyIndex, Object newValue) {
if ("value".equals(propertyName)) {
ClientUpdateManager clientUpdateManager = (ClientUpdateManager) context
.get(ClientUpdateManager.class);
clientUpdateManager.setComponentProperty(component, "value",
newValue);
}
}
}
3. Create a client-side represantation of the component (/jfix/echo/spinner/Spinner.js)
JFixSpinButton = Core.extend(Echo.Component, {
$load: function() {
Echo.ComponentFactory.registerType("JFixSpinner", this);
},
componentType: "JFixSpinner"
});
JFixSpinButton.Peer = Core.extend(Echo.Render.ComponentSync, {
$load: function() {
Echo.Render.registerPeer("JFixSpinner", this);
},
_addOffset: function(offset) {
var value = parseInt(this._inputField.value);
if(!isNaN(value)) {
value += offset;
this._inputField.value = value;
this.component.set("value", value);
} else {
this._inputField.value = 0;
this.component.set("value", 0);
}
},
_processDecrementClick: function(e) {
this._addOffset(-1);
},
_processIncrementClick: function(e) {
this._addOffset(+1);
},
_processTextChange: function(e) {
this._addOffset(0);
},
renderAdd: function(update, parentElement) {
this._decrementElement = document.createElement("span");
this._decrementElement.style.cursor = "pointer";
this._decrementElement.appendChild(document.createTextNode("<"));
this._inputField = document.createElement("input");
this._inputField.type = "text";
this._inputField.size = 4;
this._inputField.style.textAlign = "right";
this._incrementElement = document.createElement("span");
this._incrementElement.style.cursor = "pointer";
this._incrementElement.appendChild(document.createTextNode(">"));
this._divElement = document.createElement("div");
this._divElement.appendChild(this._decrementElement);
this._divElement.appendChild(this._inputField);
this._divElement.appendChild(this._incrementElement);
parentElement.appendChild(this._divElement);
Core.Web.Event.add(this._decrementElement, "click",
Core.method(this, this._processDecrementClick), false);
Core.Web.Event.add(this._incrementElement, "click",
Core.method(this, this._processIncrementClick), false);
Core.Web.Event.add(this._inputField, "change",
Core.method(this, this._processTextChange), false);
this.renderUpdate(update);
},
renderUpdate: function(update) {
this._inputField.value = this.component.get("value");
},
renderDispose: function(update) {
Core.Web.Event.removeAll(this._decrementElement);
Core.Web.Event.removeAll(this._incrementElement);
Core.Web.Event.removeAll(this._inputField);
this._decrementElement = null;
this._inputField = null;
this._incrementElement = null;
this._divElement = null;
}
});
4. Create mapping between component and peer (/META-INF/nextapp/echo/SynchronizePeerBindings.properties)
jfix.echo.spinner.Spinner jfix.echo.spinner.SpinnerPeer
5. Now you can use the Spinner-component in your application like any other component
Column column = new Column();
column.add(new Spinner(10));