November 16th, 2010
2:59 pm
JSF 2.0 Composite Components

Posted under JSF
Tags , , , , , ,

This post highlights a few lessons learned whilst experimenting with a simple composite component, in this case an experimental  Primefaces theme switcher component. The component does the following:-

  • Automatically iterates the themes directory on the server to build a list of available themes which are presented for the user to select
  • Generates a simple theme control panel with a border, consisting of a drop down combo listing the themes, with previous theme/next theme buttons to the right.
  • Also allows theme switching via ctrl/shift/left arrow and ctrl/shift/right arrow, to give a quick way of cycling through the themes when choosing one.
  • The component is used on the JSF page in two modes – the first usage is with outputStyle=”true”, themeBase and defaultTheme attributes. It is placed in the <head> section, and it defines the base path for all the theme directories, and the default starting theme (which may be programmatically overriden by setting the theme property in its backing bean, themeSwitcherBean). This mode also outputs the link directive to link the current theme stylesheet to the page. It does not result in the display of the control panel.
  • The second mode is used inside a <form> on the page, and results in the theme switcher panel being displayed.
  • A theme switch results in a form submission, so this must be acceptable to the form logic. If not, i.e. if the form is dirty, the theme switcher must be disabled. This would be done by passing a disable flag attribute to the component, which maps to a disable property of the backing bean, which results in enabling/disabling the controls. At present, a disable feature is not supported.

 

The following salient points were picked up along the way:-

  • The component does not have to be placed in a form. The examples in the Core JavaServer Faces book seemed to always show the client page with the control placed on a form, and also with <form></form> tags present in the custom component implementation. There is absolutely no requirement for the custom component implementation definition to be in its own form.
  • With JSF 2.0, it is easy to pass a value e.g. from a composite component attribute in a call, direct to a backing bean property, as JSF 2.0 now supports method expressions with parameters in EL expressions – just add the brackets and the call arguments. This used to be tricky, and many posts on technical blogs just seemed to answer ‘why on earth do you want to’. Well, perhaps it is unusual, but in this example it feels just the right thing. Normally when linking to a style sheet, one would put the path to the sheet directly on the page in the <link> tag, as one also would when referring to other resources such as images. I have therefore done exactly the same with the themeswitcher – you pass the theme base web context path (along with the default theme name) to the component just as you would do to a <link> tag. This then allows the backing bean to discover the physical theme directory location on disk and automatically iterate it to generate a list of the available themes which are present, which is then passed to the select list of the combo. Whilst the theme base context path could be set up as an injected property of the backing bean, it just does not feel right to do it that way, as normally this knowledge is encapsulated on the page. Sometimes, passing values from the page to a bean is actually the right thing to do!
  • When using an EL method expression to write to a bean property, note that you can just call a setter on the bean directly as if it was a method, giving the “set” prefix, and passing the value as an argument. You literally just plant the EL call on its own in the middle of the page. (You can of course also use another custom method if you wish, for example if you want to pass a number of properties in a single call). Furthermore, when calling for example a setter or any other method that returns void, nothing is written to the page, as you would expect. In the example code below, the EL expression #{cc.attrs.bean.setThemeBase(cc.attrs.themeBase)} does exactly this.
  • A composite component acts as a JSF naming container. Naming containers are required to ensure uniqueness of IDs on a page , by modifying Ids to add a prefix. For example a composite component could be placed many times on a page, and the Ids of all its constituent components/controls must be unique. As a test example, when the above component was placed in the <head> section (i.e. not in a form), its clientId was j_idt4. When placed on the page a second time, in the form to show the control panel , its clientId was frmTest:j_idt9. Notice that by default the clientId was automatically prefixed by the form ID. This issue becomes important when Javascript is in use to refer to controls in the component, as the Id given to a control is in turn prefixed by the clientId. For example, when on the form, a select box which was given an Id of cmbTheme actually ended up with an id of frmTest:j_idt9:cmbTheme. This needs to be taken account of in the code. Note that in the Javascript examples in Chapter 9 of Core JavaServer Faces (p369), the form is inside the composite component. This turns things around, as the form ID is then prepended by the clientId of the composite component as the latter is a naming container – our case is different.
  • By default a form’s controls have the form id prefixed to their id, as the form is also a naming container. This behaviour can be disabled if desired by adding the attribute prependId=”false” to the form tag, but I did not do this.
  • JSTL functionality can be used such as c:if, and for example you can test parameters passed to composite components (cc.attrs.attrname)– the themeswitcher example uses this with the outputStyle attribute to determine whether to output a <link> tag for the theme stylesheet and set the theme base directory/default theme, or whether to output the themeswitcher control panel. The use of c:if in this way is a powerful means of controlling exactly what a custom component renders on the page, and is a useful alternative to using the render property on a component to prevent it being rendered. In addition, it can for example conditionalise the setting of backing bean properties from the page, as is done in the themeswitcher, which could not be done via toggling the render property on components.  In this case, it seemed more convenient and clearer to give two modes to the same component, so that all the design decisions where encapsulated and visible in one place, rather than inventing another component. Other examples of where this might be useful is where a general purpose composite component might be tailorable via its call attributes. For example a table component might have adjacent up/down buttons to allow re-ordering/moving of a block of selected rows, but the re-order capability might not always be needed, so it could be conditionally selected with c:if.
  • When using JSTL, there are limitations. As an example, I tried c:set to copy an attribute containing the backing bean reference to another variable, to use later in a subsequent instance of the composite component and save passing it twice. Setting a valueChangeListener using the saved copy of the bean reference gave a run time error and is not supported. However, reading and writing properties on the bean using the saved copy of the reference worked fine.
  • Note that other JSTL functions can also be used, e.g. to return the size of a string or list, as noted here.

Comments Off on JSF 2.0 Composite Components

Comments are closed.