I want to share my experience using primefaces, f:viewParam and p:commandButton, and ask a few questions.Take a look at this page:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<f:metadata>
<f:viewParam required="true" name="id_file" value="#{bean.idFile}" />
</f:metadata>
<h:form id="tableform" prependId="false">
<p:commandButton actionListener="#{bean.myMethod())}" icon="ui-icon-search" title="View" />
</h:form>
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true" />
</h:body>
</html>
The backing bean have a "myMethod()" method that does nothing. When you enter the page it expects the "id_file" parameter and put it in the idFile property of the backing bean. Then you click the button and the myMethod is called. Then you click again and you get an obscure validation error and myMethod is never called:
j_idt1: Validation Error: Value is required.j_idt1: Validation Error: Value is required.
First of all, remember that without p:messages you can't see this message, you have to dig the XML that primefaces send on ajax calls. Secondly, after 4 hours of debugging I've tried to change the f:viewParam like this:
<f:viewParam name="id_file" value="#{bean.idFile}" />
without "required": magically everything start working, I can click 1,2,3,etc and myMethod is called every time. So, the problem is that the ajax submit validate the parameter specified with f:viewParam, it sounds silly to me, but ok, I can live with it.
My questions are:
why this validation error doesn't appear the first time button is clicked? If you look at the ajax POSTs they are identical
it is supposed to be ok to validate the view parameters (that, in my idea, belongs to the view) on a partial ajax call?
is there a way to tell to primefaces not to validate on particular ajax request (process="#this" does not resolve)?
Thank you, I hope that my experience will allow you to avoid spending hours doing debugging!
The viewParam is a UIComponent. That means it's semantically no different from a <h:commandButton/> or a <h:inputText/> and it's liable to go thru every prescribed JSF request processing lifecycle phase, up to and including validation and conversion. In fact, the tag itself causes any given view to go into the full processing of any given page, just by being there
The <p:commandButton/> is going to do a postback, meaning, it's going to be re-requesting the same view, using a POST. So to solve your current problem, you need to base your required condition on that fact:
<f:viewParam required="#{!facesContext.postback}" name="id_file" value="{bean.idFile}"/>
What you get from the new condition is that the parameter will be required only on the first request. Subsequent postbacks will not trigger the condition. Just be sure you don't have any logic (maybe in a #PostConstruct that's built around that expectation
Related
I use OmniFaces' <o:validateAll> validator to validate a number of input components. This works fine as long as I do not put it into a RichFaces <rich:tabPanel>. When I do this and leave fields blank, validation fails (as expected), but the active tab is changed, regardless of the failed validation. Other validators I tried prevent the tabPanel from switching to another tab, whenever validation fails.
What could be the reason for this?
I'm currently using OmniFaces 2.1 and RichFaces 4.5.17.Final with Mojarra 2.2.12 on Wildfly 9.0.2.
Here is the XHTML code to reproduce the problem:
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:o="http://omnifaces.org/ui"
xmlns:rich="http://richfaces.org/rich">
<h:form id="form">
<rich:messages />
<rich:tabPanel id="tabPanel">
<rich:tab id="tab1" header="Tab 1">
<h:inputText id="myDouble" value="#{someDoubleVal}">
<f:validateDoubleRange minimum="1.0" maximum="2.0"/>
</h:inputText>
<o:validateAll id="allValid" components="myDouble" message="Missing value!" />
</rich:tab>
<rich:tab id="tab2" header="Tab 2">
Just another tab to switch.
</rich:tab>
</rich:tabPanel>
</h:form>
</ui:composition>
Enter a value outside 1.0 and 2.0 and try switching to Tab 2 to see expected behavior, triggered by <f:validateDoubleRange>: a faces-message is displayed and the first tab is still active.
Leave input blank and try switching to Tab 2 to see behavior of <o:validateAll>: validation seems to fail (a faces-message is displayed), but Tab 2 is activated.
Update: The described behavior applies with switchType="ajax" (the default) as well as with switchType="server". In both cases, the tab-panel performs a submit of the included inputs, so from a users point of view, a tab-switch seems to be the same as a <h:commandButton> submit (technically there might be differences, I don't know the implementation details of the tab-panel).
If I perform the tab-switch via a regular <h:commandButton> with a <f:setPropertyActionListener>, the <o:validateAll> behaves the same way as the other validators, i.e. the tab-switch is not performed due to the validation error.
<rich:tabPanel id="tabPanel" activeItem="#{bb.activeTab}">
...
<rich:tab id="tab1" name="tab1" header="Tab 1">
...
<h:commandButton value="submit">
<f:setPropertyActionListener value="tab2" target="#{bb.activeTab}" />
</h:commandButton>
...
</rich:tab>
</rich:tabPanel>
Note: This is just a minimalistic example showing the problematic behavior. In my real code I have not just a single component validated by <o:validateAll> and I do actually associate the input values with a backing-bean. The observed behavior is exactly the same.
The problem is two-fold.
First problem is, <o:validateAll> doesn't explicitly call context.renderResponse() when validation has failed and leaves this job to JSF which will implicitly call it during validations phase when at least one input component is found invalid after <o:validateAll> has run, or otherwise during the subsequent update model values phase.
Second problem is, <rich:tabPanel> tab switch event is queued for update model values phase instead of for invoke application phase. I'm not sure why RichFaces guys designed it like that, but the consequence is that the tab switch event is fired anyway even when validation is found failed during the update model values phase only.
When you move <o:validateAll> before at least one associated input component, then JSF will implicitly call context.renderResponse() during validations phase already and therefore completely skip the update model values phase and therefore the queued <rich:tabPanel> tab switch event won't have chance to be invoked.
I have fixed it in OmniFaces 2.6-SNAPSHOT as per issue 322. When using OmniFaces 2.6 or newer, it should not anymore matter where <o:validateAll> is placed in the tree in order to achieve the desired behavior of <rich:tabPanel> tab switch event to not be invoked.
I've been facing some problems using JSF with AJAX to render a table without reloading the whole page every time I submit a form.
When I first run the server, my database is empty, so the page is supposed to show only a form to add books. When user submits the form, a fieldset whith all books is supposed to be rendered. I don't want this fieldset to be shown when database is empty.
This is a simple version of my code (it is just a small form and a table to be refreshed using AJAX):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<h:graphicImage library="img" name="caelum-logo.png"/>
<h:form>
<p>Book Title:</p>
<h:inputText id="title" value="#{livroBean.livro.titulo}" />
<h:commandButton value="Add book" action="#{livroBean.addFirstBook}">
<f:ajax execute="#form" render="title :addedBooksTable" />
</h:commandButton>
</h:form>
<div id="addedBooksTable">
<p:fieldset rendered="#{livroBean.numberOfBooks > 0}">
<h:dataTable value="#{livroBean.allBooks}" var="book">
<h:column>
<h:outputText value="#{book.titulo}" />
</h:column>
</h:dataTable>
</p:fieldset>
</div>
</h:body>
</html>
And i wanna focus on this part:
<h:commandButton value="Add book" action="#{livroBean.addFirstBook}">
<f:ajax execute="#form" render="title :addedBooksTable" />
</h:commandButton>
The fieldset and the table inside it are supposed to be hidden when there's no book added to the database, that's why i used <p:fieldset rendered="#{livroBean.numberOfBooks > 0}">. But I want it to be rendered after I click the commandButton, even if there's nothing at the inputText.
Here's what's happening when I test the code:
if I test the code just as it is with an empty database, the inputText is refreshed (it "erases" what were typed before the submisssion) when I click on the commandButton, but the fieldset is not. I know that the fieldset has a rendered="#{livroBean.numberOfBooks > 0}" and the inputText does not, but the method getNumberOfBooks is called everytime i click the commandButton, that's why I don't get it...
if I change the f:ajax tag so it ends up like this <f:ajax execute="#form" onevent="click" render="title :addedBooksTable" />, it solves the problem, but i can realize the screen flashing for a while when I click the commandButton. As far as I know, one of the uses of AJAX is that we don't want the screen flashing when a request is made.
Why is the fieldset rendered only when I use onevent="click"? Should I consider the flashing something normal? Is there a more elegant solution for that?
Thanks!
You can't ajax-update a plain HTML element. You can only ajax-update a JSF component. Simple reason is that the target must be resolveable by UIViewRoot#findComponent(), so that JSF can find it in the component tree and render the updated HTML into the Ajax response.
Replace
<div id="addedBooksTable">
by
<h:panelGroup layout="block" id="addedBooksTable">
Normally, this should have thrown an exception as described in How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar", but they removed this check in Mojarra 2.2.5 in order to support ajax-updating a specific iteration of <ui:repeat> and <h:dataTable> (this missing check will be fixed later on as that's indeed unhelpful to starters like you).
As to why adding onevent="click" appear to work, that's because it caused a JavaScript error which in turn caused the whole JavaScript/Ajax thing to break down, which in turn caused that the command button fall backs to default synchronous behavior with a full page reload (as if you aren't using <f:ajax> at all). You likely meant to use event="click" instead. The onevent attribute serves a different purpose. See also a.o. Proccess onclick function after ajax call <f:ajax>.
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)
I have a Java Web Application (WAR) in Weblogic 10.3.0:
JSF 2.0
Primefaces 3.5
jboss-el-2.0.0.GA.jar (If i use el-api-2.2.jar and el-impl-2.2.jar is the same)
validation-api-1.1.0.Final.jar
Eclipselink (JPA 2.1)
hibernate-validator-4.2.0.Final.jar
JSTL 1.1
Java EE 5
I have a <h:form/> inside a <p:dialog/> to edit/create entities and persist them to the Database.
My problem is the <p:commandButton/> doesn't invoke the actionListener when the values are set directly to the entity's properties. For example, here is my code:
<h:form>
<p:outputLabel value="Name:" for="name" />
<p:inputText id="name" value="#{Servidores.selectedEntity.name}" title="Name" />
<p:outputLabel value="IP:" for="ip" />
<p:inputText id="ip" value="#{Servidores.selectedEntity.ip}" title="IP" />
<p:commandButton value="Submit" oncomplete="appEditingDialog.hide();" actionListener="#{Servers.processEntityAndRefresh()}"/>
</h:form>
But if i set values to a simple String variable declared in the bean and not in the entity it works. Like this:
<p:inputText id="name" value="#{Servidores.stringInMyBean}" title="Name" />
I thought it was a validation problem but if i put this form outside the Dialog it works.
What could be the problem and the solution here ? I've seen people putting the properties directly in the #ManagedBean but, wow, I can't mix the Model and the Controller.
Thanks.
This is how i solve this and other problems i had:
In my Template.xhtml i made sure the declarations are like this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
because instead of "java.sun.com" i had something with "xmlns.com" (something like that, i dont know why). My problems with the EL were solved but a new problem came out: Everything was big: font, components, etc.
I had to fix everything with CSS but i didn't like that way, it was unnaceptable! Plus, Dialogs were showing in the bottom of the page. So after trying some things, i fixed it making the Template Clients using HTML instead of just <ui:composition/>. So i could delete all the "forced changes" i made to my CSS files (I really don't know why that behavior with just <ui:composition/> ) .
But wait! , in a part of a page the problems came back! Calling methods/properties in the ManagedBean from a Datatable wasn't working properly again and it was because of the Primefaces <p:Dashboard/> tag called "Disabled" which i set it to true to not let the user move the panels. My datatable was inside of a Panel which was inside of a Dashboard, after setting it to false everything was working properly (I guess it is a primefaces bug).
Then, i just move from Primefaces 3.5 to 4.0 and used JSTL 1.2 instead of 1.1
But yeah, the main problem was because of the wrong links when declaring xmlns, xmlns:h, xmlns:f, etc.
Yesterday I was trying to implement a Listener for a SelectManyListbox using Ajax in JSF 2.
Following code is from my memory, since I dont have it available right now :-)
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:selectManyListbox value="#{myBean.myList}">
<f:ajax render="delete" listener="#{myBean.listener}" />
<h:selectManyListbox>
<h:commandbutton id="delete" disabled="#{myBean.disabled}" value="Delete" />
<h:body>
I tried a lot of different things because my listener was never called. In the end I just added a surrounding <h:form> tag and everything worked. Why is that?
My goal is a composite-control that just displays a list and enables/disables the delete-button when a item is selected/unselected. In my understanding a form is only needed when I want to submit multiple values at once.
Thanks
In my understanding a form is only needed when I want to submit multiple values at once.
This is thus untrue. A <h:form> is necessary when you want to send a POST request to the server by JSF by an UIInput component such as <h:selectManyListbox>. This is regardless of whether the POST request is performed by a regular (synchronous) request or an ajaxical (asynchronous) request. This is regardless of the amount of inputs. You should not forget that the javax.faces.ViewState hidden input field and if necessary also the name=value of the command button itself also needs to be sent along as well, so there's basically never means of a single input value in a JSF postback request.
POST has the major advantage over GET that there's no limit in the amount of data which can be sent. In GET this is dependent on the webbrowser used and ranges from 255 characters until 2~4KB in older browsers and 8~10KB in newer browsers. In POST the limit is usually around 2GB.