I'm in the process of migrating our primary application from Seam 2.2 to Seam 2.3beta1, in order to get some of the benefits of JSF 2.0 and JPA 2.0. For the most part, it's going smoothly. However, some of the Ajax changes in JSF 2.0 and Richfaces 4.x are proving to be problematic in porting the code.
I have a series of components that are populated based on the contents of the others. For example, the first menu selects the item category. When a value is selected, the subcategories of that category are retrieved from the database and act as the selection items for the second menu. This entire process is Conversation scoped. Currently, the code looks like this:
<h:selectOneMenu value="#{newObjAction.category}"
required="true"
requiredMessage="You must select a category"
style="width:300px;">
<s:selectItems var="cat"
value="#{newDesignAction.designCategories}" label="#{cat.name}"
noSelectionLabel="Select a category..."
hideNoSelectionLabel="true" />
<s:convertEntity />
<a:support event="onchange" reRender="subCategoryPanel"
limitToList="true" ajaxSingle="true" status="subCategoryStatus" />
</h:selectOneMenu>
This works with no problem in Seam 2.2 with JSF 1.2. However, has been removed from JSF 2.0. I've tried something like this in its place:
<f:ajax listener="#{newObjAction.handleCategoryChange}">
It fires the event as expected, but there's one large problem: it is not propagating the conversation. As a result, when the listener object is about to be called it is intercepted and the user is redirected to the defined no-conversation-view-id from pages.xml. Is there any way to propagate the conversation when using <f:ajax />? Is there a better way to accomplish this? At this point the entire migration is at a stand still, as this is a major component in the application.
I'd REALLY appreciate any help or advice.
Related
Okay, so I have read through stackoverflow and various other portions of the net for a few days, and have not found a solution yet that fixes my issue.
Basically, I have an h:form in a p:dialog with two required fields. When the fields are both filled in, the form successfully submits and the dialog closes. When either or both fields are left blank, required field validation fails and updates the h:messages component in the p:dialog with the appropriate required messages. However, also when validation fails, the AJAX call seems to never "finish" and prevents subsequent calls from being executed. This is seen evident by my p:ajaxStatus component never disappearing from the screen, indicating that something is hanging somewhere. This is remedied by refreshing the page, at which point all other AJAX components begin to function again.
Additionally, I will note that this p:dialog is in a ui:define in a ui:composition, that dumps it into a master template. It is not nested within another h:form.
<p:dialog id="dlgDecision"
header="Decision"
widgetVar="dialogDecision"
modal="false"
resizable="false"
appendToBody="true">
<h:form id="fDlgDecision">
<h:messages id="msgDlgDecision" binding="#{msgform.messages}" errorClass="errormsg" infoClass="infomsg1" layout="table"/>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'A'}">
<h:outputText value="Select an accept and admit code."/>
</h:outputFormat>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'C'}">
<h:outputText value="Select a cancel and reason code."/>
</h:outputFormat>
<h:panelGrid columns="1">
<h:selectOneMenu id="apdcCode"
value="#{studentDetails.apdcCode}"
required="true"
requiredMessage="Please choose a decision code.">
<f:selectItem itemLabel="Select Decision Code"/>
<f:selectItems value="#{apdcCodes.apdcCodeList}"
var="apdc"
itemValue="#{apdc.apdcCode}"
itemLabel="#{apdc.apdcCode} - #{apdc.apdcDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="admtCode"
value="#{studentDetails.admtCode}"
required="#{studentdetailsform.decisionAction == 'A'}"
requiredMessage="Please choose an admit code."
rendered="#{studentdetailsform.decisionAction == 'A'}">
<f:selectItem itemLabel="Select Admit Code"/>
<f:selectItems value="#{admtCodes.admtCodeList}"
var="admt"
itemValue="#{admt.admtCode}}"
itemLabel="#{admt.admtCode} - #{admt.admtDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="wrsnCode"
value="#{studentDetails.wrsnCode}"
required="#{studentdetailsform.decisionAction == 'C'}"
requiredMessage="Please choose a reason code."
rendered="#{studentdetailsform.decisionAction == 'C'}">
<f:selectItem itemLabel="Select Reason Code"/>
<f:selectItems value="#{wrsnCodes.wrsnCodeList}"
var="wrsn"
itemValue="#{wrsn.wrsnCode}"
itemLabel="#{wrsn.wrsnCode} - #{wrsn.wrsnDesc}"/>
</h:selectOneMenu>
<p:commandButton id="decisionSubmit"
value="Submit Decision"
type="submit"
action="#{mainform.saveDecision}"
ajax="true"
partialSubmit="true"
process="#form"
update="#form msgDlgDecision"
oncomplete="if (!args.validationFailed) dialogDecision.hide()"/>
</h:panelGrid>
</h:form>
</p:dialog>
Some things I have already done in my debugging and troubleshooting:
- Moved the h:form into the p:dialog
- Made the backing bean with the values for the rendered attribute on the required fields ViewScoped (was having an issue with only some of the required messages showing, this resolved this problem)
- Added appendToBody="true" to p:dialog
- Added if (!args.validationFailed) to the oncomplete event of p:dialog
- Tried making the required fields NOT conditional (removed rendered attributes) to be sure this wasn't being caused by failed validation on non-rendered components (grasping at straws...)
EDIT: Here is a console dump from Chrome. Javascript error gets thrown when submitting the form with null required fields.
Uncaught SyntaxError: Unexpected token { jquery.js:14
bG.extend.parseJSON jquery.js:14
PrimeFaces.ajax.AjaxUtils.handleResponse primefaces.js:1
PrimeFaces.ajax.AjaxResponse primefaces.js:1
j.success primefaces.js:1
bZ jquery.js:14
b7.fireWith jquery.js:14
ca jquery.js:21
bZ
EDIT 2: Below are the only two JavaScript imports, both of which are in my template that is applied to the page via the ui:define and ui:composition mentioned above.
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<script type="text/javascript" src="#{request.contextPath}/resources/scripts/jscript.js" />
The first import will force Primefaces to import jQuery into the page, even if there are no components on the page that utilize JavaScript. This is to allow my custom scripts in jscript.js to use jQuery reliably.
Other information:
JSF 2.1
Primefaces 3.4.2
Tomcat 6.0
Don't import jQuery.js manually as this is already done implicitly by PrimeFaces (it uses jQuery under the hood). You can remove that line.
Also you should see some examples of importing your custom js files with h:outputScript like this for example:
<h:outputScript library="scripts" name="jscript.js" />
but this is probably not reason of your problem, this is just hint for better JSF design.
A similar error showed up in Google Chrome, today, after I downloaded PrimeFaces 4.0 snapshot (2013-05-09) and tested my app.
Basically, I had to remove single quotes from data sent from bean to p:schedule via JSON. Since the error mentioned 'parse JSON' and "unexpected '" (unexpected single quote), I went to the datatable view of my data (instead of p:schedule) and recognized that some of the data had single quotes embedded. So, I removed the single quotes from the data, and that solved the issue for me.
Please click forum topic URL below.
PF 4.0 SNAPSHOT 2013-05-09: schedule not working
I've had the exact same problem at my application. The real problem was a duplicate jar problem.
I've had two primefaces jar in my application, one under the WEB-INF/lib directory, and the other under the ear/lib directory. Once I deleted the one under the WEB-INF, everything started to work as expected.
You could find the solution on the net via a search for the js exception.
I use Primefaces 3.2 with ApacheMyfaces on WebSphere Application Server 8.
I have a selectOneButton with an ajax update inside.
When I switch the button, my setter firsts sets the value (int) to 0 and then to the value which is selected:
<p:selectOneButton value="#{graph.view}" id="view">
<f:selectItem itemLabel="W" itemValue="1" />
<f:selectItem itemLabel="M" itemValue="2" />
<f:selectItem itemLabel="Y" itemValue="3" />
<p:ajax event="change" update=":optform:datecol"/>
</p:selectOneButton>
datecol is another selectComponent inside my form (optform).
Why does JSF first set the value to 0 and then to e.g. 2?
SOLUTION
It is a PrimeFaces selectOneButton Bug. See My question here .
Best Regards
Veote
Likely what you are seeing is that the managed bean graph is being instantiated early in the JSF lifecycle, and only later in the APPLY_REQUEST_VALUES phase is the appropriate value being set for the managed property view. The managed bean regardless of scope, will be reinstantiated after each request due to the inherently stateless nature of the web.
For more information, BalusC has a great article on debugging the JSF Lifecycle with a step-by-step walkthrough on how to implement a custom PhaseListener that will help you understand and debug behavior like this in your application.
http://balusc.blogspot.com/2006/09/debug-jsf-lifecycle.html
JFS1.2 + Richfaces 3.3
Situation is as follows:
JSP page renders conditionally one or another panelGroup.
Within each panelGroup there are couple setters and one command button.
Each of two panelGroups uses own bean for setting and performing action.
On the top of a page there's selectOneRadio with (obvious) two items - coresponding tow options of conditional rendering.
Page renders properly, switcher causes to render appropriate panel.
Case is, commands buttons doesn't call an action.
I know what's going on - when I click a button to call action dom is regenerated, but the value that hold my decision to display particular panel doesn't exist anymore. The button is not recreated, action is not fired.
Technically:
<h:selectOneRadio value="#{reportType}">
<f:selectItem itemLabel="x" itemValue="x"/>
<f:selectItem itemLabel="y" itemValue="y"/>
<a4j:support event="onclick" reRender="xPanel, yPanel/>
</h:selectOneRadio>
<h:panelGrid id="xPanel "columns="2" rendered="#{reportType eq 'x'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
<h:panelGrid id="yPanel "columns="2" rendered="#{reportType eq 'y'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
Question is, how to design the page to obtain proper rendering and actions?
For now, I created additional session bean that holds switching value (x|y), but that desing smells bad for me...
RichFaces 3.3 offers the <a4j:keepAlive> tag which does basically the same as Tomahawk's <t:saveState> and JSF2 #ViewScoped. Add the following line somewhere in your view:
<a4j:keepAlive beanName="#{bean}" />
This will keep the bean alive as long as you're returning null or void from action(listener) methods.
See also:
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
I'm working on an application that's basically a customised database administration tool.
The page structure is basically the following:
<a4j:region>
<h:selectOneMenu value='#{bean.selectedTable}'>
...
<a4j:ajax event='change' render='tablePanel'/>
</h:selectOneMenu>
<a4j:outputPanel id='tablePanel'>
<rich:extendedDataTable id='table' selection='#{bean.selectedRows}' ...>
<f:facet name='header'>
[datascroller etc.]
<a4j:commandButton action='#{bean.deleteSelectedRows}' execute='#region' render='tablePanel'/>
</f:facet>
[columns]
</rich:extendedDataTable>
</a4j:outputPanel>
<a4j:region>
The selectOneMenu is used to choose which database table will be displayed. The backing bean is request scoped and set up to pick the first available table as a default when it's initialised. I'm using an ExtendedDataTable subclass to paginate data in the database.
When I click the commandButton to delete the rows, it seems that the extendedDataTable component determines the selected rows /before/ the value of bean.selectedTable is applied. This means that no matter what table is selected in the dropdown menu, RichFaces tells me the selected rows are some (more or less arbitrary) rows in the default database table.
I verified that this is an ordering problem, when deleteSelectedRows() is called the value of selectedTable is correct. I'm using Richfaces 4 M6, and a4j:keepAlive doesn't seem to be there anymore to preserve the bean state.
Is there a way to tell RichFaces / JSF in which order to do these things? I tried using immediate="true" on the h:selectOneMenu but that didn't help.
Also, after a delete, the tablePanel doesn't seem to be rerendered, while another a4j:commandButton that adds new records with the same execute and render attributes seems to work fine. Is there a way to debug the state of RichFaces ajax requests / hook into them via events?
I have JSF page has two drop down lists and I want to load the second one with values based on what was chosen in the first one. However, the "onchange" event is only detected the second time I change the selection!
Web page Code snippet:
<h:form id="selectRegion">
<h:selectOneMenu id="governorate"
value="#{SearchView.governorate}"
styleClass="mediumInput" immediate="true"
valueChangeListener="#{SearchView.goverValueChanged}"
onchange="submit();">
<f:selectItems value="#{SearchView.goverItemsList}" id="govItems" />
</h:selectOneMenu>
<h:selectOneMenu id="district"
value="#{SearchView.district}"
styleClass="mediumInput">
<f:selectItems value="#{SearchView.districtItemsList}" id="distItems" />
</h:selectOneMenu>
</h:form>
<h:form id="SearchFor">
<hx:commandExButton
id="button1" styleClass="btn" type="submit"
value="Search" action="#{SearchView.searchAction}"
onclick="document.getElementById('selectRegion').submit();">
</hx:commandExButton>
</h:form>
The problem is that goverValueChanged(ValueChangeEvent event) is invoked only when I modify the value of the governorate for the second time but not for the first time (I put system out in goverValueChanged(ValueChangeEvent event) to know that).
Does anyone have an idea regarding what might be wrong? Thanks in advance! I am using JSF 1.1 and run on IBM WAS
It has been a long time ago I fighted with IBM and JSF 1.1 for last time, but I vaguely recall some ancient JSF 1.1 bug which caused that the valueChangeListener won't be fired when the initial value is null. I'd suggest to set the initial value (the property behind value="#{SearchView.governorate}") to an empty string or to something else.
You can of course also upgrade JSF 1.1 to the latest build JSF 1.1_02. It has pretty a lot of functional bugfixes, maybe it will also fix this (and other) problems. IBM WAS 5.x namely ships with a very early version of JSF 1.1 which is cluttered of some odd bugs like that. Or maybe you're using IBM WAS 6.x, then you can also dump JSF 1.1 altogether and go for the much improved JSF 1.2. You can download JSF libraries from the archives right here.