JSF p:commandLink and p:ajax have different behavior in update - java

I have a menu with list items and a p:commandLink inside. While using this for different pages I realized that I have problems updating form with a p:dataTable and p:columns inside. After clicking on the link, form2 which actually has some panels and the table inside should be updated. Now my problem: Only most of the content in form2 is updated correctly, but the p:columns have the old value. If I click again on the link, the correct values are shown.
The bean method public void selectProject(Project myProject) is called correctly and the values are correctly processed.
Now the strange thing: If I add a h:graphicImage with a p:ajax everything works fine!!
<h:form id="form1">
...
<li>
<p:commandLink update=":form2" actionListener="#{bean.selectProject(p)}">
<h:outputText value="#{p.name}" />
</p:commandLink>
<!-- Code below is for testing only, but works fine! -->
<h:graphicImage value="#{iconBean.icon(12,'clock')}">
<p:ajax event="click" update=":form2" listener="#{bean.selectProject(p)}"/>
</h:graphicImage>
</li>
...
</h:form>
Update This does not seem to be related to p:columns, a simplified test case shows the expected behavior of p:commandLink. In the original (still failing) setting the menu is implemented as a composite component.

As a workaround I use
<h:commandLink>
<h:outputText value="#{p.name}"/>
<p:ajax event="click" update=":form2" listener="#{bean.selectProject(p)}"/>
</h:commandLink>

Related

Primefaces / JSF: selectOneMenu value is not set, ajax listener not called

I am using Primefaces and JSF to develop this frontend. My issue is that one of my selectonemenus never sets its value binding, "selectedGroup", so the second dropdown is never populated. My backing bean is being called to "update" the second selectonemenu, but the listener of that ajax is not called, nor is selectedGroup ever set. This code is effectively identical to the Showcase for "Select". I even verified that the showcase code works from scratch (which i did not doubt), but fail to see how my situation is any different from that example.
Other stackoverflow questions on this topic indicate that something was left out, but none of those suggestions matched my issue.
I have two selectOneMenus, like so.
<h:form id="outerForm">
<p:panel id="outerPanel">
<p:panelGrid id="outerPanelGrid">
<h:outputLabel for="groupSelection" value="Group: "/>
<p:selectOneMenu id="groupSelection" value="#{myBean.selectedGroup}" >
<p:ajax update="commandSelection"
listener="#{myBean.handleGroupSelection}" />
<f:selectItem itemLabel="---Please Select Group---" itemValue=""/>
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group.name}" />
</p:selectOneMenu>
<h:outputLabel for="commandSelection" value="Command: "/>
<p:selectOneMenu id="commandSelection" value="#{myBean.command}">
<f:selectItems value="#{myBean.commandStringsList}"/>
</p:selectOneMenu>
</p:panelGrid>
</p:panel>
</h:form>
This page is being displayed in the "center" portion of my layout template like so..
<ui:define id="content" name="content">
<p:panel id="contentPanel" style="float:left; border:none">
<ui:include src="#{anotherBean.currentView}.xhtml"/>
</p:panel>
</ui:define>
The backing bean DOES use some data classes to contain some of the data which is populated, but I thought i was doing everything correct to map it into the view. For the most part, I am using Strings, though.
Does anyone see what I am missing? At the very least, is this xhtml valid?
I should also mention that this page was working before I created and used a template. Basically, I was rendering it in a tab of a tabview using ui:include in the body of index.xhtml. Though I did not notice initially, this page stopped working sometime after I incorporated the template (poor testing on my part, I know).
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group.name}" />
you can't specify selectItems this way. translation has to be bidirectional. use a converter!
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group}"
converter="groupConverter"/>

Server side listener for rich:dataScroller (RF 4.1)

I'm using an extendedDataTable because I need multiselect. The table can get pretty large, so I'm using a dataScroller for paging.
What I want to achieve is, that the selection is cleared when switching to another page. The selection is stored in the backing bean and I have a method clearTableSelection to clear the selection.
Now my question is, how is it possible to call the method clearTableSelection when switching pages.
I found a simple solution:
...
<rich:extendedDataTable>
...
<f:facet name="footer">
<rich:dataScroller
onbegin="document.getElementById('form:hiddenButton').click()" />
</f:facet>
</rich:extendedDataTable>
<a4j:commandButton
id="hiddenButton" action="#{backingBean.clearTableSelection}"
value="HiddenButton" execute="#this" style="display: none;" />
...

Cancellation of Ajax Request in RichFaces

I have issue with canceling Ajax Request. Our application interface is build in RF.
On the progress bar modal there should be cancel button - that interupt current operation,
for example cancel filling controls from database. How to make it?
I tried using reloading page, flags with "if" conditions on getters for controls and also using "bypassUpdates" with no positive effects.
Thanks in advance for your help
XHTML (Button):
<a4j:commandButton id="showData"
value="View" styleClass="hBtn"
disabled="#{events.isButtonsDisabled}"
oncomplete="if (#{facesContext.maximumSeverity==null})
{window.open('/seed/pages/data.jsf','DATA')};"
actionListener="#{events.actionShow}"/>
JAVA: (Button):
public void actionShow(ActionEvent evt) {
//Some logic, getting data from database
}
XHTML (Main Page - showing wait Popup)
<a4j:form>
<a4j:status id="ajaxStat"
onstart="Richfaces.showModalPanel('waitPanel');"
onstop="#{rich:component('waitPanel')}.hide()" />
</a4j:form>
XHTML (Popup):
<rich:modalPanel id="waitPanel" autosized="true" moveable="false"
minWidth="250" styleClass="popup">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Operation in progress"></h:outputText>
</h:panelGroup>
</f:facet>
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="../images/icons/action_close.gif" styleClass="hidelink" id="hidelink"/>
<rich:componentControl for="waitPanel" attachTo="hidelink" operation="hide" event="onclick"/>
</h:panelGroup>
</f:facet>
<a4j:form id="msgFrm" ajaxSubmit="true">
<h:outputText value="Please wait..."/>
<h:graphicImage styleClass="progressBar" value="../images/indicatorbar.gif"/>
<a4j:commandButton value="Cancel" type="button"
onclick="#{rich:component('waitPanel')}.hide()"
action="#{main.cancelAction}"
bypassUpdates="true"/>
</a4j:form>
</rich:modalPanel>
JAVA (Popup):
public void cancelAction(){
//there was setter for true/false flag for actionShow() here, now there is nothing here (it was not working)
}
Reloading the page stops all current ajax requests. It does not stop the java backing beans from finishing the requests but I assume that is not the question.
c:if and the ajax render do not mix very well. Possibly you could use 'rendered' to disable updating the controls? Then split the control in two parts. One is shown with valid data and for example bright blue. The other is rendered without any data and has a grey picture.
But... I'm not sure I understand the question correctly.
Edit 23-1-2012: Seeing the code I would say that the cancelAction must set a flag that then finishes the action running inside actionShow(). Then the ajax request finishes and the popup is closed. Can't see why this won't work.

Rules for ids to update components

I'm new to JSF2 and Primefaces and realized an issue to update components.
Lets' assume I have the following piece of code, I can directly update="counter"
<h:form id="f1">
<h:outputText id="counter" value="#{clientBean.counter}" />
<h:graphicImage url="/images/circle-ok.png">
<p:ajax event="click" update="counter" process="#this"
listener="#{clientBean.tag}"/>
</h:graphicImage>
</h:form>
In another h:form I have to use update="f1:counter". Only a update="counter" does not work here.
<h:form id="f2">
<p:dataTable var="var" value="#{clientBean.vf}">
<p:column>
<f:facet name="header">Tag</f:facet>
<h:graphicImage url="/images/circle-ok.png">
<p:ajax event="click" update="f1:counter" process="#this"
listener="#{clientBean.tag}" />
</h:graphicImage>
</p:column>
</p:dataTable>
</h:form>
I haven't faced this with JSF1.2 (and RichFaces), what are the rules to address the ids correctly?
In your first example JSF could lookup up the counter element in the same scope as ajax listener. Form implements NamingContainer which means it prefixes client ids (used in html) with its own id and creates a distinct name space for ids. Have a look at the page source under browser - there will be f1:counter id assigned to your counter. In your second example there is no counter element in the scope (inside form f2) so the lookup fails.
You can disable this form behaviour with prependId="false". This is useful if you are sure there won't be elements with identical ids across all forms.
Icefaces works differently - it automatically calculates the html delta and sends it to the browser as partial update. In most cases this is more convenient for the programmer but comes with considerable performance cost. I believe JSF2 adopted icefaces partial updates concept but requires ids to be passed explicitely.

How to refer to dataTable parent within the dataTable?

Consider a dummy case:
<h:form id="wrapperForm">
<h:panelGroup id="rowsContainer">
<h:dataTable id="rowsTable" value="#{bean.rows}" var="row" >
<h:column>
<h:commandButton value="Click me to update (#{component.parent.parent.parent.clientId})">
<f:ajax render=":#{component.parent.parent.parent.clientId}" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:panelGroup>
</h:form>
On button click, the id=rowsContainer gets successfully updated as it should.
However, if I add ui:repeat there, it does not work anymore:
<h:form id="wrapperForm">
<ui:repeat id="blocksRepeat" var="block" value="#{bean.blocks}">
<h:panelGroup id="rowsWrapper">
<h:dataTable id="rowsTable" value="#{block.rows}" var="row" >
<h:column>
<h:commandButton value="Click me 2 update (#{component.parent.parent.parent.clientId})">
<f:ajax render=":#{component.parent.parent.parent.clientId}" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:panelGroup>
</ui:repeat>
</h:form>
Instead, this gets:
<f:ajax> contains an unknown id ':wrapperForm:blocksRepeat:0:rowsWrapper' - cannot locate it in the context of the component j_idt363
However, that component is really there with that ID, so the EL should be ok. Somehow the ui:repeat breaks the case. Is it possibly trying to evaluate the EL before the actual loop?
How do you refer to the rowsWrapper element from within the dataTable?
Note: I recently asked about odd dataTable naming within ui:repeat, which turned out to be a bug. This issue should not be related to that, however, as I am wrapping the dataTable within a panelGroup as suggested here.
There are actually two things going wrong:
1) ui:repeat is broken
As answered by BalusC in the comments of the question, the first issue occurs (once again) due to a bug in Mojarra. It seems ui:repeat is so broken even the wrapper container holding the h:dataTable does not help. For more details, see question "Why doesn't h:dataTable inside ui:repeat get correct ID?" and the comments of this question.
As BalusC suggests, a workaround is to use h:dataTable instead of ui:repeat. It will provide unconvenient (<table>) HTML but works. This removes some odd issues when adding and removing rows to/from the inner iteration.
Note: some issues regarding ui:repeat seem to be fixed in Mojarra 2.0.3 but not all.
2) The references just fail
Even with h:dataTable workaround, the reference to the inner h:dataTable from the button inside it fails. As there is no ui:repeat in use, this must be datatable's internal issue. I don't see any solution at the moment, so I filed a ticket for this behavior as well.

Categories