Dear Wiki user, You have subscribed to a wiki page or wiki category on "Shale Wiki" for change notification.
The following page has been changed by CedricDumoulin: http://wiki.apache.org/shale/CreatingClayComponents The comment on the change is: Typo and code formating ------------------------------------------------------------------------------ There are numerous ready-made components within the Java``Server Faces world. These are available in Clay too (There is a tool that maps the tag library description;tld into its Clay component counterpart call Tld2``Clay``Cfg), so there is normally not a big need for creating own components (from scratch). But in many cases you may not be satisfied with what the standard components have to offer or you simply want to adapt them to your own special needs or not to forget add basic components together to form a new reusable component. - In this tutorial we look at some components that we want to create fro out site (we will be making some sub-components too) , amongst others: a person registration form, a news component and a table/list. + In this tutorial we look at some components that we want to create for our site (we will be making some sub-components too) , amongst others: a person registration form, a news component and a table/list. If don't want to tag along and enter code as we go, you can download the completed stuff attachment:shaleclay2.zip @@ -16, +16 @@ Add the following attributes: - * lastname - String[[BR]] + * lastname - String[[BR]] - * firstname - String[[BR]] + * firstname - String[[BR]] - * streetadress - String[[BR]] + * streetadress - String[[BR]] - * post - Post = new Post()[[BR]] + * post - Post = new Post()[[BR]] Create getters/setters for all. Then create the Post bean with following attributes: - * zipcode - Short[[BR]] + * zipcode - Short[[BR]] - * city - String[[BR]] + * city - String[[BR]] - * zipcodes - Short[] = new Short[] {51000, 51001, 51002, 51020, 51030, 51050, 51100, 51200}[[BR]] + * zipcodes - Short[] = new Short[] {51000, 51001, 51002, 51020, 51030, 51050, 51100, 51200}[[BR]] Create getters/setter for except for the zipcodes which only require a getter (read-only). If you started with the Maven2 archetype, the person bean will already have been defined as a managed bean in the faces-config.xml file, if not enter this into it: - + {{{ <managed-bean id="person">[[BR]] <managed-bean-name>person</managed-bean-name>[[BR]] <managed-bean-class>[[BR]] @@ -41, +41 @@ </managed-bean-class>[[BR]] <managed-bean-scope>session</managed-bean-scope>[[BR]] </managed-bean>[[BR]] + }}} - Now we almost have the receiver for the data in place. What we lack is a viewcontroller (controller in MVC) for the person registration form. Create a bean PersonVC that extends Abstract``View``Controller and has on attribute of type Person with respective getter/setter. + Now we almost have the receiver for the data in place. What we lack is a viewcontroller (controller in MVC) for the person registration form. Create a bean PersonVC that extends Abstract``View``Controller and has one attribute of type Person with respective getter/setter. - Define it the following in faces-config.xml file + Define the following in faces-config.xml file - Definer denne i faces-config.xml + {{{ <managed-bean id="personReg">[[BR]] <managed-bean-name>personReg</managed-bean-name>[[BR]] <managed-bean-class>[[BR]] @@ -61, +62 @@ <value>#{person}</value>[[BR]] </managed-property>[[BR]] </managed-bean>[[BR]] + }}} The next we do is to add a method that "saves" the person. Do this by adding the following method: + {{{ public String save()[[BR]] {[[BR]] return null;[[BR]] }[[BR]] + }}} For now this method does nothing. Also note that it returns null. This means that no navigation rule will be executed and we remain at the same form. @@ -75, +79 @@ attachment:ShaleClay9.png - As we can see from the design, there are two distinct blocks of information here, and would be natural to break this down into two components first. By so doing we can also reuse these by them self in another case. When we take a second look at it we see that there is a repetition of equal components; 2 labels and 2 input fields. We could of course created a component that was a combination of firstname label and firstname input field, but it would be cumbersome over time to have to create new components for different attributes (lastname, streetadress etc.). In some cases that is desirable though to ensure consistency everywhere (We will be creating such a component too). Instead we create a generic label/input combination. This we can then reuse for any attribute. We have two alternatives for how we create it, as an XML definition in the Clay configuration file, or as a HTML mockup with Clay annotations. To demonstrate both we will use the XML variant for the name panel and HTML for the address panel. We will start with the name panel, so lest try to define it. + As we can see from the design, there are two distinct blocks of information here, and would be natural to break this down into two components first. By so doing we can also reuse these by them self in another case. When we take a second look at it we see that there is a repetition of equal components; 2 labels and 2 input fields. We could of course created a component that was a combination of firstname label and firstname input field, but it would be cumbersome over time to have to create new components for different attributes (lastname, streetadress etc.). In some cases that is desirable though to ensure consistency everywhere (We will be creating such a component too). Instead we create a generic label/input combination. This we can then reuse for any attribute. We have two alternatives for how we create it, as an XML definition in the Clay configuration file, or as a HTML mockup with Clay annotations. To demonstrate both we will use the XML variant for the name panel and HTML for the address panel. We will start with the name panel, so let try to define it. We start by creating the generic labell/input filed component and we will call it "gltic". This is short for Generic Label Text Input Component. + {{{ <component jsfid="gltic" extends="clay" id="gltic">[[BR]] <element jsfid="outputLabel" renderId="1">[[BR]] <attributes>[[BR]] @@ -91, +96 @@ </attributes>[[BR]] </element>[[BR]] </component>[[BR]] + }}} - There are a couple of things to note here. Firstsly, we extend from "clay". All components must either extend "clay" or another existing component. Next ting to note is that within the component define elements that are part of the component. Be careful with the rendered attribute. This attribute governs the rendering order of the elements to the device. So be careful to order them in the order that you want them displayed. Also take care that the renderIDs are unique at the same element level (You can have nested elements). + There are a couple of things to note here. Firstsly, we extend from "clay". All components must either extend "clay" or another existing component. Next thing to note is that within the component define elements that are part of the component. Be careful with the rendered attribute. This attribute governs the rendering order of the elements to the device. So be careful to order them in the order that you want them displayed. Also take care that the renderIDs are unique at the same element level (You can have nested elements). As you can see we have tied the values of the attributes to symbols (identified by @). This means that we do not have to worry about the actual values of these now, but handle that when we use the component. Lets now try to define the first panel, which is the name panel. As we said earlier there are a lot of ready-made component libraries for us to choose from. We are now going to use one of these. It is know as [http://myfaces.apache.org/tomahawk/index.html/ Tomahawk] and comes from the [http://myfaces.apache.org/ MyFaces project]. The component that we are going to use is the [http://myfaces.apache.org/tomahawk/htmlTag.html/ htmlTag]. This is a component that will render any HTML tag that you specify as a value. To be able to use this, you need to download it and install it into you project. How you do this depends on whether you are using the Maven2 plugin, Maven2 by it self or not at all. The important thing is that you get the tomahawk jar file in the WEB-INF/LIB when you deploy your application(if itâs a standalone WAR). We base our application on the latest version which is currently 1.5-SNAPSHOT. Next is to make Clay aware of the components. You do that by adding th e attachment:tomahawk-1.1.5-SNAPSHOT-config.xml Clay configuration file to your WEB-INF folder. Then change the following section in the web.xml file: + {{{ <!-- Clay Common Configuration Resources -->[[BR]] <context-param>[[BR]] <param-name>[[BR]] @@ -108, +115 @@ /WEB-INF/tomahawk-1.1.5-SNAPSHOT-config.xml[[BR]] </param-value>[[BR]] </context-param>[[BR]] + }}} We are now ready to use all the components that Tomahawk has to offer. - Back to our name panel, there is one thing that we need to decide. What to use as the outermost container? As you may know JSF builds a componenttree and uses POST to send data from the client to the server and that requires a form. Since we are going to add more components to our page that carry data, we choose to use a tag that is frequently (container) used within a form: Fieldset. So this will be our container. Now our componet looks likes this: + Back to our name panel, there is one thing that we need to decide. What to use as the outermost container? As you may know JSF builds a component tree and uses POST to send data from the client to the server and that requires a form. Since we are going to add more components to our page that carry data, we choose to use a tag that is frequently (container) used within a form: Fieldset. So this will be our container. Now our componet looks likes this: + {{{ <component jsfid="namepanel" extends="clay" id="namepanel">[[BR]] <element jsfid="t:htmlTag" renderId="1" id="namefieldset">[[BR]] <attributes>[[BR]] @@ -157, +166 @@ </element>[[BR]] </element>[[BR]] </component>[[BR]] + }}} Looking closer at this, we see that the first element we define is the Tomahwk component htmlTag, identified by "t:htmlTag". We give it a value of "fieldset" through the attributes section. Then we define a nested element where we use "htmlTag" again, only this time we give it a value of "legend". However "legend" requires a value, so we create a nested element where we the standard Clay "outputText" component. The value we get from the resourcebundle (messages) â Remember to add that value now: personpanel.text=Person data. @@ -167, +177 @@ We now have a panel where we can enter firstname and lastname. But we also need a panel to enter the address information. As we mentioned earlier this time we define the component in HTML. The principals are the same, only now we are using HTML and are able to do preview on what we do. The panel then becomes (stripped): + {{{ <fieldset>[[BR]] <legend>[[BR]] <span jsfid="outputText" value="@adresslegend" allowbody="false">Adress</span>[[BR]] @@ -186, +197 @@ </label>[[BR]] <input jsfid="inputText" value="@cityField" type="text" allowbody="false">[[BR]] </fieldset>[[BR]] + }}} As you can see this is pure HTML with some special attributes on some of the HTML tags. These attributes are Clay directives. The attribute "jsfid" points at a Clay component defined in a Clay configuration file. Next is "value" where we which value the tag should have. Since this is to be a reusable component, we use the symbol instead of hardcoded values. The "SPAN" tag is used as a replacement for the cases where we want to simply output some text that is not related to any tag. We save this in the pages folder and give it a name of adresspanel.html. Now that we have defined our HTML based Clay component, we need to tell Clay of its existence. We do that by adding the following in our clay-config.xml file; + {{{ <component jsfid="adresspanel" extends="clay" id="adresspanel">[[BR]] <attributes>[[BR]] <set name="clayJsfid" value="/pages/adresspanel.html" />[[BR]] </attributes>[[BR]] </component>[[BR]] - + }}} Note that we here use a special attribute "clayJsfid". This is Clay's variant of including something (ala jsp:include). So here we import our HTML component and assign it a Clay id (jsfid). So now that we have defined our two components that we are going to use, what remains is to stitch the whole thing together. Again we can either define them in HTML or XML. Here we will use the latter. There is one thing that we have not looked at yet, the button that needs to be pushed in order to submit the data to the server. If you want a common "look&feel" for this type of component the it makes sense to define them, such that you later on can use them "as is". An example of this would be: + {{{ <component jsfid="saveButton" extends="commandButton"> <attributes> <set name="value" value="#{messages['savebutton.label']}"></set> <set name="action" value="[EMAIL PROTECTED]@metode}" ></set> </attributes> </component> + }}} Let's assume that you always wanted this to have a font-size of 10px and a green backgroud and white bold font. The only thing we would need to add then is: - + {{{ <set name="style" value="background: green; font-size: 10px; font-weight: bold; color: white;" ></set> - + }}} This way it would always look the same when you used the "saveButton" component. SO lets stitch this together as a whole. Since we are not adding any more components to our page, we can use the form as basis for it. Our completed component then becomes: - + {{{ <component jsfid="personregpanel" extends="form"[[BR]] id="personregpanel">[[BR]] <element jsfid="namepanel" renderId="1"></element>[[BR]] @@ -249, +264 @@ </symbols>[[BR]] </element>[[BR]] </component>[[BR]] + }}} Here we have defined our reusable components as elements (respecting the rendered) and defined actual values to substitute the symbols with. The last thing we need to do is to as another entry in our menustructure awhich is defined in defaultLeftNav.html (in folder pages): - + {{{ <li><a jsfid="commandLink" action="personreg" allowBody="true" immediate="true"><span jsfid="outputText" value="#{messages['menu.personreg']}" allowBody="false">Personreg</span></a></li> - + }}} Package, deploy and start the application. The choose Personreg from the menu. You should now be presented with this: @@ -267, +283 @@ To refine this you can substitute the zipcode field with a combobox that gets its values from the Post beans getZipcodes method (This is shown in the downloadable finished application). The HTML definition for it is: + {{{ <select value="@zipcodeFelt" allowBody="true">[[BR]] <option value="@zipcodesList" />[[BR]] </select>[[BR]] + }}} In addition we also have to declare what the symbol "zipcodesList" is to be replaced with when we use it on our page. The values for such a list must be one of the following types: [http://java.sun.com/javaee/javaserverfaces/1.1_01/docs/api/javax/faces/model/SelectItem.html/ SelectItem] '''Select''Item[]''', Collection or Map. We use Select``Item, so you need to add the following method to the Post bean: + {{{ private void initZipcodesList() {[[BR]] zipcodeliste=new Select``Item[zipcodes.length];[[BR]] Select``Item selectItem;[[BR]] @@ -288, +307 @@ }[[BR]] [[BR]] }[[BR]] + {{{ And add a default constructor to it: - + {{{ public Post()[[BR]] {[[BR]] initZipcodesList();[[BR]] }[[BR]] + }}} When you run this it will look like this: