Reference Manual for Gracelets - 2.0.0.RC2SourceForge.net Logo
2.17 - Tutorial : Writing JSF Components
The JSF component set available for definition in a Gracelet Library are backed by a set of sub classes that can be instantiated via the definition provided in the library. Each type will translate to a true sub class of the base JSF UI component set (Input, Output, Data, Form, etc.,) and so will work as expected in the JSF lifecycle.

Components that are truly stateful (Form, Input, etc.,) will have the isTransient() on the UIComponent implementation return false and thus will maintain state between requests.


Example Output Component

To create a component that will create a ul html tag based list off a value binding we could do the following:

Toggle Line Numbers
1 namespace = "http://gracelets/doc/example" 
2 list = Output { cmp -> cmp.builder.ul { cmp.value.each { val -> li { print val } } } } 
Here we assign an Output() component to the list variable which will translate into a tag called "list" available to this component library. Then we accept the first of a few optional parameters, called cmp, which represents the UIComponent implementation behind this component (which is a true sublcass of UIOutput in this case). We get a RendererMarkupBuilder for this component by calling the builder attribute which allows us to render xml markup to the JSF ResponseWriter. We call ul() which will create an html ul tag. Inside the ul tag we loop through the value binding returned from the component and create a li html tag and print the toString() value of each item in the list.

Then we could use this tag as shown below:

Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 ex.list(value: { ["One", "Two", "Three"] }) 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf
  • One
  • Two
  • Three

Example Generic Component

If you do not want to make any particular type of component (Output, Input, so on...) you can declare a Generic component which is a simple extension to the UIComponentBase class.

These are particularly useful for making non-rendered components. Ones that provide functionality but do not render anything additional themselves. For instance if we wanted to render children of a particular component depending on a system wide variable we could do so as follows:

Toggle Line Numbers
1 showSpecialMenu = Generic { cmp -> if (someSetting) { cmp.renderChildren(); } } 
When the component is rendered, it will call this default closure as the encodeChildren() method and since we are using the default closure, the rendersChildren flag is set to true. Here in this closure we check to see if 'someSetting' in variable context resolution is a groovy true (non-zero, not null and not an empty string) and if so then we call the automatically available method 'rendersChildren' on the UIComponent that was passed.

We could then use this tag as follows:
Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 def someFlag = true 
4 someSetting = { someFlag = !someFlag } 
5  
6 ex.showSpecialMenu { h.outputText("Will Not Be Rendered") } 
7 ex.showSpecialMenu { h.outputText("Will Be Rendered") } 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf

Example Command Component

With some components, you still need to understand how the JSF lifecycle works and what other pieces need to be defined. For instance, a Command component needs a corresponding decoder. Otherwise, althought it gets rendered, it will never actually do anything when the form is submitted.

For instance, if we wanted to create a Command component that uses the html <button> tag, we could do the following:

Toggle Line Numbers
1 import javax.faces.event.ActionEvent 
2  
3 button = Command(decoder: { cmp, ctx -> 
4     String clientId = cmp.getClientId(ctx) 
5     if( param[clientId] == clientId ) cmp.queueEvent(new ActionEvent(cmp)) 
6 }) { cmp, ctx -> 
7     def x = cmp.builder 
8     def f = cmp.support.findParent(UIForm.class) 
9      
10     if (== null) print "Your action buttons must be inside of a form." 
11      
12     String clientId = cmp.getClientId(ctx) 
13  
14     def html = cmp.extractHtmlAttributes() 
15     html.name = "button_$clientId" 
16     html.onclick = "this.form['$clientId'].value = '$clientId'; this.form.submit();" 
17      
18     x.input(type: "hidden", name: clientId, value: "") 
19     x.button(html) { 
20         if (cmp.children.size() == 0) print cmp.attributes.value 
21         else cmp.support.renderChildren(); 
22     } 
23 } 
When the button is clicked, it uses javascript to set the hidden input value to the same clientId and then submits the form. When the form is submitted it will post the hidden value and when the decoder is ran it will then detect that the value of the hidden input is the correct value and then queue an ActionEvent object that will later be handled by the default jsf system Action Listener who in turn calls the method expression/binding defined by the developer.

Thus we can use it as follows:
Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 h.form { 
4     ex.button(action: {  }, onmousedown: "alert('This is only a demo and cannot be submitted'); return false;") { print "This is a button component" } 
5 } 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf

Example Data Component

Writing some components even though much easier can require a bit of code. For instance making a fully featured grid renderer is by nature somewhat involved. For now we will make a simple Data component that renders the columns in a table:

Toggle Line Numbers
1 import javax.faces.component.UIColumn 
2  
3 grid = Data { cmp -> 
4     def columns = cmp.support.getComponents(UIColumn) 
5      
6     if (columns.size() == 0) return 
7      
8     def x = cmp.builder 
9      
10     x.table(width: cmp.get("width", "100%")) { 
11         if (cmp.hasFacet("header")) caption { cmp.renderFacet("header") } 
12          
13         def headers = false 
14         def footers = false 
15          
16         columns.each { 
17             if (it.hasFacet("header")) headers = true 
18             if (it.hasFacet("footer")) footers = true 
19         } 
20          
21         tbody { 
22             if (headers) tr { columns.each { col -> th { col.renderIfHasFacet("header"); } } } 
23          
24             cmp.rowIndex = 0 
25             while (cmp.rowAvailable) { 
26                 eventContext.set(cmp.get("var", "row"), cmp.rowData) 
27                 tr {  
28                     columns.each { col ->  
29                         td(col.extractHtmlAttributes()) { col.render() }  
30                     }  
31                 } 
32                 cmp.rowIndex++ 
33             } 
34              
35             if (footers) tr { columns.each { td { it.renderIfHasFacet("footer"); } } } 
36      
37             if (cmp.hasFacet("footer")) caption { cmp.renderFacet("footer") } 
38         } 
39     } 
40 } 
Above we use yet another feature for Gracelet Component Developers, a simple call to getComponents(class) will return all UIComponent children that are a sub class of the passed class. So first we get the collection of UIColumn children. Then, if there are actually children, we render an html table, we use some other features for easily checking and optionally rendering the header and footer facet as well as the footer and header column facets. Then we simply loop through each row in the available data model and render each column for each row available. To use this grid component we could use the following code:
Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 ex.grid (facets: [header: { print "Example Data Table" }], var: "row", value: DataModel ("exampleDataModel") { ["1","2","3"] }) { 
4     h.column(facets: [header: { print "Value" }], align: "center") { print { row } } 
5     h.column(facets: [header: { print "Length" }], align: "center") { print { row.length() } } 
6     h.column(facets: [header: { print "Hash Code" }], align: "center") { print { row.hashCode() } } 
7 } 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf
Example Data Table
ValueLengthHash Code
1149
2150
3151

Example Form Component

With form components, similiar to command components, you also need to write a corresponding decoder to flag the submitted boolean to true if the form was really submitted. Notice the example below:
Toggle Line Numbers
1 form = Form(decoder: { cmp, ctx ->  
2     def clientId = cmp.getClientId(ctx) 
3     if ( param[clientId] == clientId ) cmp.submitted = true 
4 }) { cmp, ctx -> 
5  
6     def x = cmp.builder 
7     def html = cmp.extractHtmlAttributes() 
8      
9     def clientId = cmp.getClientId(ctx) 
10  
11     html.action = actionURL 
12     html.method = "post" 
13     html.onsubmit = "$html.onsubmit; this['$clientId'].value = '$clientId';" 
14     html.id = clientId 
15      
16     x.form(html) { 
17         input(type: "hidden", name: clientId, value: "") 
18         print ctx.viewState 
19         cmp.renderChildren() 
20     } 
21  
22 } 
Here we get the xml builder. Then we extract all the valid html attributes so we can pass them onto the form tag. We make sure we add (or override) the action, method and onsubmit html attributes. We use the globally available 'actionURL' variable which will contain the full url to postback to for the currently rendered view. We use a hidden input that we will set only if this form is submitted. Also we print out the view state provided by this implementation (which in html is a a special hidden input) required by the JSF system in order to restore view state on postbacks. This is made easy via the added method to FacesContext called getViewState(). Then we render the children of this component inside the form tag.

We could use this component as follows:
Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 ex.form(enctype: "multipart/form-data", onsubmit: "alert('This is only an example'); return false;") { 
4     h.commandButton("Click Here") 
5 } 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf

Example Renderer

As with regular JSF component development, inside a Gracelet Component Library you can define abstract renderers that can be applied to more than one component. For instance if we wanted to write a renderer that will always put a styled div arround certain components, we could do that as follows:

Toggle Line Numbers
1 divRenderer = Renderer( 
2     encodeBegin: { cmp, ctx -> 
3         print "<div style=\"border: solid black 1px; padding: 5px; margin-bottom: 10px;\">" 
4     }, 
5     encodeEnd: { cmp, ctx -> 
6         print "</div>"; 
7     } 
8 ) 
9  
10 header = Output(renderer: divRenderer) { cmp, ctx -> print "Some Header" } 
11  
12 body = Output(renderer: divRenderer) 
Toggle Line Numbers
1 ex = ns."http://gracelets/doc/example" 
2  
3 ex.header() 
4 ex.body { 
5     print "Some Body Content" 
6 } 
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf
Some Header
Some Body Content

Example Render Kit

If you need to write a component library that produces something other than HTML/XHTML, like maybe Voice XML, you can add a render kit component to your Gracelet Component Library. This can be done as show in the example below:

Toggle Line Numbers
1 public static final String POST_KEY = "voicexmlViewState" 
2  
3 namespace = "http://gracelets/voicexml" 
4 alias = "vxml" 
5  
6 VXML_BASIC = RenderKit(requestKey: POST_KEY, getContentType: { "text/xml" }) 
7  
8 form = Form (decoder: { cmp -> 
9     cmp.submitted = param[this.getClientId(cmp)] != null 
10 }) { cmp -> 
11     def xml = cmp.builder 
12     def clientId = this.getClientId(faces, cmp) 
13     xml.form (id: clientId) { 
14         xml.field(name: POST_KEY, expr: { "'$faces.viewState'" }) 
15         xml.field(name: "javax.faces.RenderKitId", expr: "'VXML_BASIC'") 
16          
17         cmp.renderChildren() 
18     } 
19 } 
20  
21 private def getClientId (ctx, cmp) { cmp.getClientId(ctx).replaceAll(":","_") } 
22  

Example Phase Listener

If you need to do some pre-processing or post-processing for your library components or you simply need to hook into the JSF lifecycle for some other reason, you can do so easily by defining a phase listener hook in a Gracelet Component Library.

For instance you could easily write a phase hook that allows you to debug when each phase starts and ends:

Toggle Line Numbers
1 import javax.faces.event.PhaseId 
2  
3 debugHook = Phase(PhaseId.ANY_PHASE, { before, phase -> 
4     if (before) log.info("Starting phase: ($phase)") 
5     else log.info("Ending phase: ($phase)") 
6 }) 

Other Components (Graphic, Input, SelectOne, SelectMany, SelectItem, SelectItems, Message, Messages)

The rest of the components will generally not be used often, but are available if you discover a need to use them. You might define them to change base functionality, like how the component is decoded, converted, updated, etc., and you want that to be inherent to the component instead of having to define converters and validators in every use case.


More about components

All of the components that take a renderer setting can thus reference a string renderer id (defined in faces-config.xml file), a renderer defined in the library or a dynamic closure. The following example shows how this might be done:

Toggle Line Numbers
1 someTag = Command(renderer: "javax.faces.Link") 
2  
3 someRenderer = Renderer { cmp, ctx -> print "Hello World" } 
4      
5 someOtherTag = Ouptut(renderer: someRenderer) 
6  
7 someOtherRenderer = Renderer { cmp, ctx -> print "Hello Jupiter" } 
8  
9 dynaTag = Output(renderer: { cmp -> return cmp.value ? someRenderer : someOtherRenderer }) 
10  
11 anotherDynaTag = Output(renderer: { cmp -> return cmp.value ? "javax.faces.Link" : "javax.faces.Button"}) 
On the first tag we reference a renderer-id defined in a faces-config.xml, which will take care of rendering our Command component. After that, we define a renderer right inside the library and then use that with a Output component. In this way you can define a permanent renderer for the component.

The last part of the example shows a dynamic way of determining the renderer at component rendering time, right when the component is to be rendered. In the 'dynaTag' definition we basically say that if the component has a value we should use 'someRenderer' and if it does not we use 'someOtherRenderer'. Then in 'anotherDynaTag' we do the same thing, but use renderer-id's instead of library level renderers.