The last couple of days have been one of those 'why is this so difficult' moments. I essentially lost more than a day trying to figure out how to get HTML5 canvases to show up in one of our JSF applications. Here is the background on the stack:
The initial result:
Initially what we saw was when initial load happened on the page the canvas(es) showed up appropriately.
What's up?: Was there a Javscript error? What was being returned. The what's up is always the part that ends up eating up hours or days. I'm not going to go through all of the tribal and tribulations, but will point out the key points along the way to the solution.
A key tool in this whole discovery were the developer tools available within Chrome. If you are not familiar, certainly get familiar with them or at least the respective developer tools within your browser of choice. We monitored the javascript execution within our logic. There were no errors and the paintCanvases() function was appropriately getting called.
The key hint: It wasn't until I decided to monitor and inspect the state of the DOM post the AJAX call that it triggered something odd was happening. None of the content for the canvas tags was being included in the response. The canvas tags and all attributes were disappearing. All of the other dynamic content created from the AJAX request was being included appropriately.
The resolution: Richfaces uses a filter for correction of code on an AJAX request. The default configuration was removing all of the canvas related content. You can read up on the filter configuration here. We switched the configuration to use the NEKO filter.
- JBoss AS 7.2.0
- JDK 1.7.x
- Seam (JSF Framework) v2.2.0
- Richfaces v3.3.3
Essentially we wanted to introduce a canvas to our page in order to graphical represent a numeric value and where it falls upon its normal range and possible range of values.
The page was leveraging a <ui:include> in order to display the results section. It was a common component used among multiple pages and therefore the reason being pulled in via an include. A richfaces commandLink was being used to initiate an AJAX request that would pull back none, one or many results and re-render the display within a JSF panelGroup.
Canvas Background:
If you look at any of the examples of using HTML5 canvases, you generally will see the definition of the <canvas> tag and its appropriate attributes and then a javascript function defined. The javascript function gets called usually on page load to paint the actual canvas(es). We were utilizing JQuery in order to bind the painting function to all canvas elements within our page div. We set up the JQuery selector to select canvases with a certain id (i.e <canvas id="numberRange" ... ></canvas>).The Path:
It was pretty easy to set up the number range displays as we already had an existing javascript library that included the function for painting the canvas. We included the library into our .xhtml page and defined the canvas locations. We defined our handoff function which included the JQuery selector. The selector identified the applicable elements and then called the paintCanvas() javascript function for each matched element.The initial result:
Initially what we saw was when initial load happened on the page the canvas(es) showed up appropriately.
Then after the date range was changed and the search was clicked, an AJAX request initiated, the resulting display did not show any canvases.
The common issue:
Generally these type of issues can be caused by the fact that you need to remember there is just a partial page load occurring. An AJAX request that repaints a section of the screen does not result in a reload of the full page/DOM; therefore the document.load() is not re-triggered. This would mean the JQuery $(document).ready would not be triggered and therefore our painting of canvases would not be initiated.
However we were using the commandLink from richfaces. The component allows you to specify a javascript function to call when the AJAX request completes. We double checked the component definition and the proper function was being included on the oncomplete attribute of the tag.
<a4j:commandlink action="#{controller.search}" onclick="ajaxSpinOn();showSearching();" oncomplete="ajaxSpinOff();paintCanvases();" rerender="content" value="Search"> </a4j:commandlink>
What's up?: Was there a Javscript error? What was being returned. The what's up is always the part that ends up eating up hours or days. I'm not going to go through all of the tribal and tribulations, but will point out the key points along the way to the solution.
A key tool in this whole discovery were the developer tools available within Chrome. If you are not familiar, certainly get familiar with them or at least the respective developer tools within your browser of choice. We monitored the javascript execution within our logic. There were no errors and the paintCanvases() function was appropriately getting called.
The key hint: It wasn't until I decided to monitor and inspect the state of the DOM post the AJAX call that it triggered something odd was happening. None of the content for the canvas tags was being included in the response. The canvas tags and all attributes were disappearing. All of the other dynamic content created from the AJAX request was being included appropriately.
The resolution: Richfaces uses a filter for correction of code on an AJAX request. The default configuration was removing all of the canvas related content. You can read up on the filter configuration here. We switched the configuration to use the NEKO filter.
Switching to the NEKO Filter
- First we needed to add the maven dependency for the NEKO library. The library is not pre-packaged with the rich-faces library so you must explicitly include the library. This POST may be helpful in regards to miscellaneous setup for Richfaces 3.3.3
- In your web.xml file add the following context-param for the filter configuration (changing from the default, TIDY).
<dependency> <groupId>nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.6.2</version> <scope>runtime</scope> </dependency>
<context-param> <param-name>org.ajax4jsf.xmlparser.ORDER</param-name> <param-value>NEKO</param-value> </context-param>
Finally
Then with a rebuild and deploy, canvases starting displaying appropriately. Hopefully this may save a few other developers a few hours.
Comments
Post a Comment