I have a complex page with a p:commanButton with actionListener and immediate="true"
Upon clicking this commandButton, I need to process a single inputField(thus skipping rest of the form). The problem is, that the inputField has a validator which I'd like to use only in full page submit.
<p:inputText id="#{cc.attr.id2}_input" value="#{myBB.value}"
immediate="true">
<f:validateLength minimum="4"/>
</p:inputText>
<p:commandButton id="#{cc.attr.id2}_search" immediate="true"
process="#{cc.attr.id2}_input #this"
actionListener="#{myBB.listener}">
</p:commandButton>
When I do this with i.e. 3 letters in the inputText, the myBB.value is not updated because of the failed validation. So I'd like to disable the validator for the inputField for the immediate processing by the commandButton. But I don't know how.
I know I can get the value from the ExternalContext, but this seems like a very hacky solution to me(and in my case is not even applicable, because it's inside composite component and I have no way of knowing the clientId of the textField.)
I also know about disabled attribute of the validator tag, but I have no idea how could I put that to use in this situation.
EDIT: I've changed a code a bit, because the IDs I'm using are actually not as simple as I first stated and don't allow me to use simple proposed solution.
I use Mojarra 2.2.4 and Primefaces 4.0
So, first of all, you haven't got the problem with immediate, but rather with <f:validateLength> validator.
That is, to rephrase your question, you'd like to skip validation of a given component in case the particular button is clicked.
Depending on whether you are on Mojarra 2.1.18+ or not there are two solutions. The first one is quite straightforward: use the disabled attribute of <f:validateLength>, while the other one takes into account issue 1492. As we've nowadays have advanced past the aforementioned version of Mojarra, I'll post the first and easier solution, otherwise, scroll through the excellent answers to Why does f:validateDoubleRange only work for #SessionScoped? and Disabled attribute of <f:validateLength> does not evaluate request parameters by BalusC.
So, the solution is the following:
<h:form id="formId">
<p:inputText id="inputId" value="#{myBB.value}">
<f:validateLength minimum="4" disabled=#{not empty param['formId:buttonId']}" />
</p:inputText>
<p:commandButton id="button" process="#this inputId" actionListener="#{myBB.listener}" />
</h:form>
As a side note, you can see that I didn't use immediate attribute at all because I supposed that you abused it to perform a given task. With the rise of AJAX in particular within JSF-based applications you can now easily group a subset of input elements validation by specifying the process attribute of <p:commandButton> or <p:ajax> instead of the previously used prioritized validation especially in synchronous requests. Only those components whose ids are supplied will be processed on the server and all other components will be omitted prom processing lifecycle. Also note that process="#this ..." is also mandatory to execute actions associated with the button itseld.
Regarding the appropriate usage of immediate I'd strongly suggest to refer to the classics: Debug JSF lifecycle blog post by BalusC to check whether you've used it correctly.
Related
I'm working with Primefaces 5.3.
First, I implemented functionality to change visibility of a p:selectOneMenu depending on the value of a p:selectBooleanCheckbox according to this post:
Enabling and disabling components via select checkbox
This works so far, if I use the h:form.
Next, I wanted to update the values in the bean, as chosen in the p:selectOneMenu. This is where my question starts: Even if i use p:ajax to explicitly call a listener, it won't get called. This is my code:
<h:panelGrid>
<p:selectOneMenu value="#{schedulerCDIBean.selectedParentTask}" var="parentTask" id="taskDependence" disabled="#{task.dependsOn != 'true'}">
<p:ajax event="change" listener="#{schedulerCDIBean.taskToAddListener}"/>
<f:selectItems id="taskDependenceItems" value="#{schedulerCDIBean.taskWebDataObjectList}" var="item" itemLabel="#{item.taskName}"
itemValue="#{item}" />
<p:column>
<h:outputText value="#{parentTask}"/>
</p:column>
</p:selectOneMenu>
</h:panelGrid>
And here is how I enable/disable the selectOneMenu:
<p:selectBooleanCheckbox id="dependsOnTask" value="#{task.dependsOn}" itemLabel="Depends On">
<p:ajax update="taskDependence" process="#this"/>
</p:selectBooleanCheckbox>
All this lives inside a p:tab of the p:accordionPanel where 'task' is the var of my DataObject-List.
As mentioned by #BalusC in this post: commandLink/commandButton/ajax backing bean action/listener method not invoked (Possible Causes: 2),
"You cannot nest multiple UIForm components in each other."
So, if i remove the h:form directive, the call to the listener in the bean works. But now, the value of the p:selectBooleanCheckbox is always set to 'false', and thus the component is not being updated to visible.
I found a post here, where OP had the same problem and solved it by adding the h:form directive.
EDIT:
My 'form' is a ui:composition and starts like this <ui:composition template="/templates/pages/mainPage.xhtml">, where mainPage.xhtml contains h:head and includes the 'header.xhtml' by using ui:include, and there is a h:form. But this h:form is already closed before, so the problem isn't here.
Well, I don't want to go the way with adding the h:form again, as it leads to unspecified behaviour. But what am I doing wrong, if my p:selectBooleanCheckbox values are not being set correctly?
Thank you for your help!
UPDATE
The problem was not the h:form, as it actually wasn't nested. Now I'm just still stuck with the listeners for the p:selectOneMenu, as they aren't being called. I also tried setting partialSubmit="true" on the <p:ajax />, which did not lead to a solution so far.
Thanks for your help, guys. With your help I fixed the problem.
Just as if someone else experiences similar problems, here a few things to check:
Check #BalusC's answer here, as also mentioned in #irieill's answer.
Check if you're having equals() and hashCode() of the object you're willing to show in the selectOneMenu.
The solution for my situation actually was mentioned in #irieill's comment:
[..]Not providing a proper converter does not raise any exceptions but faces error messages. So try to add a <p:growl autoUpdate="true" /> to your page to see if any conversion error is raised. If so, add a propper converter to your selectOneMenu.
I think, that's also what #BalusC said at point 3 of his list of possible causes.
See also: How to write a custom converter for <p:pickList>, Custom converter in JSF 2.0, PrimeFaces ShowCase: SelectOneMenu
As mentioned by #BalusC in this post: commandLink/commandButton/ajax backing bean action/listener method not invoked
Also note point 1. You must enclose your input components with a <h:form /> tag.
Well, I don't want to go the way with adding the h:form again, as it leads to unspecified behaviour.
As i understand, you are misusing the tag or you do not understand how to use it. Just enclose your whole page (or at least all input components) in one <h:form /> tag and it should work.
Can you please update your question with the page code also containing the lines where you placed the <h:form /> tag(s).
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'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...
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...
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.