Archive for the 'JSF' Category

March 22nd, 2011
8:27 pm
Using the Browser Resize Event in jQuery

Posted under JSF
Tags , , , ,

jQuery ties into this event in a browser independant way. The following code fragment illustrates the use of this. Note tha following points:-

  • Different browsers implement resize differently. Most fire continual events during the resize, but some browsers (e.g. I believe older versions of Firefox) just fire the resize at the end of the drag. You therefore cannot predict how often and when the resize is called.
  • You need to place the code in the body section – I placed it in the head initially and it was never called.
  • When referring to a function defined in the head section as I have here, you need to prefix the call with “document.” otherwise the target function appears out of scope. The example assumes that yourFunctionName is a Javascript function defined elsewhere, e.g. in the header section of the page.

 

        <script type=”text/javascript”>
                /*
                 * This script block executes the target function on a resize.
                 * Note that jQuery has a browser independant means to hook into the event.
                 */
                jQuery(window).resize(function() {
                //alert(‘resize called’);
                document.yourFunctionName(args);
            });
        </script>

No Comments »

March 22nd, 2011
8:11 pm
Fixing Primefaces scrolling table header width issues using jQuery

Posted under JSF
Tags , , , , , , , ,

This has been very much an ongoing chestnut with Primefaces, mainly due to the tricks you have to use in order to get fixed table column headers and a scrolling table. Primefaces does this with a pair of tables – one for the header row and another for the data. The problems which often arise are mismatching columns between the header and the data, incorrectly sized table header above the column headers, and an incorrectly sized header row which does not appear to size properly dynamically when scrollbars are present/absent.

These issues can often be fixed, but it does appear that there is no overall silver bullet which makes everything work in every use case. The best approach I have found is to have a selection of approaches to try, and to apply the appropriate ones to solve problems which arise in particular use cases. The following details the different approaches I have used in various cases to solve width and alignment problems.

The following commented code sample shows how to use jQuery to correct table header width and column header width problems for scrolling tables. These problems are typically triggered by the dynamic appearance/removal of scrollbars, which will depend on table height and row count. Note that the function described, ss_FixTableHeaderWidth, would either be called in an inline script block placed immediately after a table definition in a facelets page (for a static table) or would be triggered as part of an Ajax call (for a dynamically rendered Ajax table). The example shows the static case. Note the following points about the code:-

  • The code may be found in the repository here.
  • The jQuery selectors should be optimised for performance. In general, ID selectors are the most efficient, so  narrow down with an ID selector first if you can (as below). Element selectors are also efficient, but classes can be really slow depending on what the browser supports – jQuery may end up doing a full DOM tree scan for every class selector, which is highly undesirable!. To avoid this below, I have prefixed class selectors with an element type which then makes use of the faster element searching, e.g. div.ui-scrollable-datatable.
  • Avoid duplicating selector searches where possible – in the example below a reuse them where I can, by using previous selector results as the context for subsequent lower level selectors, for example jQuery(‘div.ui-scrollable-datatable-container’, mainDiv) makes use of the jQuery result mainDiv from a previous selector when selecting its descendant scrollable container div.
  • You need to keep track of the difference between DOM elements returned by some calls, and jQuery objects which can be returned by others. You can always wrap a DOM element with a jQuery object using jQuery(element), but this is not always necessary. Avoid the overhead of doing it when you already have a jQuery object as it is redundant. The jQuery documentation makes all this clear.
  • The jQuery online docs are available here.  You cannot directly download the docs from the jQuery site, but it does link to some unofficial PDF downloads. However, the best and most searchable option seems to be an unofficial windows help file/CHM version download linked from StackOverflow (not fully up to date but still very useful). This is available here.
  • The RH header column size is set to auto to accommodate header row size changes, the idea being that this RH column will expand to fill the row, and the browser will not mess with other column sizes. Note that the column widths are just a guide to the browser and it is free to mess with them. This can be really awkward as we rely on the header table and data table being rendered exactly the same way to line up. This auto approach seems to work.
  • Firefox (3.6 and 4) has a problem whereby when setting an element width (in this case with jQuery), the actual value set is often 1px less than the requested value (particularly a problem when setting header table width). This can easily be seen by reading back the element width immediately after setting it. The fix I use for this is to do all width setting in a function (ss_setWidth) which checks the width afterwards and calculates the value of the mismatch. If there is a mismatch, the mismatch is then added to the width to set, and the element width is set a second time. This function is safe to use for all browsers.

 

Function definition, placed in page header section

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {
           
            /*
             *Fix incorrect table header width due to scrollbars
             */
           
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
            var lastColumnHeader = jQuery(‘thead > tr:eq(0) > th:last’, headerTable);

/*           
            alert (‘TableId=’+fullTableId + ‘\n’ +
                   ‘topHeader=’+topHeader.attr(‘class’) + ‘\n’ +
                   ‘mainDiv=’+mainDiv.attr(‘class’) + ‘\n’ +
                   ‘headerTable=’+headerTable.attr(‘class’) + ‘\n’ +
                   ‘dataContainer=’+dataContainer.attr(‘class’) + ‘\n’ +
                   ‘dataTable=’+dataTable.attr(‘class’) + ‘\n’ +
                   ‘lastColumnHeader=’+topHeader.attr(‘class’));
*/           
            /*
             * Set the RH header column width to auto to prevent header table width adjustments
             *  from messing up column alignments
             */
            lastColumnHeader.css(‘width’, ‘auto’);

            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }       

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);
            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
           /*
            * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
            * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
            * We read back the width after setting it, and if it differs from what we set,
            * we adjust our original value by the mismatch and set the width again.
            */           
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

Function call, placed inline immediately following table

<p:dataTable …>

</p:dataTable>
<script type=”text/javascript”>ss_FixTableHeaderWidth(‘frmTest’, ‘tblTable’);</script>

Iterating columns to set the width for each one individually

The following code sample uses the jQuery .each loop to iterate the header columns and set the width of each one to its matching data column (along with setting the table/row widths correctly). This sounds ideal for solving the header problems, but in practice it did not work well. The main issue is that jQuery reported a different value for the header column widths to that reported by the browser (via Firebug). The values were out by 1px, which caused an incremental mismatch in the column alignment as you go left to right. This approach was therefore abandoned in favour of just setting the RH header column size to auto to accommodate row size changes, as explained above. However, I reproduce the code here as it is a useful example of how to iterate a returned  jQuery object collection from a selector.

Function definition, column iteration version

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {

            /*
             *Fix incorrect table header width due to scrollbars
             */
            
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
           
            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }                       

            /*
             * Now iterate the columns with a jQuery each loop and set the header column width
             * to be the same as its corresponding data column width.
             * This is for illustration – the idea has been abandoned, as I found that Javascript/jQuery
             * reports a different value for the header widths to firebug on the final rendered page (out by 1px).
             * This causes an increasing mismatch between data columns and header columns as you go from left to right.
             * The column widths are only a suggestion and the browser may modify them anyway.
             * Therefore the final version, in SortTable.xhtml just sets the RH column width to auto
             * to take up the slack when the row width is changed, and leaves the others alone.
             * This appears to work much better.
             * However the iteration technique here is a useful working jQuery example.
             */
            var columnHeaders = jQuery(‘thead > tr:eq(0) > th’, headerTable);
            var firstRowCells = jQuery(‘tbody > tr:eq(0) > td’, dataTable);
            var columnCount = columnHeaders.size()
           
            columnHeaders.each(function(idx){
                    var columnHeader = jQuery(this);
                    if (idx < columnCount – 1) {
                       
                        var firstRowCell = jQuery(firstRowCells.get(idx));
/*
                        alert(‘idx=’+idx+’\n’+
                              ‘header width=’+columnHeader.width()+’\n’ +
                              ‘header csswidth=’+columnHeader.css(‘width’)+’\n’ +
                              ‘header innerWidth=’+columnHeader.innerWidth()+’\n’ +
                              ‘header outerWidth=’+columnHeader.outerWidth()+’\n’ +
                              ‘data width=’+firstRowCell.width()+’\n’ +
                              ‘data csswidth=’+firstRowCell.css(‘width’)+’\n’ +
                              ‘data innerWidth=’+firstRowCell.innerWidth()+’\n’ +
                              ‘data outerWidth=’+firstRowCell.outerWidth());
*/
                        var newWidth = columnHeader.width() + firstRowCell.outerWidth() – columnHeader.outerWidth();
                        //alert(‘idx=’+idx+’,width=’+columnHeader.width()+’, newWidth=’+newWidth);
                        //columnHeader.width(newWidth);
                        ss_setWidth(columnHeader, newWidth);
                    }
                    else {
                        columnHeader.css(‘width’, ‘auto’);
                    }
              });

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);

            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
            /*
             * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
             * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
             * We read back the width after setting it, and if it differs from what we set,
             * we adjust our original value by the mismatch and set the width again.
             */                       
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

No Comments »

March 9th, 2011
12:49 pm
Problems updating a checkbox in a Primefaces Table header

Posted under JSF
Tags , , , ,

With reference to my previous post, I found that a checkbox in a row cell in a Primefaces Table could not (from its value change listener) update a checkbox in the header. Per the previous post I was using component binding and calling UIInput.setValue() to update the value.

Strangely, another checkbox (checkbox B) outside the table was able to (again from its value change listener) update the checkbox in the table header.

More strangely, I then just moved checkbox B into a table row cell, and then found that it would not update the header checkbox.

I noticed that the checkbox row selection feature in the Primefaces showcase has the same issue – if you select all via the checkbox in the header, then all the rows become correctly selected. If however you then deselect a row, you would expect the header check box to deselect itself – however it does not.

As a further test, I tried it with Ajax, and was still unable to update the header checkbox from a row checkbox listener.

This Primefaces forum post may points to some possible causes, but its not clear cut. It certainly appears to be an internal issue to do with the Primefaces Table.

Workaround

One workaround to this would be to link the checkboxes client side with Javascript or jQuery. I resisted this because I will need to perform immediate actions elsewhere on the form based on a select click, so originally decided to do it all server side with listeners and (in the final solution) Ajax. However I may end up doing both – doing the at least some of linked selecting client side, but still using server side listeners for the other requirements.

Doubtless I will need to be careful that my own Javascript/jQuery does not interact negatively with the Ajax Javascript when implementing this. This post here points out that programmatic update of components via javascript does not fire events – only user actions cause events. In my case this need not be an issue – I could used javascript to cause row check box clicks to update the header check box. For example, if all rows were selected manually, I would tick the header box via script. Similarly, if then a row was deselected, I would untick the header check box. In each of those cases, I would not want or need any events to fire due to the header check box change. However, if the user explicitly clicked the header check box either way, I could use its listener to update all the row boxes (as I know this works) and to take any other action needed. whether in this latter case I allow the Javascript to update all the row boxes or not I am not sure – it is more consistent as then all the interlocking is in Javascript, but it will not cause row checkbox events to fire, so the header checkbox listener will still need to update all the selected properties for each row checkbox. If Javascript updates all the row boxes, then at least I don’t need to do any re-render of them which is more efficient. However, it is more complex as it involves iterating all the rows in script, although I expect this can be done pretty easily via jQuery.

No Comments »

March 8th, 2011
6:47 pm
JSF – changing input component values in a value change listener

Posted under JSF
Tags , , , , ,

My requirement on this one was to have some linked logic between select checkboxes on table rows and a ‘select all’ checkbox in the column header. Checking ‘select all’ should check all the row boxes. Then, unchecking one or more of the row boxes should uncheck ‘select all’ as the rows are no longer all checked.

Initially I had decided to get a whole test form working without Ajax, then apply the desired Ajax to all of it consistently. I had previously hit event timing issues due to mixing Ajax and HTTP submits on the same form. This gave rise to strange behaviour such as old queued events seeming to fire from nowhere, and events containing null arguments in method expressions. The basic wisdom on this is don’t mix Ajax and traditional HTTP submits on the same form – bad things will happen! I therefore decided to get the code logic working first with plain submits, by adding “onclick=’submit();’” to the checkboxes to force submits temporarily. The idea behind this was to avoid getting a mix of problems due to Ajax and problems due to other coding bugs, by eliminating the other coding bugs first.

The approach when doing this kind of thing is typically to set the components to immediate=”true” and call FacesContext.getCurrentInstance().renderResponse(); at the end of the value change listener to force an immediate rendering.

The problem I hit however, was that although I was correctly setting bean values for other checkboxes from the listener, the values were not being read again prior to renderResponse(),so the new values were not being displayed on the page. This is in fact standard behaviour. The way to update the values being rendered is to call setValue()  on the actual UIInput Component as well as writing the backing bean. To do this you need to get at the component instance, and the best way to achieve this is to use the binding attribute in the JSF page. For example, the following code fragments could be used in the JSF page and the managed bean:-

 

JSF Page

<h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                         valueChangeListener=”#{mainBean.selectedListenerB}”
                         binding=”#{mainBean.selectBoxBBinding}”
                         id=”chkSelectB” immediate=”true” onclick=”submit();”>
</h:selectBooleanCheckbox>

 

Managed Bean

private UIInput selectBoxBBinding;

public UIInput getSelectBoxBBinding() {
    return selectBoxBBinding;
}
public void setSelectBoxBBinding(UIInput selectBoxBBinding) {
    this.selectBoxBBinding = selectBoxBBinding;
}

 

Value Change Listener

public void selectedListenerA(ValueChangeEvent event) {
    boolean newValue = (Boolean)event.getNewValue();
    setSelectedA(newValue);

   //SelectedB is set to the same value as selectedA
    setSelectedB(newValue);
    selectBoxBBinding.setValue(newValue);
    FacesContext.getCurrentInstance().renderResponse();
}

This causes the new value to be displayed in the updated checkbox.  Binding to a component allows access to a number of other properties and methods as well, so gives a lot of flexibility. However, in most normal cases straightforward value binding is enough.

 

Using Ajax to achieve the same result

Ironically, if I had used Ajax on this issue, I would not have hit the problem. When Ajax is used, setting the new values in the managed bean is enough to allow them to be displayed directly on screen. The following JSF fragment shows how to use Ajax in check box SelectA in order to directly update check box SelectB without using a form submit. execute=@this causes the server side processing for SelectA to be performed (@this means the current component and is the default). render=”chkSelectB” causes the rendering to be peformed for SelectB, which displays the new value. Both execute and render take a space delimited list of client Ids, or special keywords such as @this, @form, @all, @non etc. The Ids can be prefixed with “:” to force Id scanning from the root where there are naming container issues etc. I am not covering any of this here. 

<h:outputText value=”Select Box A”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedA}”
                             valueChangeListener=”#{mainBean.selectedListenerA}”
                             id=”chkSelectA”>
    <f:ajax execute=”@this” render=”chkSelectB”/>
    </h:selectBooleanCheckbox>
<br/><br/>
<h:outputText value=”Select Box B”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                             valueChangeListener=”#{mainBean.selectedListenerB}”
                             binding=”#{mainBean.selectBoxBBinding}”
                             id=”chkSelectB”>
    </h:selectBooleanCheckbox>

No Comments »

March 6th, 2011
7:47 pm
Adding jsf view state to domain objects–part II

Posted under JSF
Tags , , , , , , ,

My original post on this is here.  It links to an Icefaces post which discusses using a decorator to do this. The fundamental problem is that you often want view state such as (but certainly not limited to) a selected flag on objects e.g. in tables. However, you do not want to pollute domain classes with view state, so it would not be desirable to add a selected flag to your domain objects as this blurs the layers (especially as you may have multiple different UI layers on the same domain, such as JSF browser clients, smart phone web clients, web services etc. all with different needs). Other examples of view state might be style classes to be used on different table rows in response to use actions etc.

Since my original post I have looked at other ways of achieving this, and summarize various approaches below which could be used to add view state to rows of a table.

In each case, assume initially we have a JSF table of the form <h:dataTable var=”row” value=”#{mainBean.rows}”>, where each row object has the properties firstName and surname, plus the need for a selected boolean flag to be maintained separately from the row.

 

1/ Using a row decorator

My original post discusses using a decorator to add the extra state, as per the icefaces post. This involves wrapping every row, but is transparent to the code. The downside of the decorator is that each domain class requiring the extra state needs its own decorator even though each case might require the same extra state. This potentially means a lot of extra classes just to add a selected flag.

 

2/ Using a generic row wrapper class composed with the row

A second alternative which is similar to the decorator would be just to use a wrapper class which holds the extra state plus the domain class instance, and explicitly make the calls to the domain class methods and properties. Thus, the following code might be used to read our table row properties and the selected flag (all the examples use direct instantiation for simplicity) :-

//wrap a row. rowWrappers is the list containing the wrapped rows
rowWrappers.add(new RowWrapper<Row>(row));

// read properties on a facelets page – note that the table now contains wrapped rows:-

<h:dataTable var=”rowWrapper” value=”#{mainBean.rowWrappers}”>,
<h:outputText value=”#{rowWrapper.row.firstName}”>
<h:outputText value=”#{rowWrapper.row.surname}”>

//read the selected flag on a facelets page
<h:outputText styleClass=”#{rowWrapper.selected ? ‘style1’ : ‘style2’}” value=”…”/>

The pros and cons of this approach are:-

  • All the rows need to be wrapped as before.
  • All the ‘delegation’ to access row properties is explicit in all the expressions.
  • The upside however is that to add a given set of view state properties, only a single class is needed and this can wrap any number of domain classes generically, which can be a significant advantage.

 

3/ Using a Map to hold the additional row state objects

A third approach makes use of the fact that JSF EL value expressions can transparently read Map entries just like properties. Therefore where object m is a map or object that implements java.util.Map, the equivalent expressions m.property1 and m[‘property1’] when reading a value (i.e. on the right hand side of an expression, or rvalue mode) both result in

m.get(‘property1’)

being executed. When writing a value (i.e. on the left hand side of an expression, or in lvalue mode), as in m.property1 = rhsexpression, the statement

m.put(‘property1’, rhsexpression)

will be executed, assigning rhsexpression as the value of property1.

This technique allows us to use the row object itself as a key to the map containing the additional row state:-

//add row state object to map
rowFlagsMap.add(row, new RowFlags());

// read properties on a facelets page :-

<h:dataTable var=”row” value=”#{mainBean.rows}”>,
<h:outputText value=”#{row.firstName}”>
<h:outputText value=”#{row.surname}”>

//read the selected flag on a facelets page using the current row as a map key
<h:outputText styleClass=”#{mainBean.rowFlagsMap[row].selected ? ‘style1’ : ‘style2’}” value=”…”/>

Note that the nested expression evaluation works correctly with the map as the ‘man in the middle’ and that the expression mainBean.rowFlagsMap[row].selected could be used equally to fetch any other property from the rowflags object instead of the selected  property. The expression works as we would expect in both lvalue and rvalue modes, such that if for example the above property value was written to as true from the jsf page (e.g. from the value property of an updated check box we had just ticked), the expression would execute correctly as

mainBean.rowFlagsMap.get(row).selected=true;

The pros and cons of this approach are:-

  • We need an extra map access to get the row state, but for typical table sizes a hashmap would give very efficient access and should not be an issue.
  • We need to use the more complex expression mainBean.rowFlagsMap[row].selected  to fetch the additional row state. However, the plus is that we do not have to wrap each row in the code, and assuming that there are more table properties than additional state, we do not have to explicitly use a nested expression for them as we would in the previous approach.
  • When using this approach, it must be born in mind that you are using an object as a Map key. This should not be an issue, but if you override the hashCode function such that the hash value could change during the lifetime of a row object (for example if a row property changed) you would need to take account of this. Note also that rows in the map will only correctly match the exact same objects. If you refetch the same domain objects again from your entity manager you cannot expect them to match any existing objects in the map. Again, this should not normally be an issue as you would expect to rebuild the map from scratch when refetching domain objects from persistent storage.

 

4/ Using a Smart Map Interface to implement a selected property by storing the selected row objects

This approach is similar to the previous one, in that it uses a Map interface to hold a selected flag. The difference is that we implement our own class implementing  the Map interface and hide a map behind it. Our Map class simply stores each selected row in a ‘real’ map. When the caller reads the selected flag for a row by calling map.get on our map class, we perform a contains call on the ‘real’ map and return true if the row is present, or false if it is not. Similarly, when asked to set selected =true for a row, we just add the row to the ‘real’ map. When asked to set selected=false for a row, we remove it from the ‘real’ map. The pros and cons of this approach are:-

  • We only need to store the selected rows in the map, so we are storing less map entries.
  • The expressions to check the selected flag are a bit simpler, requiring something of the form mainBean.selectedMap[row]
  • Conversely, we need to implement the smart map – this needs quite a number of dummy methods when implementing the Map interface. When implementing this, I typically create an abstract base class which dummies out most of the java.util.Map methods which I don’t need, and then extend this for a desired implementation. This project in the repository makes use of this technique – see the classes uk.co.salientsoft.view.JSFValueMap and uk.co.salientsoft.view.SelectedMap.
  • The other downside is that this method only allows storage of a simple boolean based on the presence or absence of a row. If we need more additional row state, we need to look to one of the other methods.
  • As with the previous method, we are using a row object itself as a map key, so the same caveats apply as in the previous case.

 

Conclusion

As is often the case, there is no clear winner – you take your pick depending on individual requirements and the various pros and cons. Overall, my current favourite in general is to use the additional Map. It is simple to implement (you don’t need to dummy a load of Map methods like you do with the smart Map). Unlike the smart Map, you can add any number of additional properties to a row. The domain row properties can be accessed exactly as before, and you don’t need to wrap every row (however you do need to create the row state object and add it to the map for every row). Whilst the access to the additional state requires a slightly more complex expression, this is likely to be needed less often than expressions to read the domain properties.

No Comments »

March 4th, 2011
5:48 pm
Breadcrumb Composite Component using ui:repeat

Posted under JSF
Tags , , , , , , ,

Update 16/1/2012

A bug was found in the crumb styling. max-width was correctly set on the crumbs to truncate them, but when white space is present in a crumb, the default is to wrap at the max-width. This causes the breadcrumb to increase in height and add a second line. The fix was to turn off the wrapping by setting “white-space:nowrap” in the css for the crumb anchor tags (see Mantis issue 99 for details) :-

.ss-breadcrumb ul li,
.ss-breadcrumb ul li a {
    overflow:hidden!important;
    display:inline-block;
    white-space:nowrap;
    text-decoration: none;
}

 

Original Post

This follows on from my previous posts on the Primefaces breadcrumb here  and here.

I found a couple of further important issues I hit when using the standard breadcrumb:-

  1. In order to add and remove crumbs dynamically, it uses the Primefaces MenuModel. Methods of the MenuItem class are used to add actions and listeners.
  2. The mechanism seems somewhat cumbersome. In particular, it does not appear to be easy to pass a particular target object as an argument to an action or listener method, as the binding appears to be created as a string. Ideally what I would want is for the breadcrumb entries to be created by iterating a list using a var attribute like a table, and then to pass the var object containing the current crumb in the list as an argument in a method call to an action when that crumb was clicked.
  3. The only way I could see to do it involved passing an identifier for an object (such as the primary key for an entity). Whilst I certainly did not bottom it out completely, the mechanism seemed somewhat complex to use and lacking in flexibility.

Adding these issues to the ones already highlighted in the other posts (in particular the slowness of the jQuery operations when initially collapsing a breadcrumb in preview mode), I decided to take the step of rolling my own custom breadcrumb. The following approach was taken:-

  1. I decided to use a composite component rather than create a full blown custom component in code, as this looked more straightforward, and I had experience of composite component creation.
  2. The key factor which made this possible was that I could use ui:repeat to build the breadcrumbs dynamically from a list.
  3. Conditionally rendered xhtml tags could be handled using ui:fragment within the ui:repeat loop. This allowed the use of the rendered attribute on ui:fragment to optionally render sections even when standard non-jsf html tags such as <li> were used. For example, the root crumb of the component is rendered differently to the others, using an icon only. Also, full width crumbs are rendered differently to truncated crumbs (when truncating the component to fit a target width)

The following are the key features and design points for the breadcrumb:-

  1. The component is designed specifically for dynamic use, being driven from a list much like a table. It is not possible to build it statically on the facelets page (static use is covered by the standard control so this was specifically a non-goal/non-requirement).
  2. It is rendered entirely statically, so there is no (potentially slow) javascript/jQuery stuff going on at render time or during use.
  3. Compression to fit a target width is done by passing the desired target width in to the control. This is then used to set max-width css properties on the crumbs. This allows the crumbs to take the width they need and to only be truncated when they hit the max value. The max value is calculated on the server at render time by dividing the max target width by the number of crumbs to be rendered (allowing for the root crumb as a special case).
  4. The full text for a crumb can be viewed at any time by hovering over the crumb – it is displayed using the HTML title attribute. This is one annoyance with the standard Primefaces control – it does not allow use of the title attribute. Using the title  attribute allows the control to be static on the page for speed but still allows truncated crumbs to be easily read.
  5. The component supports the concept of stale crumbs. The idea is that when moving back up the crumb path (leftwards, or navigating up a tree path), the crumbs to the right which were previously visited are not immediately removed. They are highlighted differently as non bold and italic to make them less important compared to the ‘fresh’ crumbs on the path. In addition, the current crumb is underlined in order to make it completely clear where the current position is. Without stale crumbs present, this would normally be the rightmost crumb, but this will now no longer be the case if stale crumbs are present.
  6. Stale crumbs are only removed if the user navigates down a different tree path which invalidates them, in which case they disappear. Provided the user remains on the same tree path, the crumbs will be left in place.
  7. The stale crumbs may be clicked for navigation just like the fresh ones, to allow the user to revisit old ‘stale’ locations. When a stale crumb is revisited, it changes back to a fresh crumb again (as do all other stale crumbs to its left) and it becomes the current crumb – it is therefore rendered in bold, non-italic, and is underlined. The crumbs to the right of it if any still remain stale as they were before.
  8. To assist navigation up a tree structured hierarchy, it is common to include an ‘up’ button somewhere. This is taken a step further by including both up (= left pointing) and down (=right pointing)buttons on the left hand side of the breadcrumb component. When combined with stale crumb support, this feature allows easy navigation both up and down a given tree path. The right button is only enabled when stale crumbs are present, and clicking it moves down the stale crumb list just as if the next stale crumb was clicked. Navigating to the root of the tree (leftmost crumb) disables the left button.
  9. The component is styled in a similar way to the standard Primefaces component, and uses the same CSS classes for the styling.
  10. Styling may be modified, and features such as up/down support turned on or off.
  11. The component is styled using an inner div which holds the component itself – this can be floating if desired in which case it resizes the width to hold its contents. The inner div is contained in an outer div which is typically fixed in size to suit the page, allowing the inner div to scale up to that size. The width used for crumb truncation calculation is passed separately into the control – this will normally be slightly less than the max width set for the divs.
  12. The component is backed by a controller backing bean, BreadcrumbCtrl/BreadcrumbCtrlImpl, which may be subclassed to allow further customisation. The crumbs are passed into the bean as a simple generic list, and a property name used for the crumb text display is passed as a string attribute to the composite component. The controller fields action and listener events from the component, and passes them on using a BreadcrumbEvent interface – an object implementing this interface is passed into the controller bean at init time. When the user clicks on a crumb, the actual crumb in the list plus its list index are simply passed to its action method. When multiple components are used on a page, each will have their own controller object. These will typically be injected into the page backing bean e.g. by CDI as dependent beans. When the action and listener events are called, the actual controller object is also passed. This would allow for example the page backing bean to implement BreadcrumbEvent and manage actions for a number of dependent breadcrumb controllers, using the passed controller object to determine which one was clicked.

The following are some of the key technical issues which arose during development of the component:-

  • ui:repeat is used for iterative xhtml generation of the crumbs. This uses a var attribute like a table to represent the current object (crumb) in the list. It also supports a varstatus attribute which allows access to various loop properties within the loop, such as the current loop index, first and last boolean properties and others. The index property in particular is used to determine styling for the current crumb and stale crumbs etc.
  • In addition, the varstatus object (com.sun.faces.facelets.tag.jstl.core.IterationStatus) can be accessed from the controller bean using code similar to the following, where varStatusKey is the name given in the varstatus attribute to ui:repeat:-

Map<String, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
IterationStatus varStatus = IterationStatus) requestMap.get(varStatusKey);

  • It is important to note that whilst it is tempting to cache the varstatus object in the controller bean, this does not work – a new object must be obtained each time using the above code.
  • ui:fragment can be used directly in the ui:repeat loop within the composite component implementation – it is not immediately obvious from the documentation that this is the case.
  • When declaring the attributes for the composite component using <composite:attribute>, note that the type attribute allows specification of a particular object type, the required attribute makes an attribute mandatory, and the default attribute sets a default.

The source code and a usage example of the breadcrumb control may be found in the repository here.

No Comments »

February 11th, 2011
5:49 pm
Further h:outputStylesheet issues

Posted under JSF
Tags , , , , , , ,

I needed to load a custom style sheet for a composite component.

Primefaces has problems loading theme images correctly when using h:outputStylesheet as per here, but using a raw link tag was no good as I wanted to develop a custom component which loaded its own styles, i.e. it had no <head> section.

This post here indicates that if you don’t use the library attribute you can get h:outputStylesheet to work even with Primefaces themes.

In my case, I was not loading themes/images etc. so this was not an issue, but I still used the following directive and avoided use of the library attribute for simplicity:-

<h:outputStylesheet name=”uk.co.salientsoft/util/SSBreadcrumb.css”/>

This version worked. My initial attempts (which failed with a resource loading error) were as follows :-

<h:outputStylesheet name=”resources/uk.co.salientsoft/util/SSBreadcrumb.css”/>

<h:outputStylesheet name=”#{request.contextPath}/resources/uk.co.salientsoft/util/SSBreadcrumb.css”/>

In other words, with a css file stored in Eclipse under WebContent/resources/uk.co.salientsoft/util/SSBreadcrumb.css,  the above working example was correct, i.e. to load correctly, omit the context root and the resources level and use a relative reference without the preceding slash.

I did try to debug this by visiting the logger settings in Glassfish admin, then under the Log Levels tab, setting everything with JSF in it to finest! This did display an error when trying to load the resource:-

[#|2011-02-11T17:21:13.331+0000|FINE|glassfish3.0.1|javax.enterprise.resource.webcontainer.jsf.application|_ThreadID=31;_ThreadName=Thread-1;
ClassName=com.sun.faces.application.resource.ResourceHandlerImpl;MethodName=logMissingResource;
|JSF1064: Unable to find or serve resource, /SSBreadcrumb/resources/uk.co.salientsoft/util/SSBreadcrumb.css.|#]

However the error was not particularly informative as it just spat back to me the path I gave it to load. It would have been nice for it to tell me how it was mapping the path as then I could have seen the problem more easily.

Note however that using this page in Glassfish is a very convenient way to turn on logging in Glassfish, as it lists the common logger paths for you and gives a combo to select the level for each. You don’t have to go googling for the logger paths and edit a log properties file yourself. Note also that when you do this you must restart Glassfish for the log level changes to actually take effect.

No Comments »

February 2nd, 2011
7:56 pm
Primefaces Table Sorting–Common Gotchas

Posted under JSF
Tags , , , , , , , ,

Update 2/2/2011

According to this post here by Cagatay Civici, the Primefaces Project Leader, as at Primefaces 2.2M1, client side datatable is not supported and the dynamic attribute is deprecated from then on.
Seemingly it was becoming too hard to support all the table features on both client and server sides.
It is a shame that this was not documented better and more widely – the user manual still documents the dynamic attribute, and there are a number of posts about client side sorting (though in fairness they probably predate 2.2M1).

This behaviour exactly ties up with what I am seeing in my testing – the dynamic attribute does nothing, sortFunction is ignored, and all sorting is done via Ajax server side.

Original Post 2/2/2011

Having successfully got sorting working I was frustrated to find that a new simple example failed to work. Primefaces table sorting is pretty much transparent, requiring minimal effort and working out of the box. The lessons learned on this one are instructive so I summarise them below.

Details of Example and Problem

  1. The example fetched a list using JPA, stored the list in a view backing bean, then displayed it in a table with a sortable header.
  2. When the header was clicked, the up/down arrows were correctly displayed, but the data was not sorted – it was as if the request was ignored.
  3. It was not immediately obvious how the header click was handled – there was no obvious click event on the HTML element, and I could not see any Javascript running after a quick test with Firefox/Firebug. I gave up this line of attack but may look into it later as to how it all works. Some dynamic CSS pseudo classes/jQuery trickery may be involved.
  4. I was not certain as to whether the table was client side or server side/Ajax, even though it should have been client side by default. To diagnose the problem, I changed the value of the sortBy attribute in the column header to be an invalid bean property. The symptoms did not change, but an errors were logged in the Glassfish server log for each header click – “[#|2011-02-02T18:22:14.557+0000|SEVERE|glassfish3.0.1|org.primefaces.model.BeanPropertyComparator|_ThreadID=24;_ThreadName=Thread-1;|Error in sorting|#]”.
  5. This showed that the sort was being attempted but was failing due to the invalid property, which indicates that the sort was attempted server side. According to the Primefaces forum, for client side sorting, the sortBy property is not used as the displayed data is sorted.
  6. Interestingly, I would have expected Primefaces to use a client side table by default, but clearly it was not. Changing the dynamic property on the table tag to false explicitly had no effect and the behaviour was unchanged, so I will need to investigate client side tables further as for small data sets they are faster – I will update this post when I have done this.
  7. I turned on FINEST logging with Eclipselink in persistence.xml. Use <property name="eclipselink.logging.level" value="FINEST" /> to do this, and note that you need to bounce Glassfish to for a logging level change to be picked up. I noticed after this that the JPA query seemed to be rerunning very often, perhaps for every click of the sort header. This lead me to wonder if the backing bean was being recreated each time.

 

Cause and Solution

In the end, it was simply that I had not annotated the JSF backing bean as @SessionScoped (the example used CDI throughout, and did not use JSF managed beans). This meant the bean was request scoped by default, and was indeed being recreated – the sort was trying to do the correct thing, but the data was getting reloaded from the database in the original sort order each time!

Adding the correct annotation as above (and making a couple of the beans correctly implement serialisable to satisfy CDI/Weld) solved the problem.

This is a good example of where a problem cause is not immediately apparent from the symptoms.

Sample JSF page fragment showing the form containing the table

<h:form id="frmTest">   
    <util:themeSwitcher form="frmTest" outerStyle="clear: both; float: left; margin-bottom:20px;" innerStyleClass="ui-widget"/>
    <h:panelGroup layout="block" style="width:300px;">   
        <p:dataTable var="taxonomyNodes" value="#{taxonomyBrowser.taxonomyNodes}" scrollable="true"
             styleClass="clear #{fn:length(taxonomyBrowser.taxonomyNodes) lt 20 ? ‘ss-tableheader-scrolladjust-nobars’ : ‘ss-tableheader-scrolladjust-bars’}"
             height="460" > 
             <f:facet name="header">
                Client Side Sorting
             </f:facet>
             <p:column headerText="Category List"  sortBy="#{taxonomyNodes.text}">
                 <h:outputText value="#{taxonomyNodes.text}" />
             </p:column>           
        </p:dataTable>
    </h:panelGroup>
</h:form>

No Comments »

December 6th, 2010
10:45 am
Customising the Primefaces Breadcrumb control

Posted under JSF
Tags , , , , ,

This control has a preview mode which dynamically shrinks and expands the links on hover. Nice idea, but it’s rather slow to render the page on load when there are many entries, as the initial compress is done by jQuery so lots of JavaScript going on.

My preference when a lot of entries are present would be to render the control statically, and instead of dynamically expanding the entries, to have them permanently compressed but with tooltips (= html title attribute) to show the full entry on hover (as suggested here in Jenifer Tidwell’s excellent book Designing Interfaces). This would be much faster.

Unfortunately, the current control does not support that – the menu item children that make up the breadcrumb entries do have a ‘help text’ attribute which looks like it should render a title/tooltip but this does not work.

I would like at some point to make a custom version. The best way would probably be to make it a new different control, possibly in my own library but at least as an additional Primefaces control that I could easily deploy on new released without having to customise code.

Chapter 11 of Core JavaServer Faces has a good example walkthrough of a full custom component development, which helps to give a background. Customising the breadcrumb looks easy as it is just a question of enhancing existing code by adding some additional attributes and changing the encoding in the renderer to encode titles and do a static breadcrumb. The following functionality would be needed:-

ToolTipMode attribute to turn on the new mode. Other modes would possibly still be present  – no point in disabling them unless I have too. If it looks like carrying the old modes is a lot of baggage I could create a stripped down control using the old one as a framework, and only support the new modes I require. As I am keeping the existing control there is no need to duplicate its features if I don’t need to. As the rendering for the new control should be straightforward, I could even rip out all the jQuery stuff and just use some of the existing CSS techniques for rendering it, but statically. I would duplicate the classes and give my own names.

In the new mode, all entries would have a hover title.

  • ToolTipCompressThreshold attribute would be a character count for the whole breadcrumb which would trigger compression of all entries equally. This is obviously a static guess figure, but it avoids having to do any client side stuff in JavaScript and so will render fast.
  • ToolTipMaxLength attribute would be a notional maximum length in pixels for the breadcrumb (set separately from the css). When the compress threshold has been reached, this attribute would be divided by the number of breadcrumb entries to be rendered, and the resulting value used as the maximum pixel size for rendering each entry (it would be good to allow them to be shorter if they don’t use all the space, so it does not look odd). Rather than strip out characters from the entries, I would just hide the excess width via a hidden overflow in a div (as the existing control does now).

The source is all available in the source or bundled zip download. Note the following from a first look:-

  • BreadCrumb.java contains the properties for all the attributes – all driven from an enum with custom methods in it (note the technique, could use this as it enforces consistency and avoids typos etc.)
  • BreadCrumbRenderer.java renders all the html and js calls.
  • BreadCrumbTag.java – note that Primefaces 2.2M1 had this file, but 2.2RC2 does not have it. Check/compare the code – they either simplified it or it has gone missing from the latest release. I could base my version on either.
  • MenuItem.java – will probably want to look at this as each BreadCrumb item is a menu item.
  • primefaces-i.taglib.xml and primefaces-p.taglib.xml are the taglibs – I will need to define a taglib for mine (see core Javaserver faces again). Note that these are in the deployed jar but not in the sources jar.
  • faces-config.xml – defines all the component classes. As with the taglibs this is in the deployed jar but not the sources jar.

No Comments »

December 3rd, 2010
12:17 pm
Using the Primefaces Breadcrumb Component

Posted under JSF
Tags , , , ,

I did some experimentation on the best look and feel (in my humble opinion!) for this component, and found the following points along the way:-

  • By default the component was underlining all the entries. This was because all anchor tags were being underlined. The Primefaces showcase has specific rules in default.css to turn this off, so I added them too. (You might have expected this to all be done by the themes or breadcrumb css, but not the case). I just added “a {text-decoration: none;}” and “a:hover {text-decoration: underline;}” rules, but obviously there are other ways if you want other links to be underlined.
  • I then tried to place a breadcrumb in a scrolling div, to ensure that it would still work if the content overflowed. I knew that horizontal scroll bars on a breadcrumb would not look at all sexy, but wanted at least some solution for edge cases with extreme amounts of content, as by default the component truncates to the right and content is lost/not accessible. I was unable to solve this issue – the component would not play ball. I wanted to leave an inner div containing the component at a floating size, so that the control sized itself for the content, and then add a scrollable outer div with overflow:auto so that it would scroll if needed. However, the component appears to use some jQuery magic to detect the size of any fixed ancestor outer level div of the component, and then fix the control width to that size using inline styling added to one of its own inner divs by jQuery/Javascript. The only partial solution was to have a large fixed size component in a smaller outer scrolling div, but this was not good as the scrollbars were present even if not needed as the control had a fixed size.
  • The problem could probably be solved using jQuery, perhaps by modifying the jBreadcrumb jQuery component which Primefaces uses, but I did not investigate this further.
  • In the end, I reconciled myself with the default way the component works. It does have a good solution to this issue by (optionally) dynamically collapsing the entries to a designated preview width, and then expanding an entry on mouse hover (so-called preview mode). This does save a lot of space, and I decided that I could easily have more than enough entries for my needs in say an 800 pixel wide breadcrumb. Alternatively the component can be left to float entirely and rely on the browser for scrolling, but in practice there will generally be an outer container of some kind which will set a limit and trigger the above issue. In my case, this would likely be an outer level tab for a form.
  • I also decided that in practice it would be helpful to turn the preview mode on dynamically, perhaps say when the number of entries exceeded a certain number, or better still when the total character count in the breadcrumb exceeds a certain figure, as this would give good results on average and still be easy to calculate. For normal use, when there is plenty of room left in the breadcrumb, preview mode is a nuisance, but it is obviously essential when the component fills up. Ideally, this would be done when the component is filled rather than based on an entry count, but this would be tricky to calculate. Ideally this would be done dynamically by the component itself. Best of all might be a dynamic preview mode which shrinks the entries only when required and only enough to fit everything in the component.
  • Rendering the component in preview mode takes significant time when there are a lot of entries (even on my Core I7 920). This might be an issue when partially updating a page (and the component) during navigation. This is even more reason not to use preview mode unless it is really essential, as with it turned off the breadcrumb renders very quickly. On some occasions it would be possible to update the control client side, for example when just changing the underline/italic decoration on the text (see below re traversing a hierarchy) and no entries are added or removed. In this case the necessary classes could just be added and removed from the breadcrumb entries dynamically with jQuery. I have also not tried any Ajax/partial form updates with it, for example just adding or removing a single entry, but I expect the whole component will be re-rendered each time as the manual makes no mention of partial updating.
  • I experimented a bit with the expand and contract timings in preview mode. These interact with the time taken by the JavaScript to dynamically collapse the entries when the component is first rendered, so if you try to make them too fast it looks clunky. Also if the expand is too fast it can confuse you as to which entry you are hovering on, especially when there is a lot of preview compression, as you can end up highlighting the next entry along without realising it, just due to the expand/collapse effect.
  • One common use case for me is to use the component to hold the navigation path when traversing a hierarchical data set. A desirable feature would be that when you traverse back up the tree say by clicking on one of the higher levels in the breadcrumb, you do not immediately lose all the lower levels you visited. They would only be removed if you visited a higher level and then traversed down a different lower level path at some point, in which case the lower levels visited previously beyond that point would then be removed and a new path built.
  • The nice thing about the above concept is that you can repeatedly wander freely up and down a given tree path via the breadcrumb without losing any of the context, which is handy in my case as the UI deliberately only shows the current level of the tree in a table – no tree or treetable components are used in order to keep things intuitive and simple for novice users.
  • When applying this concept, it is necessary to highlight the current location in the breadcrumb, as this will no longer always be the rightmost entry. The most logical way to do this seemed to apply the same highlight as the mouse hover, which is to underline an entry. Therefore, the current entry will always be underlined, as will any other entry that is hovered over.
  • In addition, it is desirable to distinguish between the breadcrumb levels between the root and the current point from those previously visited below the current point, as the breadcrumb is no longer only showing the path to where you currently are. I tried various kinds of dimmed, disable style highlighting, but whilst it is important to make these previously visited lower level entries look different, it must also be clear that you can still click on them. In the end, my preferred solution which looks good in all the top 5 browsers and with all the Primefaces themes was to italicise the previously visited lower level entries. You therefore end up with ‘normal’ styling up to the current level. The current level itself is then shown underlined so it is clear where you are. All the entries to the right (if any) are then italicised.

The following example shows my preferred component, which is somewhat thinner than the default due to the removed padding. Examples of the different highlighting discussed above are all just coded directly into the menu options. The example also uses my theme switcher component which is not listed.

 

index.xhtml

<!DOCTYPE HTML>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"   
xmlns:util="http://java.sun.com/jsf/composite/uk.co.salientsoft/util">
<f:view contentType="text/html">
<h:head>
    <util:themeSwitcher    outputStyle="true"
                        themeBase="/resources/themes"
                        defaultTheme="redmond"/>
<style>
    .ui-widget {
        font-size: 75% !important;
    }
    h1.header {
        font-size: 1.2em !important;
        padding: 5px;
        margin: 0px 0px 20px 0px;
        float: left;
    }
    .themeswitcher {
        float: left;
        clear: both;
        margin-bottom: 20px;
    }   
    .ss-breadcrumb {
        clear:both;
        margin: 0 0 10px 0;
        padding: 0;
        width:800;
    }   
    a {text-decoration: none;}
    a:hover {text-decoration: underline;}
    .ss-currentlevel {text-decoration:underline;}
    .ss-lowerlevel {font-style: italic;}
</style>

</h:head>
<h:body>
<h1 class="header ui-widget ui-widget-header ui-corner-all" style="">Breadcrumb</h1>

<h:form id="frmTest">
<util:themeSwitcher form="frmTest" outerStyleClass="themeswitcher"/>
<br/><br/>
    <p:breadCrumb styleClass="ss-breadcrumb" preview="false">
        <p:menuitem value="Categories" url="#" />
        <p:menuitem value="Sports" url="#" />
        <p:menuitem value="Football" url="#" />
        <p:menuitem value="Countries" url="#" styleClass="ss-currentlevel"/>
        <p:menuitem value="Spain" url="#"  styleClass="ss-lowerlevel"/>
        <p:menuitem value="F.C. Barcelona" url="#" styleClass="ss-lowerlevel"/>
        <p:menuitem value="Squad" url="#" styleClass="ss-lowerlevel"/>
        <p:menuitem value="Lionel Messi" url="#" styleClass="ss-lowerlevel"/>
        <p:menuitem value="Squad" url="#" styleClass="ss-lowerlevel"/>
        <p:menuitem value="Lionel Messi" url="#" styleClass="ss-lowerlevel" />
    </p:breadCrumb>
    <p:breadCrumb styleClass="ss-breadcrumb" preview="true" previewWidth="24"
        expandEffectDuration="400" initialCollapseEffectDuration="100"
        expandedBeginningItems="1" expandedEndItems="1">
        <p:menuitem value="Categories" url="#" />
        <p:menuitem value="Sports" url="#" />
        <p:menuitem value="Football" url="#" />
        <p:menuitem value="Countries" url="#" />
        <p:menuitem value="Spain" url="#" />
        <p:menuitem value="F.C. Barcelona" url="#"  styleClass="ss-currentlevel"/>
        <p:menuitem value="Squad" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Lionel Messi" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Categories" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Sports" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Football" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Countries" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Spain" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="F.C. Barcelona" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Squad" url="#" styleClass="ss-lowerlevel" />
        <p:menuitem value="Lionel Messi" url="#"  styleClass="ss-lowerlevel" />
    </p:breadCrumb>
</h:form>
</h:body>
</f:view>
</html>

No Comments »