I have adapted a Pie chart JS object to use with JSF; in order to do so, I've created a custom component that outputs the appropriate markup and JS calls on the page, rendering the graph correctly. For reference's sake, this is the link for the tutorial I've followed for the JS part.
The next step is listening to clicks on the slices, and calling an action from a backing bean. The JS object for the chart already contains a placeholder function that listens to such clicks, so I believe the JS part of it is good. However, the JSF side bugs me still; I've read the Java EE tutorial, Jim Driscoll's blog posts, and all over the internet, and still can't get my head around it.
So, could anyone be so kind as to give a little example, of how I could bind a JS function call to an event listener in JSF, so that my backing bean would be nicely informed of which slice index had been clicked by the user?
It would be something close to:
function myChartObject() {
function onSliceClick() {
// This will somehow trigger JSF ajax event listener with slice data
}
}
class MyCustomChart extends UIComponentBase implements ClientBehaviorHolder {
// Is the decode() method the place to bind JS calls to JSF actions?
}
The closest I've found to my problem is something like this. However, I'd like to have this support in my own component, using the standard JSF API. Something perhaps close to this?
Thank you all in advance!
The JSF Javascript API to do AJAX calls is itself standardized (resource library "javax.faces", resource name "jsf.js") but adding full AJAX support in your own Java based custom component is a little elaborate.
The quickest way I can think of is following the blog by Jim Driscoll that you cited, and re-use the existing AJAX machinery offered by the <f:ajax> tag by wrapping your own Java based custom component in a composite component.
In Jim's example, I guess the following code from line 22 in his example is what you should render inside your onSliceClick function:
String click = behaviors.get("click").get(0).getScript(behaviorContext);
It would then look a little like this:
<ui:component
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:cu="http://javaserverfaces.dev.java.net/demo/custom-taglib"
>
<cc:interface shortDescription="Some Description">
<cc:attribute name="render" required="false" />
<cc:attribute name="clickAction" method-signature="java.lang.Object action" required="true" shortDescription="The click action method" />
</cc:interface>
<cc:implementation>
<cu:custom id="customId">
<f:ajax render="#{cc.attrs.render}" listener="#{cc.attrs.clickAction}"/>
</cu:custom>
</cc:implementation>
</ui:component>
Note that I haven't tested this, but it's the general idea. Of course it's also possible to do all of it directly in Java code but that surely takes some more work.
It looks like you want the ability to encode ajax style behaviors in your java compiled code, while integrating this with a J2ee stack.
The framework that comes to mind is JBOSS's Seam
Seam integrates directly with JSF by design, (GWT is more of a lightweight, standalone, statefull web-application framework - it doesn't have a lot of embedded features for direct integration with JMS and other modern J2ee features)...
Seam directly supports GWT-style ajax enabled components.
There is a good tutorial here : http://www.ibm.com/developerworks/java/library/j-seam3/
Related
I want to move the JSF AJAX triggering code written with f:ajax, f:event and the h:commandLink (with its action attribute) to Javascript by using the jsf.util.ajax. - Why ? Because to avoid globally written handler functions to handle call backs. We are migrating the JS code to AMD Require JS and JSF isn't playing very well
Previously, the code to trigger AJAX calls from the view XHTML file in JSF was written like this :
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}">
<f:ajax render="#{someBean.getElemId('LinkID')}" onevent="renderAjax" />
<jsft:event type="ajax"> someBean.someMethod(); </jsft:event>
</h:commandLink>
The above markup gets rendered in HTML as follows:
Then, a click event was triggered on this link to execute the AJAX and the action.
The jsft:event was used which behaves similarly to its counterpart f:event.
I do not want to use this because it forces to define JS functions globally. In this case, renderAjax() in the onevent attribute of f:ajax
As you can see, This relies on a globally defined function called renderAjax() as the callback function to execute something and render on the UI side.
The trouble is we are moving into AMD and require JS and we have no scope of defining any globals in our code (we can but we do not want to). Even if we did, this ajax call gets triggered much before Require AMD loads
So I attempted to re-write this ajax call from the client side in JS, inside an AMD module, like this (from the generated HTML snippet's onclick mentioned above)
(Point to note, I did not know how to mention the action attribute in this JS code.)
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Once I wrote the above code in JS, I removed the f:ajax (since the render and the onevent attributes came inside the JS code itself ) and the jsft:event from the view, in the XHTML file. Once I removed this, it began causing a continuous reload of the page, as an infinite loop. I had to stop the server and put back the code to its old state.
Next, I thought h:commandLink was the issue and decided to replace h:commandLink with a normally rendered anchor tag via the h:outputLink.
Unfortunately this doesn't have an action attribute. The point is, although the element is rendered,
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Since my code with h:outputLink has no action attribute, it doesnt execute the method in the managed Bean.
Suppose I included the h:commandLink, without the jsft:event and the f:ajax, then it causes an infinite page reload.
I even added the action attribute to the h:commandLink after removing the jsft:event and f:ajax . I made it work with the below update.
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}" action="#{someBean.someMethod()}">
<f:ajax />
</h:commandLink>
and then using the following in JS:
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
So far it works. But the problem is my renderAjax is still globally defined. Now i move my JS function into a require AMD module. The function renderAjax is no longer globally available and I move the jsf ajax code also into my module and access it as:
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:_t.renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Note, _t.renderAjax() is now inside a module in Require JS. The Error i get now is _t is undefined. I guess it expects to see only global functions. The fun part is it automatically creates a wrapper function around the code. Is there any way to fix this?
(function(event
/**/) {
jsf.ajax.request('elemID',event,{render:'LinkID',onevent:_t.renderAjax,'javax.faces.behavior.event':'action'})
})
If someone could help me fix this, it would be extremely helpful.
Ok. I figured this out. I'm not sure if this is the right method. But it works.
Remove the following section as its not right to create a dummy link just for the sake of triggering a click event on it (in order to make JSF ajax work). It also forces to define global handler call backs as mentioned above which pollutes the global namespace, prevents the modularization of JS code, makes it imposs to move to AMD:
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}">
<f:ajax render="#{someBean.getElemId('LinkID')}" onevent="renderAjax" />
<jsft:event type="ajax"> someBean.someMethod(); </jsft:event>
</h:commandLink>
Now create a simple XHTML file called ajax.xhtml that serves as a template.
Create another file called needHelp.xhtml that uses the above file ajax.xhtml as the template
Both steps (1) and (2) have been shown in an image below:
http://i61.tinypic.com/2rgypsi.png
In the backing bean, do this:
http://i62.tinypic.com/1037bci.png
This completes the setup. Our Ajax response is now in the JSON format and written to the response stream.
Now, in the required AMD require Module,
define('checkChannel', ['jQuery', 'ajaxHandlers'], function($, ajaxHandlers){
(function checkChannel(){
$.ajax({
url : baseURL+"/needHelp.jsf",
dataType : "json",
type: "POST",
success : ajaxHandlers.renderAjax
});
})();
})
The success handler is used to update whatever DOM element needed, based on the response flags. In this case, it would update the element with id="LinkID", as defined in the original code snippet.
Now, the renderAjax is well wrapped inside an AMD module and is no longer required to be defined globally. Now there is no need to use the and or have dummy links created via to simulate a click and trigger AJAX in JSF. If the view state needs to be maintained, it can always be got and updated in a similar manner.
Also, baseURL is the basehref of your app. For example, if the page
was www.example.com/tool/index.jsf, then the baseUrl would be
www.example.com/tool/. So, the AJAX URL would be
www.example.com/tool/needHelp.jsf
PS: pardon the external image links as stackoverflow did not let me
post pics / more links as i needed atleast 10 reputation to post. I
had to use external images as I had some trouble formatting the code.
I am using RichFaces 4. I am using flot as a JQuery Charting library and i want to implement a chart, that keeps refreshing itself via AJAX.
I get the data for the chart via JSON from my backing bean.
I am lost on how to get new data from a backing bean into a javascript variable. From what i understand i can't use <f:ajax> since there is no user interaction and no use of html input elements.
I think the solution would be the use of jsf.ajax.request. But i don't understand how to call that without an input-element either.
Following is a code snipped of how it should look like, but i don't know how to get the value from my backing bean into a javascript variable.
$(function() {
function update(){
//**dont know how this call should look like**
jsf.ajax.request('dev-form-input1', {render:'dev-form-output1'});
//'newAjaxData' would be the value from #{someBean.chartData}
plot.setData(newAjaxData);
// draw the chart with the new data
plot.draw();
//get an update every second
setTimeout(update, 1000);
}
I managed to send AJAX requests with jsf.ajax.request when using some input-element, but i didnt get the new value to render. And even if i could i wouldnt know hot to get it in a javascript variable (i dont have a lot of experience with javascript).
<h:form id="dev-form">
<h:inputText id="input1" value="#{someBean.chartData}"/>
<h:outputText id="output1" value="#{someBean.chartData}" />
</h:form>
note: i changed the javax.faces.SEPARATOR_CHAR to "-", because i need ":" for jquery.
Thanks for your help!
JSF is the wrong tool for the job. Use a webservice framework like JAX-RS, not a MVC framework like JSF. Then you can in the client end just use jQuery the usual way and so on.
See also:
Jersey (JAX-RS reference implementation) tutorial
Servlet vs RESTful
I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards
I have a JSF 2.1 (MyFaces) app running using several Session Beans (All the beans are session beans).
The timeout is defined in web.xml as such:
<session-config>
<session-timeout>3600</session-timeout>
</session-config>
Which translates to 1 hour.
The problem is that on normal usage I get the No Saved View... exception:
SEVERE: An exception occurred
javax.faces.application.ViewExpiredException: /mainPanel.jsfNo saved view state could be found for the view identifier: /mainPanel.jsf
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute(RestoreViewExecutor.java:128)
The beans are, currently, defined in faces-config.xml for compatibility with Eclipse's ide.
I'm not sure what could be causing this and it's definitely not timeout.
Any ideas what could be the problem?
If there is any further information I can provide, let me know..
Thanks!
P.S - there is no jsf-2.1 tag
Update 1 I just figured 60 meant 1 minute! :-) That could be the problem. I will close the question if it turns out that way
Update 2 Thats wasn't it... Some more information That might be helpful:
While the error is specifically for /mainPanel.jsf, this is actually a composition of xhtml's using <ui:include>
It happends only when I click one specific point in the app. The code that runs as a result of the click is:
Jquery Code:
$(document).ready(function() {
$("#someTable tr:not(:first)").click(function(event) {
var someValue = $(this).find("input:hidden").val();
$('#currently_selected').val(someValue );
$('#currently_selected').change();
});
});
JSF 2 Code:
<h:form prependId="false" class="hide">
<h:inputText value="#{someBean.someBeanValue}">
<f:ajax event="change" listener="#{someBean.someBeanValueChanged}" render=":anotherForm"
onevent="ifCompleteSetWindowHash" />
</h:inputText>
</h:form>
At first view it seems to be some side effect over javax.faces.ViewState hidden field. If this field is ovewritten, a ViewExpiredException will be thrown. Try to do the same you are doing with other different javascript code.
Anyway it is not related to your session-config parameter. The information provided here is insuficient to reproduce it. If the previous suggestion does not solve your problem, please create an issue on MyFaces Issue Tracker and attach an example. In this way you'll get it solved.
I believe the $ symbol is a reserved character for EL expressions in JSF (EDIT: As noted below, the '$' alone is not reserved, however third party component libararies may use various javascript libraries that could have a naming conflict with jQuery). Try changing your jQuery function calls to the explicit long form name and see if that makes a difference.
Eg. Instead of...
$(document).ready(function() {
Do this...
jQuery(document).ready(function() {
sorry if I am being thick but what is the execute="#all" in an f:ajax tag really supposed to do? I expected it to submit all the elements on a page but it seems to POST only the values in the enclosing form, not all forms on page.
For example
<h:body>
<h:form id="form1">
Input1/Form1 <h:inputText id="testinput" value="#{testBean.input1}" />
</h:form>
<h:form id="form2">
Input2/form2 <h:inputText id="testinput2" value="#{testBean.input2}" />
<h:commandButton value="Ok" actionListener="#{testBean.al}">
<f:ajax execute="#all" />
</h:commandButton>
</h:form>
</h:body>
Only form2 is posted on click.
Using mojarra 2.0.2..
The execute="#all" was just a major oversight during designing JSF2 spec. JSF kind of abstracted away too much of its HTML form based nature, forgetting that it's ultimately actually a HTML code generator.
In HTML, submitting a different form than the enclosing one is disallowed. So execute="#all" will never work from that perspective on. It will behave exactly the same as execute="#form". Given that JSF is just a HTML code generator, the same "problem" will hit JSF too. It's not possible to process multiple <h:form> components at once.
If you really need to have this feature for some reason, you should take a step back and reconsider the incorrect way how you look at HTML forms. You need to make sure your forms are designed in such way that you never need information from another form.
See also:
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?.
PrimeFaces already realized early that #all was fundamentally wrong. That's exactly why they never supported #all in process attribute, their equivalent of execute. They initially also never supported #all in update, their equivalent of render. However, the only real world use case where that made sense was handling a full error page during an ajax exception, so they ultimately brought update="#all" back after I created the FullAjaxExceptionHandler. The process="#all" will still have exactly the same effect as process="#form".
However, the very same PrimeFaces library also unintentionally made the imagined behavior of execute="#all" possible via its later introduced partialSubmit="true" feature whereby you explicitly specify all other forms like below (the PFS #(form) is just for simplification, a hardcoded collection like :formId1 :formId2 :formId3 etc is also just possible).
<p:commandButton ... process="#(form)" partialSubmit="true" />
This works because partialSubmit="true" prepares the process="xxx" at client side rather than server side. In other words, instead of sending the entire enclosing form from server to client and then processing the specified inputs, it sends only the specified inputs from server to client and then processes them all. Do note that when partialSubmit is absent or set to false, then it would still only send the enclosing form. This misbehavior should rather not be relied upon. They may fix this misbehavior on their side sooner or later.
See also:
Any significant technical difference between JSF non-AJAX submit and a "#all" AJAX submit?
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
Here is a quote from JavaServer Faces 2.0 - The complete reference, page 352:
The execute and render keywords accept a set of special keywords, each with the meaning shown in this table:
#all (using with execute): Every component on the page is submitted and processed. This is useful when you want to do a full-page submit.
I think this quite clearly states that the fields from all forms should be submitted with the AJAX request.
However, even with Mojarra 2.0.3 this doesn't happen. Despite of contents of the execute attribute (whether you put a list of forms or #all) only the enclosing form gets its' fields submitted. So this seems like a bug. I am raising an issue about this unless there are altering views?
It would have to be execute=":form1 form2" (if you have the default separator), but anyway no, it doesn't. It only sends the second one.
If you put #all in the first form, it only sends the first. At least on Safari 5/Firefox 3.6.3 anyway. I guess one would have to look at the mojarra javascript to find out more.
Have you tried this?
<f:ajax execute="form1 form2" />
Does it send both forms' data if you explicitly mention them?
AFAIK, you are right: #all represents the whole page.