Some times you would like to be able to have the power of any component inside your page, for a very rare solution
or to even prototype or proof of concept a component and do so right inside a particular page.
Also, you may need to have more complex logic very specific to a particular page. In these cases, Gracelets
provides you with at least 3 options. 1) Page Level JSF Components, 2) Page Level Renderers, and 3) Page
Level Tag Handlers.
Page Level JSF Components
You may want to write a Form, Command, Data or other type of component right inside your page, and thus inside your
page having access to exactly what is rendered and having a part on your page where you participate in the
decoding phase.
You can create prototypes of the following types: Form, Command, Data, Input and Generic. You specify the type
via the 'type' attribute passed to the prototype() tag which can be called on any builder (as long as the builder
itself does not have a prototype() tag).
You can specify the 'decoder', 'encodeBegin', 'encodeChildren', 'encodeEnd', 'isRendered' and 'getClientId'
as attributes with closures that will be ran as parts of the component decoding and rendering process.
For example, to prototype a security form on a page you could do the following:
You may simply want to have complete control on how the page is rendered on each page access and don't need
or want to write a component to do so, and it could be simple rendering logic very specific to your page. You
can accomplish this with page level renderers. You can call the render() tag on any builder. If you pass it a single
closure, it will be the encodeChildren() part of a transient component produced for your renderer.
For instance, in the Blog application example, we don't want to have to create a data model and the like just
to show the comments on this one page and we don't need a bunch of bindings and closure expressions, but rather
we want full control of rendering this part of the page. We can use a page level renderer instead, like so below:
Notice above that the table tag is part of the Facelet tree building process. But everything inside the
render() tag is part of the Page rendering process. Thus in this part you have full control of how it is rendered
every time right inside your page.
Page Level Tag Handlers
There are many cases where you may want to decide whether to even include a component on a page or not
depending on a certain condition. When Facelets was created this was made possible via TagHandler's. However
in facelets it still requires alot of setup and scaffolding code to do so. In Gracelets you can use them in
Gracelet Component Libraries but also have the option of using them directly in your page/view.
The difference between using TagHandlers and regular components is at what point your code is ran and how it
affects the component tree. With regular components you could use the 'rendered' attribute for instance to control
whether a component is rendered or not, but that component is still part of the JSF component tree in the view
and can still participate in decoding and other parts of the JSF lifecycle.
With TagHandlers you can completely remove a component from the tree depending on a certain condition, or even
add a component to the tree many times.
For instance below we render twice the following page each time the tag handler will decide which
components are in the tree:
1 Factory("counter","event"){0} 2 3 u.handler(cond:{ 4 if(counter %2!=0){ counterNWas = counter;returntrue;}elsereturnfalse 5 }){ 6 7 print {"All children component will be included when $counterNWas is not divisible by two"} 8 9 } 10 11 u.handler(cond:{ 12 if(counter %2==0){ 13 counterPWas = counter; counter++;returntrue; 14 }elsereturnfalse 15 }){ 16 17 print {"All children components will be included when $counterPWas is divisible by two"} 18 19 }
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf
All children components will be included when 0 is divisible by two
http://somesite/somepage.jsf - Mozilla Firefox
http://somesite/somepage.jsf
http://somesite/somepage.jsf
All children component will be included when 1 is not divisible by two
The counter variable being used is manipulated by the tag handlers at TREE CREATION TIME while the sub components
that are under them will render their values at RENDER TIME, so we have to store the tree creation time value
into another variable so as to be able to access its value at render time.