Posts Tagged Ajax
Detect if JavaScript is enabled
Because of the emergence of Ajax, people don’t disable JavaScript much nowadays.
I don’t know the percentage of people having disabled JavaScript. It is likely under 5%. But if you have a website visited by millions of visitors every month, even 1% is matter!
This is why I wrote the following code:
<noscript>JavaScript is DISABLED.</noscript> <span id="displayIfJavaScript" style="display:none">JavaScript is ENABLED.</span> <script> document.getElementById('displayIfJavaScript').style.display = "block"; </script>
The text under the noscript
tag will be displayed if JavaScript is disabled or not supported. The text under the span
tag is not displayed by default and will be showed using JavaScript, this is why we can be sure JavaScript is enabled in that case.
You can obviously change the content of the noscript
and span
tags. You could, for example, hide a form which uses JavaScript validation to non-JavaScript users by putting the HTML code of the form under the span
tag.
Please see below the above script in action:
The selfRendered attribute
This is an interesting problem related to the RichFaces rich:suggestionbox
tag.
Let’s take the following code:
<rich:suggestionbox for="q" minChars="1" suggestionAction="#{myBean.mySuggestionAction}" var="result" limitToList="true"> <h:column> <h:outputText value="#{result}" /> </h:column> </rich:suggestionbox>
If you use the code above as it is, the whole page is going to be processed each time the suggestionAction is called. And because the minChars
attribute is set to 1, the action is going to be called each time the user enters a character! ๐ฎ
For obvious reason, such as performance issue, this is not ideal.
To avoid this behaviour, you simply need to set the attribute selfRendered
to true as shown below:
<rich:suggestionbox for="q" minChars="1" suggestionAction="#{myBean.mySuggestionAction}" var="result" limitToList="true" selfRendered="true"> <h:column> <h:outputText value="#{result}" /> </h:column> </rich:suggestionbox>
Here is the description of the selfRendered
attribute from RichFaces documentation:
If “true”, forces active Ajax region render response directly from stored components tree, bypasses page processing. Can be used for increase performance. Also, must be set to ‘true’ inside iteration components, such as dataTable.
Don’t hesitate to add this attribute to increase the performance of your website. ๐
limitToList attribute prevents flashing
If you have some elements (or even the whole page) that flash/twinkleย using RichFaces, it probably means that these elements are AJAX-rendering. The question is by whom and how to fix it?
A lot of tags in RichFaces can AJAX-render elements such as:
<a4j:form> <a4j:jsFunction name="updateName" reRender="showname"> <a4j:actionparam name="param1" assignTo="#{userBean.name}" /> </a4j:jsFunction> </a4j:form>
On the above example, the JavaScript function updateName
will AJAX-render the element which has the ID showname
.
In some cases, you would have some elements that would AJAX-render without asking them to do so!
I still didn’t figure it out why. ๐ (if anybody has an idea, please don’t hesitate to tell me!)
But, I found a way to prevent this!
You simply can add the following attribute to your tag:
limitToList="true"
You even can add it to the tags that don’t have a reRender
attribute.
For example:
<a4j:form> <a4j:poll id="poll" interval="1000" limitToList="true" /> </a4j:form>
No saved view state
How many of you did already get the following error when working with JSF?
I would be surprised if none of you got it at least once! ๐
HTTP ERROR: 500
/web/home.htmlNo saved view state could be found for the view identifier: /web/home.html
RequestURI=/web/home.html
Caused by:
javax.faces.application.ViewExpiredException: /web/home.htmlNo saved view state could be found for the view identifier: /web/home.html
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute(RestoreViewExecutor.java:88)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:103)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:76)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:151)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:341)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:368)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:495)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
...
This very common error happens because your session has timed out. As you probably already know, JSF is storing the view state of your page in session. Obviously, when the session has timed out, it can’t restore the view state and so throws a ViewExpiredException
.
The solution for this problem is to add the following lines in your web.xml file:
<context-param> <param-name>facelets.BUILD_BEFORE_RESTORE</param-name> <param-value>true</param-value> </context-param>
When this initialization parameter is turned on, it changes ViewHandler.restoreView()
to build the view before asking the StateManager
for help.
However, if you are using RichFaces, for some reason this is breaking a few Ajax components! ๐
To be honest with you, I didn’t investigate in depth why these components don’t work with this parameter set to true.
What I did instead is to make sure the session actually never times out! ๐
To do that, I am polling the server every 29 minutes (as my session time out is set to 30 minutes). Obviously, you can poll the server only every 59 minutes if you set your session time out to 60 minutes.
Here is the code I used to poll the server every 29 minutes:
<h:form> <a4j:poll id="poll" interval="1740000" limitToList="true" /> </h:form>
Note that the interval attribute is in milliseconds (29 minutes x 60 x 1000 = 1,740,000 milliseconds).
This solution is far from being perfect! Indeed, if, for example, a user doesn’t close his browser during the night, it means that we will have to keep the session opened during hours! ๐
But, as far as I am concerned, it is still better than to throw an exception at the user face. ๐