jZeno

pure java web development

  • Increase font size
  • Default font size
  • Decrease font size

How to selectively bypass the rendering layer

E-mail Print PDF

Introduction

Any decent abstraction layer will try to solve as many details for you as possible. We have tried to make the presentation layer of jZeno easy to use and take away details such as JavaScript/CSS/HTML/DOM/etc... At the same time we recognise that there will allways be situations where you want to take full control over these details (i.e. bypass the abstraction layer). Therefore It should be extremely simple to bypass the regular rendering model. This section explains how you can create a type of custom component that has full control over rendering.

We also think the class of applications we are targeting with jZeno only have a small number of cases where this is necessary.

 

CustomRenderingComponent

In this example we'll create a component that allows an external web site to be visualized inside of a jZeno application. The HTML required to do this is extremely simple, we simple need to create an IFRAME. The example has been kept simple for didactical reasons, but you can readily imagine how this component could have more properties in a more realistic version. Basically you need to derive your component from CustomRenderingComponent.

 

package howto.bypass;
	
import net.sj.jzeno.echo.component.CustomRenderingComponent;
	
public class ExternalSiteViewer extends CustomRenderingComponent {
	private String url = "http://www.google.com";
	
	// We still need the 2 required constructors for dynamic components.
	public ExternalSiteViewer() {
		this(null,null,null);
	}
	
	public ExternalSiteViewer(Class beanClass, String propertyPath, String constructionHints) {
		super(beanClass, propertyPath, "");
		EchoSupport.executeHints(this, constructionHints);
	}
	
	public void setUrl(String url) {
		String oldUrl = this.url;
		this.url = url;
		firePropertyChange("url", oldUrl, url);
	}
	
	public String getUrl() {
		return url;
	}
	
	// Here you get to render your component into HTML.
	String getHtml() {
		return "<iframe src=\"" + getUrl() + 
		       "\" width=\"800\" height=\"600\" frameborder=\"0\"/>";
	}
	
	
	String getJavascript() { return null; }
	
	String getJavascriptLibrary() { return null; }

	void update(String input) {}
}
	

 

In the example we implement 4 important functions :

  • getHtml : This method must return a string containing the HTML rendering of the component.
  • getJavascript : This method may return a string containing javascript that will be executed after rendering to the browser. It may also return null if that is not required.
  • getJavascriptLibrary : This method may return a string contain javascript function for use inside of the getHtml() or getJavascript() operation. It may also return null if that is not required. The javascript library will only be sent once to the browser.
  • update : This method can be used to update the state of the component with information, sent from the browser.

It also imprtant to take a look at the setUrl() method. Specifically you need to add a similar firePropertyChange event to all of the properties that change the client side rendered component. The propertyChange event is detected by jZeno and is used to enlist your component to be re-rendered.

 

State synchronisation

In order to send state updates from the client browser back to the server you need to do 2 things :

  • In your getHtml method you should write javascript event handlers that (directly or indirectly - see below) sends information back to the server. In order to achieve this, you should call the createUpdateScript() method that is available in your component (protected method inhereted from baseclass). This function accepts 2 arguments :
    1. A JavaScript expression that determines the update value to be sent (don't forget to quote javascript string constants).
    2. A boolean indicating wether or not direct update is necessary. False will result in an update that is queued on the client browser until some other event triggers a roundtrip to the server. True will result in an immediate synchronisation with the server (POSTs updates to the server)
  • Implement the update method to receive the (string) information that you have sent from the client and use it to update your component/trigger an event handler, etc... For triggering an event you should use the fireActionEvent() method, inherited from the baseclass.

 

 

package howto.bypass;
	
import net.sj.jzeno.echo.component.CustomRenderingComponent;
	
public class MyButton extends CustomRenderingComponent {
	public MyButton() {
		this(null,null,null);
	}
	
	public MyButton(Class beanClass, String propertyPath, String constructionHints) {
		super(beanClass, propertyPath, "");
		EchoSupport.executeHints(this, constructionHints);
	}
		
	String getHtml() {
		return "<input type=\"button\" onclick=\"" +
		       createUpdateScript("'action'",true) +
		       "\" />";
	}

	void update(String input) {
		if(input.equalsIgnoreCase("action")) {
			fireActionEvent();
		}
	}
	
	String getJavascript() { return null; }
	
	String getJavascriptLibrary() { return null; }
}

 

Some more tips

  • All CustomRenderingComponents are dynamic components and as such have data binding (get/setValue), dynamic event handling (fireActionEvent/setActionCommand/..), support for validation (addValidator/isValid/..), etc...
  • Any property that you implement on your component must fire call the firePropertyChanged() method if that property affects the visual representation of the component. This is necessary to notify the rendering engine that re-rendering this component is necessary.If you forget to do this, you will experience situations where you component is not drawn correctly in the client's browser, but all of the logic in the code that uses your CustomRenderingComponent is correct.