RichFaces: Displaying a notification "popup" when AJAX operation succeeded - ajax

We are currently developing a B2B web shop based on Java EE 5, JSF, Facelets and RichFaces. The technology has really worked very well so far, but now I am facing a small problem I just can't figure out how to solve:
Products are listed as tables, where every item can be added to the shopping basket by clicking on a small icon at the end of the row. Adding the product is done via AJAX to avoid the full reload of the page. This works without any problems just by using a h:dataTable and an a4j:commandLink to call an action-method which adds the selected product to the basket. Even the re-rendering of the basket total always visible in the side-bar is working properly.
Due to the nature of AJAX, there is no visible indication (except the changing total at the side) that the operation was successful or has been completed at least. Now I want to add a little "popup" box, which is made visible next to the add-icon when the AJAX-operation is completed, stating that the item was added to the basket. This box should automatically go away after a few seconds.
This is what I think should work (the popup_message and popup_content css-classes make the box float above the position where its markup is):
<h:dataTable ....>
...
<h:column>
<a4j:commandLink action="...">
<rich:effect event="oncomplete" targetId="addedMessage"
type="Appear" />
<rich:effect event="oncomplete" targetId="addedMessage"
type="Appear" params="{delay:3.0, duration:1.0}" />
</a4j:commandLink>
<a4j:outputPanel id="addedMessage" styleClass="popup_message"
style="display: none">
<a4j:outputPanel layout="block" styleClass="popup_content">
<h:outputText value="Item added!" />
</a4j:outputPanel>
</a4j:outputPanel>
</h:column>
</h:dataTable>
Unfortunately, it doesn't display the box at all. If I change the event of the "Appear" effect to onclick it works almost as expected. It is immediately shown when the icon is clicked and it dissapears 3 seconds after the AJAX operation was completed. But I don't want it to appear immediately after the click, because it would be wrong to indicate that the item was added to the basket, when in fact the operation hasn't even started yet. This becomes even more important, when I want to indicate some error or want to include some item specific information into the box, which is only available after the item was added.
So any ideas how to do this? And why adding two effects for the same event does not work?
(I've already looked at the effect-example from the RichFaces live demo. The examples do almost work the same, execept that they add the second effect with explicitly stating the for attribute. But even this does not work for me.)
Update: I've tried using the rich:toolTip for this purpose, which actually seems to be quite flexible. But no matter what I do, I can't attach anything to the "oncomplete" (I've also tried just "complete") event of the a4j:commandLink, except one effect... seems there is some bug/undocumented behaviour regarding that event. I've just found this bug report: RF-3427

you can try rich:notify for this
http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=notify&skin=blueSky

Have you tried rich:status ? I will not post a piece of code. I think the docs will do just fine.
http://livedemo.exadel.com/richfaces-demo/richfaces/status.jsf

Your defining targetId outside the parameters. What you want to do is:
<rich:effect event="oncomplete" type="Appear" params="targetId:'addedMessage',delay:3.0, duration:1.0" />
Try that, and I think it will work.

Related

How to just update "rendered" property in JSF

I've got a list of documents and I need to update all at once.
I did something like this:
<ui:repeat id="r_list" value="#{tareaController.controlador.documentosIndexar}" var="documentos" >
where documentosIndexar is the list of documents. It displays all the documents and its properties fine.
I have two panelGrids, one with the viewer of the document and another one with its information.
At the bottom of the information there's the list of documents.
I need to fill the document's information then select another one without losing the previous one.
I'm trying to update the whole ui:repeat and it renders the next document and its information ok but the information of the previous one is lost.
I also tried doing:
<ui:repeat id="r_list">
<p:panelGrid id="pg_document" rendered="#{tareaController.controlador.documentoSeleccionado.id eq documentos.id}">
<---- Document components here ---->
<p:ajax event="rowSelect" update=":f_tarea:r_list:pg_document" listener="#{tareaController.controlador.reemplazarLista(tareaController.documentoSeleccionado)}"/>
</p:panelGrid>
</ui:repeat>
All my components, and well, my page is inside a form called f_tarea, which is from its template.
When I do the above I update that panelGrid from the list, but just that one, and the variable in the rendered condition changed, so all the panelGrid dissapear.
Basically, what I want to do is update JUST the rendered condition on all the panelGrids inside the ui:repeat, so one hides and another one is shown without losing the previous one's information.
Ok. Excuse me I'm a completly stupid.
I tried doing something I haven't done before: downloading the PrimeFaces manual. On the AjaxBehavior section there's the "process" one which process a component in partial request.
I fixed it just by doing:
<p:ajax event="rowSelect" process=":f_tarea:r_list:pg_documento" update=":f_tarea:pg_doc" listener="#{tareaController.controlador.reemplazarLista(tareaController.documentoSeleccionado)}"/>
I won't delete the question in case that it helps someone in the future.

Primefaces poll triggers message from f:viewParam

First post here, so bare a bit with me. Searched a lot, but either because I was to blind or because I just didn't use the correct search strings, I haven't found any answer relevant to my problem.
Basically, I have a web application written in Java and using Primefaces. I'm using a p:layout, having the main content in the center unit, the header in the north and the footer in the south unit of the layout. The west layout unit holds a p:poll which runs every two seconds cand calls a js function when the oncomplete event is triggered.
So far so good. The thing is that on a certain page, in the center layout unit, I have a f:viewParam which accepts only longs and, even though the value is valid, when the above poll gets executed, the requiredMessage from the f:viewParam appears.
After doing some intensive search, I've found that by adding a ignoreAutoUpdate="true" to the p:poll, the messages from the f:viewParam will not get triggered and the warning telling that I have to provide a valid id isn't shown.
So, my question is: by having the ignoreAutoUpdate="true" in my p:poll will compromise, by any chance, the f:viewParam validation? Or is it safe to leave it there?
Here is the relevan parts from my layout:
The poll form the west layout unit:
<h:form id="liveQueueForm">
<p:remoteCommand name="rcStart" action="#{liveQueueMB.startPoll()}"/>
<p:remoteCommand name="rcStop" action="#{liveQueueMB.stopPoll()}"/>
<p:poll id="liveQueueUpdater" delay="10" widgetVar="livePoll" interval="2" listener="#{liveQueueMB.init}" oncomplete="updateLiveQueue(xhr, status, args);" autoStart="true" partialSubmit="true" ignoreAutoUpdate="true" immediate="true" />
<div id="live-queue">
<div id="queue-holder"></div>
</div>
</h:form>
The f:metadata block which holds my f:viewParam:
<f:metadata>
<f:viewParam name="callId" value="#{viewInboundCallDetailsMB.callId}" required="true" requiredMessage="Please provide a valid call ID" converter="javax.faces.Long" converterMessage="The call ID is not numeric" />
<f:viewAction action="#{viewInboundCallDetailsMB.init}"/>
</f:metadata>
Thank you!
From Primefaces manual about ignoreAutoUpdate:
"If true, components which autoUpdate="true" will not be
updated for this request. If not specified, or the value is
false, no such indication is made."
Which means that it's not going to do update your viewParam component, and other components that have autoUpdate="true".
It's not going to disable the validation on it. (Unless of course, if you are using your poll for validation, which i presume you are not)

JSF 2.0 - Ajax and Rendered Components

I'm experiencing some problems when using the "rendered" attribute with ajax behavior. I'll paste the code so I think it will be a lot more clear:
<h:selectOneMenu value="#{registrarVentaController.esCobroChequeString}">
<f:selectItem itemLabel="Efectivo" itemValue="false"/>
<f:selectItem itemLabel="Cheque" itemValue="true"/>
<f:ajax execute="#this" render="#form"/>
</h:selectOneMenu>
<h:panelGroup id="panelMonto">
<span>Monto:</span>
<h:inputText value="#{registrarVentaController.monto}" rendered="#{registrarVentaController.banCobroCheque}"/>
<h:inputText value="#{registrarVentaController.monto}" rendered="#{not registrarVentaController.banCobroCheque}"/>
</h:panelGroup>
My "#{registrarVentaController}" is just a View Scoped JSF Managed Bean with appropiate setters/getters.
This way it works, I mean, when user selects option "Efectivo", panelGroup "panelMonto" will get updated and we'll see the first inputText, and conversely when user selects option "Cheque" user will see the second inputText.
For this approach I used "f:ajax" component where I updated the whole #form to get this behavior work and I just want to update panelGroup "panelMonto" (using render="panelMonto" It doesn't work at all (I even try with full scope resolution :formName:panelMonto with no result).
I just want to have rendered work with ajax="idComponent" or similar behavior to show certain parts according what user have selected.
Best Regards!
Note (One solution)
I managed to get a solution (taking as an input
JSF rendered is not working
and a bit of myself). I've just moved to a new form the part that I'm
interested in filtering according what user selected. This way I still
use #form ajax's render and it will just render this new form (not the
whole form as I was using!) Neverthless I'm still wondering if there
is a solution to not used #form and just the component/s ID.
what if you check with
render=":panelMonto"
not
render=":formName:panelMonto"
still not working?
this should work only with
render="panelMonto" //because is in the same form
Can you add more code?
Also can you check with your browser (in chrome: right click, inspect element, network) to see if there is any activity?? perhaps is rendering the same thing because of you...

p:commandButton update doesn't work in ui:include

I want to update a part of a page by PPR.
This is the part of page that i want to update:
<h:panelGroup id="aggiungiAuto"
rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
While this is the commandButton present in aggiungi_auto.xhtml
<p:commandButton value="Submit"
update="growl aggiungiAuto aggiungiFoto"
actionListener="#{autoBean.insert}"/>
Any Idea?
JS/Ajax works on the client side, not on the server side. JSF works on the server side, not on the client side. When you instruct JSF to not render the component to HTML, then nothing will be present in the client side, so JS/Ajax will be unable to locate the HTML element to refresh/update.
You need to wrap it in another <h:panelGroup>.
<h:panelGroup id="aggiungiAuto">
<h:panelGroup rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
</h:panelGroup>
This way the <span id="aggiuniAuto"> is always present in the client side, so JS/Ajax will be able to update it with the new HTML data generated by JSF.
So I was having this kind of a problem with PrimeFaces (the above answer not being sufficient this time), and I also discovered a solution.
Part of the problem I think was that I was using ui:include recursively. For whatever reason, PrimeFaces was irrationally causing UI components to be bound to the backend data out-of-sync; e.g., when an "Add" button was clicked, a new value would be created in the UI, but then the data for it would be ripped out of the values for the section below, etc...
The explanation? "[O]n a viewscoped bean, a hidden field is added to the form to hold post-back data[;] if that field is not included with the process, then the bean will lose context." This particular problem is prevalent with ui:include recursion especially. Solution (all regarding the p:commandButton or other actionable component):
Ensure that update and process are pointing to a JSF component, not a regular HTML component.
update the next scope up if it breaks (goes out-of-sync with the binding).
Use styleClass's for update (not e.g. PF ID's or #this:#parent kind of stuff), so that jQuery is utilized instead of PF, e.g.: #(.fieldset-class).
process whatever scope is being updated. (This is needed for the post-back data so that the Bean keeps its context for the update...) process="#this" is not needed here, provided that the button is contained by the process value component.
For all buttons without validation wanted, set immediate="true".
If none of the above works (which happened with the Add buttons, probably due to ui:include recursion), set process="#this", immediate="true", and update="#none", and then oncomplete="remoteCommandName();", and have a p:remoteCommand instead with that name with the process, immediate, and update mentioned in the above points.
If none of the above works (which happened with some other buttons, probably due to being yet another layer deeper in the ui:include recursion)... wrap a h:panelGroup around the next c:forEach up and then update the PrimeFaces ID of that in the button itself while keeping its remoteCommand call afterwards, as specified above.
If none of the above works (which happened yet again to me)... Try the following code:
In the p:commandButton(s): oncomplete="$('.FixButtonSC').click();"
In the p:fieldset with a style class of FieldsetSC:
<!-- Fix (hidden) button. -->
<p:commandButton id="FixButton" styleClass="FixButtonSC"
process="#this" update="#(.FieldsetSC)" style="display: none;" />
Hope that helps...

What is <f:ajax execute="#all"> really supposed to do? It POSTs only the enclosing form

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.

Resources