TWiki
>
WebXEO Web
>
XeoPrimer
>
XeoPrimerCustomWebComponent
(revision 6) (raw view)
Edit
Attach
Tags:
tag this topic
create new tag
,
view all tags
-- Main.PedroRio - 17 Feb 2011 ---+ XEO Web Components - Custom Component Creation XEO comes bundled with a set of predefined components to help you deal with various situations, but there will always be a situation where you need something so specific that you'll have to create your own custom component. To create and user a XEO Web Component you need to perform three steps (which will be explained in detail bellow): * Create an Implementation class * Create a Renderer Class * Register the component in the project _ ---+++ Implementation Class To create a new Custom XEO Web Component you'll need to define an implementation class which will be responsible for declaring the component properties and the component's logic. A custom component must extend the _netgest.bo.xwc.framework.components.XUIComponentBase_ class (or any class that extends from that one, including XEO's own components). When creating an implementation class you declare the set of properties of the components as class variables (of a particular type) and you can redefine some of the methods that are responsible for component logic (inherited from the _XUIComponent_ Base Class). Read the following paragraphs in order to know how to declare component properties. ---++++++ Component Properties Component properties allow you to configure a given component with a certain value (for a certain attribute it had), as such they are extremely useful when creating reusable components. The value of a property can be either supplied directly in the xml definition a viewer, or binded to a java bean property. Also, properties can have a notion of state (remembering their previous values). There are four different types of properties (properties are typed): * XUIBaseProperty (Simple property whose value can only be provided in the XML definition of the component) * XUIBindProperty (value can be binded to a java bean property) * XUIStatePropery (property has a state, remembers its previous values) * XUIStateBindPropertu (property has a state, remembers its previous value and can be binded to a java bean property) * XUIMethodBindPropery (property is binded to a method in a java bean) When declaring properties you'll also need to declare their data type (any type is valid). bellow is an example of declaring a property named text (of type String) and bindable to a java bean. <verbatim>private XUIBindProperty<String> text = new XUIBindProperty<String>("text", this, String.class);</verbatim> Notice the use of generics when declaring the property, but also the last parameter of the constructor is the class (this is required) also, the first parameter is the name of property as a string and the second parameter is the component itself. You could also use another constructor which allows you to supply a default value, like the following: <verbatim>private XUIBindProperty<String> text = new XUIBindProperty<String>("text", this, String.class, "Default Text");</verbatim> If declaring a simple property without any binding to the bean you can do the following: <verbatim>private XUIBaseProperty<String> other = new XUIBaseProperty<String>("other", this);</verbatim> When declaring a property, you should also declare a getter and a setter like the following (if it's a property which it not binded to a java bean property): <verbatim>public String getOther(){ return other.getValue(); } public void setOther(String newValue){ other.setValue(newValue); }</verbatim> and like the following if the property is binded to a java bean property. <verbatim>public void setText( String textExpr ) { this.text.setExpressionText(textExpr); } public String getText() { return this.text.getEvaluatedValue(); }</verbatim> Check the JavaDoc for further documentation on the API's for the types of properties. ( __Será que preciso de mais do que isto__) ---++++++ Component Behavior Inherited from the XUIComponentBase class are some methods that can be overridden to implement specific behavior of the custom component, like the following: * <em>preRender </em>- Method that's executed right before the component is rendered to the client allows you to make modifications to the component after the initialization. * _initComponent_ - Method that's executed after the component is created, it's used to perform the component initialization. * _wasStateChanged_ - Used to see if the component's state was changed, which may be used to determine in the component renderer if something should be done or not. ---+++ Renderer Class The renderer class is the class that's responsible for generating the HTML/CSS/Javascript necessary to render the component inside a viewer. Each renderer class must extend the _netgest.bo.xwc.framework.XUIRenderer_ class and override a few methods in order to work. One very important step when creating the renderer of a custom component is to create a placeholder for the component. The placeholder should be an html _div_ element having as identifier the identifier of the component (component identifiers are generated automatically if not declared in the xml definition).This is necessay so that when a component is updated XEO knows where to replace/update the content of your component. XEO's Renderer classes are usually declared as inner classes of the implementation class but they can be declared in a separate class as well. If declared inside the implementation class the should be declared as follows: <pre><verbatim>public static class XEOHTMLRenderer extends XUIRenderer { }</verbatim> </pre> The renderer class can have any other name, just be sure that when registering the component you use the same name (if using XEO Studio's Web Component Wizard, this step is not necessary). The skeleton of a renderer class is shown bellow. <verbatim>public static class XEOHTMLRenderer extends XUIRenderer { @Override public void encodeBegin(XUIComponentBase component) throws IOException {} @Override public void encodeEnd(XUIComponentBase component) throws IOException {} @Override public void decode(XUIComponentBase component) { super.decode(component); } }</verbatim> There are three main methods in a renderer class. The _encodeBegin_, _encodeEnd_ and _decode_ methods. The _encodeBegin_ and _encodeEnd_ methods are automatically invoked to render the start of the component and the end of the component (in between, if the component has any child components, their renderers will be invoked). The main ideia with these two methods is, in the _encodeBegin_ method to create a _div_ with the component's id and in the _encodeEnd_ method to close that div (after creating or before closing you can generate the html that will actually be the render of your component). The _decode_ method allows you to retrieve values sent from the component when the form inside the viewer is submitted to the server. In order to generate an output you have to write content to the XUIResponseWriter. For example, rendering a placeholder for the component and the string Hello World (in bold) could be done with the following code: <verbatim>@Override public void encodeBegin(XUIComponentBase component) throws IOException { XUIResponseWriter w = getResponseWriter(); w.startElement(HTMLTag.DIV , component ); w.writeAttribute( HTMLAttr.ID , component.getClientId(), null ); w.write(" <b> Hello World in </b> "); }</verbatim> and <verbatim>@Override public void encodeEnd(XUIComponentBase component) throws IOException { XUIResponseWriter w = getResponseWriter(); w.endElement( HTMLTag.DIV ); }</verbatim> Notice that the XUIResponseWriter has methods ( _startElement_, _endElement_, _writeAttribute_) that ease the creation of HTML tags (and auxiliar classes _HTMLTag_ and _HTMLAttr_ with static properties with names of all HTML tags and attributes so that you don't to write the tags yourself (although you can, as depicted in the code above)). <strong> ___ </strong> ---++++++ Adding JavaScript to a component If you need to add a piece of javascript code when rendering your component you can do it the following way: <verbatim>XUIScriptContext scriptContext = getRequestContext().getScriptContext(); StringBuilder sCode = new StringBuilder(); //Generate the javascript ... scriptContext.add(XUIScriptContext.POSITION_FOOTER, "SCRIPT_ID", sCode);</verbatim> You can add the script to the header or footer of the page. When adding full scripts (aka, making includes) you should add them using POSITION_HEADER so that they are available later on. When adding scripts to be executed, or functions that are invoked by buttons, links or alert messages The "SCRIPT_ID" parameter is the identifier of the script. If you want to replace an existing script you should add it with the same _id_ as the previous one. ---++++++ Using the component as a servlet It's possible to use the custom component as a servlet. Imagine that you want to create a component that displays a dinamically generated image in a viewer (such as a chart, for example). You can use the renderer class to generate an html <em>img </em>tag and set the source of the image to be the address of the component's servlet. In order for you to do that, the renderer class must implement the _netgest.bo.xwc.framework.XUIRendererServlet_ interface which only declares the following method: <verbatim>public void service(ServletRequest oRequest, ServletResponse oResponse, XUIComponentBase oComp ) throws IOException;</verbatim> The service method has access to the HttpRequest and HttpResponse just like an ordinary servlet, as such it can return the bytes representing a generated image. The service method also has access to the component, so that you can check property values and generate the response accordingly. In order to find the url to call the servlet of a component you can use the methods in the _netgest.bo.xwc.components.util.ComponentRenderUtils_ class which has the following methods: <verbatim>public static String getCompleteServletURL(XUIRequestContext reqContext, String clientID); public static String getServletURL(XUIRequestContext reqContext, String clientID);</verbatim> Each of the previous methods will return a string with the url to invoke the servlet for the component identifier passed as parameter (which, for any given component can reached through the _getClientId_ method) ---+++ Registering the component in the project If you use XEO Studio's wizard to create a XEO Web Component it will automatically be registered for you, but in case you have to make a change to anything after you created the component, here's how: If the root folder of your project's source code there should be a file named _XWVProjectComponents.xml_ which has the following structure: <verbatim><?xml version="1.0" encoding="UTF-8" standalone="no"?> <xwc:config xmlns:xwc="http://www.netgest.net/xeo/xwc"> <xwc:renderKits> <xwc:renderKit componentNamespace="my" name="XEOHTML"> <xwc:render for="myComponent">org.example.components.MyComponent$XEOHTMLRenderer</xwc:render> </xwc:renderKit> </xwc:renderKits> <xwc:components namespace="my"> <xwc:component name="myComponent"> <xwc:className>org.example.components.MyComponent</xwc:className> <xwc:description>Sample custom component</xwc:description> </xwc:component> </xwc:components> </xwc:config></verbatim> There are two entries for each registered component. One for the renderer class and another for the implementation class. Components are grouped by their namespace (as depicted in the XML declaration above, for the "myComponent" component registered in the "my" namespace). ---+++ Using the Component in a Viewer If you declared (and you should) the component in a custom namespace you need to declare that namespace in the xml definition of a viewer, like in the following example: <xvw:root xmlns:xvw="http://www.netgest.net/xeo/xvw" xmlns:xeo="http://www.netgest.net/xeo/xeo"<br />xmlns:my="http://www.mycompany.com/my" > After that, you use it like any other component. Setting its properties through the xml, if you take the "myComponent" example from above you could use it like the following: <verbatim><my:myComponent text='Hello World' /></verbatim> If the properties were declared as "bindable", you could also use the following (and having a _getText_ method in the backing bean): <pre><verbatim><my:myComponent text='#{viewBean.text}' /></verbatim> </pre> _ ---+++ Creating a custom component (using XEO Studio) To create a new custom component you can use XEO Studio's wizard. Go to the "File" menu, choose "New" and find "XEO Web Component", the window depicted in figure CustomComp.1 should appear (before doing this step, create an _org.example.components_ package). <img width="527" alt="" src="%ATTACHURL%/Wizard.png" height="503" /> __Figure CustomComp.1 - Wizard for creating a custom component__ In the Java Package field choose an existing package (the previouly created package), for the namespace choose "my" and name the component "MyComponent" (description can be empty). XEO Studio will generate a sample component that you can customize. The generated component will have three properties: text, bold and italic.
Attachments
Attachments
Topic attachments
I
Attachment
Action
Size
Date
Who
Comment
png
Wizard.png
manage
31.2 K
2011-02-18 - 09:21
PedroRio
Edit
|
Attach
|
P
rint version
|
H
istory
:
r10
|
r8
<
r7
<
r6
<
r5
|
B
acklinks
|
V
iew topic
|
Raw edit
|
More topic actions...
Topic revision: r6 - 2011-03-14
-
PedroRio
WebXEO
XEO Primer
-
Instalation
-
Introduction
-
Concepts
-
Architecture
-
XEO Library
-
Deploy to EAR
-
PreferenceStore
XEO - Core
-
XEO Model Reference
-
Security
-
Java API
-
BOL
-
XEOQL (BOQL)
-
Administrating
-
Background Tasks
-
boConfig.xml
-
Web.xml
-
Known Issues
-
XEO Flags
XEO - XWC
- Web Components
- Java Samples
- Custom Components
- Component Plugins
- Internationalization
- Viewer Events
- Value Change Listeners
- XUIServlet
- XeoLocalization
- XvwTemplates
Create New Topic
WebXEO Web
No permission to view
TWiki.WebTopBar
No permission to view
TWiki.WebBottomBar