My main form has a Primefaces poll with a message that I want to update with "in progress" or "completed." My menu item opens up a dialog where I allow the user to confirm the action. If yes, I want to start the poll, call the server method, and immediately close the dialog (because the method takes a while and we don't need to wait.)
If I start the poll in the same button that opens the dialog, it works. If I start the poll in the button on my dialog, what happens is that the server method gets called but the poll does not start until the method is completed. I used 'onclick' instead of 'oncomplete', but it's not helping. I can tell because the poll listener method only gets invokes when the main method is finished. I've looked through #BalusC posts about order of actions, etc., but I know I'm missing something simple here.
Sample code:
(myForm)
<p:poll widgetVar="statusPoll" interval="1" autoStart="false" update="myStatus"
listener="#{bean.pollListener}"
stop="#{bean.pollStopped}"/>
<h:outputText id="myStatus" value="#{bean.status}"/>
<p:menuitem value="Start job" onclick="PF('jobModal').show();">
(jobModal)
...
<p:commandButton value="Run the job"
action="#{bean.runMethod}"
onclick="PF('statusPoll').start();PF('jobModal').hide();"/>
Related
I have a p:dialog with a text input. When saving, the entered value is passed to an external service which may either accept or reject it. The text input has a validator, but that validator can only check so much. In particular, it does not know the external service's state. It cannot make a call to that service either cause between the checking time and saving time the input may become invalid.
So far, I have a <h:messages> in the page and in the popup. The popup is in its own form. The external service's validation error appears in the page's <h:messages> as the popup is closed because as a workaround I added the page's messages to the command button's update attribute. The popup's p:commandButton uses ajax='true' and a check for validation errors (oncomplete="if (arg && !arg.validationFailed) PF('popup').hide()") as explained in another post. It looks like validation is finished and there are no errors, so the popup closes and the button's actionListener runs to push the input to the external service, and then the error is returned from the service.
I understand that validating in a setter or listener is an anti-pattern, but I don't see a way around it here. It's not so much validating anyway, it's more a "take this" and being prepared to receive an error for it.
I tried opening the popup again from the listener but that did not open the dialog.
<h:form id="Form">
<h:messages id="pageErrors"/> <!-- external service error shows up here -->
<h:form>
<h:form>
<p:dialog widgetVar="popup">
<h:messages id="popErrors"/> <!-- I'd like to show the external service error here -->
<p:inputTextarea id="it" required="true"/>
<!-- required works as expected: error in the popup when nothing is entered, popup remains open -->
<p:commandButton value="Save it" ajax="true" update="popErrors Form:pageErrors"
oncomplete="if (args && !args.validationFailed) PF('popup').hide();"
actionListener="#{bean.saveIt}"/>
</p:dialog>
</h:form>
And the actionListener:
public void saveIt(#SuppressWarnings("unused") ActionEvent e) {
String error = extService.saveIt(it);
if (error != null) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(error)); // gets the error in the page's messages
facesUtil.showDialog("popup");
}
}
How can I keep this dialog open when the actionListener detects an error from the external service?
If I understand the problem this works for me:
update="popErrors :Form:pageErrors"
and
FacesContext.getCurrentInstance().validationFailed();
right after you add the message.
Adding a FacesMessage to the response is not the same as that the validation has failed. If you validate yourself, you must manually tell the framework if it failed.
You could also add your own callback parameter as Hatem suggests, but to my knowledge there is no problem reusing validationFailed.
I am struggling to get the click event on h:panelgroup which will call a method in my managedbean. I don't want binding as it is only for property.
Also can someone explain the function of below line.
<f:ajax event="click" render="#all" listener="#{ABC.abc}" />
This is taking click listener on the whole page. I only need it to trigger when the input is clicked. So after this was not working I am trying to get a click on panelgroup. Is there any other way.
Thanks.
So figured it out why it was taking click on whole page. I was not wrapping f:ajax call in jsf component. So it was attacking to main h:panelgroup. Wrapped it around a new panelgroup and it started working fine.
But I am getting click twice on each call. :/
I have a text box which takes a search value, and i want to send this string to the server side on click of a button. Not by a form submit, by an ajax call.
I had added an actionListener to the input tag itself, which is called on blur. But what i really want is for the user to click the button to trigger the search function.
I got an idea from this question, and implemented it this way:
<h:inputText id="likeMaterial" value="#{createBookingForm.searchText}"></h:inputText>
<a4j:jsFunction name="setParameterAndRerender" actionListener="{bean.searchMaterials}" reRender="searchResult">
<a4j:actionparam name="param1" assignTo="#{createBookingForm.searchText}"/>
</a4j:jsFunction>
<h:commandButton value="Search" onclick="setParameterAndRerender('mySearchText');return false;"></h:commandButton>
The value received at server side is of course, "mySearchText". How do i pass what the user enters? Or how do i bind #{createBookingForm.searchText} before the button's action listener is called?
Im open to any other approach to. I have limitations though : Im working on enhancing a legacy application, built using JSF 1.1. I cant upgrade, not without a fight at least!
Edit : I tried doing it this way, but i get "undefined" on the server side.
Why not use a4j:commandButton instead of h:commandButton? It will execute ajax request and render what you want. No form submit will happen. Loks like what you need.
h:commandButton by default submit the form when clicked. So no need to send specially using a4j:jsFunction or in any other way. You can completely remove your js function unless if you have something else to do. If you want to test that add an action method and print the value of searchText variale in createBookingForm bean.
Hope this helps!!
This is the whole solution
<h:inputText id="likeMaterial" value="#{createBookingForm.searchText}"></h:inputText>
<a4j:commandButton reRender="searchResult" actionListener="#{createBookingForm.searchMaterials}">
<a4j:actionparam name="param1" noEscape="true" value="document.getElementById('likeMaterial').value" assignTo="#{createBookingForm.searchText}" />
</a4j:commandButton>
Is it possible to trigger a web flow transition by putting the <f:ajax> tag inside a <h:inputText> to send request with each keypress?
I already tried this and the ajax request is send by the browser, received by the application and processed by JSF but the event is not observed by Web Flow.
<!-- does not trigger transition -->
<h:inputText id="search" value="#{friendsForm.searchUsername}">
<f:ajax listener="search"
execute="#this"
render="users"
event="keypress"/>
</h:inputText>
<!-- does trigger transition -->
<h:commandButton value="search" action="search">
<f:ajax listener="search" execute="search" render="users"/>
</h:commandButton>
When doing the same with a commandButton, it works as expected. Looking at the source code one can see that the button's base class UICommand invokes its default ActionListener which in the end triggers the transition. It seems that inputText does not have an action listener and thus the event is not processed there.
In the end I could work around this by programmatically clicking a hidden button with each keypress, but if I can avoid this I would do so.
Thanks in advance...
I found this post about how to trigger a transition on value change in h:selectOneMenu and the solution works quite well, even for my use case.
I defined the listener attribute on the f:ajax to point to a spring bean's method which in turn gets the RequestControlContext in order to handle a new Event that triggers the transition.
RequestContext requestContext = RequestContextHolder.getRequestContext();
RequestControlContext rec = (RequestControlContext) requestContext;
rec.handleEvent(new Event(this, "search"));
This way I don't have to introduce a hidden button and translate the keypress event into a click event.
i'm trying to figure out the ajax's tag 'listener' property, and from what i read here
An ajax listener, connected to your ajax event with the listener attribute, is a method that will be called every time the ajax request is made
which is exactly what i'm looking for. i've also tried the first sample of code on that web page and it works as expected.
however, when i add the following code -
<h:commandButton id="d" image="#{CodeBean.imgSrc}" action="#{CodeBean.clickImg()}">
<f:ajax event="action" render="d" listener="#{CodeBean.update}" />
</h:commandButton>
both 'clickImg' and 'update' functions are called (and 'clickImg' does its task), but the 'update' is being performed BEFORE the 'clickImg' (i've added to both function 'System.out.println(...)'). and yes - in that sample code the 'update' is being performed after the 'setHello'
that makes no sense to me - or did i miss something?
cheers,
eRez
That's fully by specification. Action listeners are called before actions during invoke action phase. If you need to execute a business action and/or to navigate, do it in action. If you need to listen on the action event so that you can if necessary do some preprocessing, use listener.
In your particular case, it look like you don't need the action listener at all. Just remove it and move the job into the action method. The event attribute is by the way superfluous. It already defaults to action. Just remove it. This works equally good:
<h:commandButton image="#{CodeBean.imgSrc}" action="#{CodeBean.clickImg}">
<f:ajax render="#this" />
</h:commandButton>
See also:
Differences between action and actionListener
in the example you looked at setHello was a setter of h:inputText value and not an action like in your code , that is what you missed...
And that's why in the example the setter was called before the ajax listener...