<p:dataTable filteredValue> is called in spite of rendered=false - jsf

I am wondering about the following behaviour of <p:dataTable filteredValue>. Hopefully you can explain it and tell me how to avoid it.
The backing bean method is called even though the corresponding component is not rendered.
<p:panel rendered="#{false}">
<p:dataTable ... filteredValue="#{backingBean.filteredRowModels}">
...
</p:dataTable>
</p:panel>
Do you know how avoid calling the backing bean method if it is not rendered?

Related

Why is this ViewScoped managed bean not working and how can I make it work?

This is the list page I have:
<h:dataTable value="#{actorSearchBacking.all}" var="actor">
<h:column>
<f:facet name="header">
First Name
</f:facet>
#{actor.firstname}
</h:column>
<h:column>
<f:facet name="header">
Last Name
</f:facet>
#{actor.lastname}
</h:column>
<h:column>
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
</h:column>
</h:dataTable>
which looks something like this in my local environment:
This is pocdetail.xhtml which is the action of Update Actor button:
<h:body>
<h:form id="updateActorForm"
prependId="false">
<h:inputText id="firstname" value="#{actorFormBacking.stupidActor.firstname}"/>
<h:inputText id="lastname" value="#{actorFormBacking.stupidActor.lastname}"/>
<h:commandButton id="updateActorButton"
value="Update Actor!"
action="#{actorFormBacking.updateActor()}"/>
</h:form>
</h:body>
And finally ActorFormBacking is as follows:
#ManagedBean
#ViewScoped
public class ActorFormBacking implements Serializable {
private Actor stupidActor;
public Actor getStupidActor() {
return stupidActor;
}
public void setStupidActor(Actor stupidActor) {
this.stupidActor = stupidActor;
}
}
When I debug the application, I see that setStupidActor is called and property stupidActor is set, but then when getter is called, it is again null.
Since this is a ViewScoped bean, I am expecting the stupidActor not to be null and I expect to see the pocdetail.xhtml page to be filled with values, but all I see is empty input texts since stupidActor is null.
What is it that I am missing? Why is the ViewScoped bean created again and the property is null?
Btw, I am using the annotations from the packages:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
It appears that you're navigating from one view to another view. In other words, you destroy the current view and create a new view. Logically, the view scope will also get destroyed and newly created, including all view scoped managed beans. That the view scoped managed bean happens to be referenced by both views doesn't change this behavior.
A view scoped bean lives as long as the view itself. Like as that a request scoped bean lives as long as the request itself and so on. In order to have a better understanding of the lifetime of various scopes in JSF (and CDI), head to this Q&A: How to choose the right bean scope?
The functional requirement is however understood. You want separate master-detail pages and pass the selected item from the master page to the detail page for editing. There are several ways to achieve this:
The canonical way is to just use a bookmarkable GET link instead of an unbookmarkable POST link. Replace the below piece
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
by this
<h:link value="Update Actor" outcome="pocdetail">
<f:param name="stupidActor" value="#{actor.id}" />
</h:link>
and in the detail page, obtain the Actor by its identifier which is passed-in as query string parameter. This is fleshed out in detail in this Q&A: Creating master-detail pages for entities, how to link them and which bean scope to choose. A #FacesConverter(forClass) is very useful here.
In case you want to stick to POST for some reason, then your best bet is storing it in the request scope.
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("stupidActor", stupidActor);
and retrieve it in the #PostConstruct of the very same bean
stupidActor = (Actor) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("stupidActor");
If you happen to use CDI, or are open to (which I strongly recommend though, JSF managed beans are already deprecated in JSF 2.3.0-m06, see also Backing beans (#ManagedBean) or CDI Beans (#Named)?), then consider using MyFaces CODI's #ViewAccessScoped. Beans with this scope will live as long as all postbacked views explicitly reference the bean. Once you navigate out with a GET, or when the navigated view doesn't anywhere reference that bean, then it will get destroyed.
#Named
#ViewAccessScoped
public class ActorFormBacking implements Serializable {}
Merge the both views into a single view with conditionally rendered master-detail sections. You can find a kickoff example in this Q&A: Recommended JSF 2.0 CRUD frameworks. Or if you happen to use PrimeFaces, How to show details of current row from p:dataTable in a p:dialog and update after save.

Trying to render a h:panelGroup outside ui:repeat with complicated structure

This is the general structure of the jsf page:
<ui:repeat id="repeater" varStatus="stat" >
<h:form id="the-form">
<h:panelGroup id="renderme">
<ui:repeat id="inner-repeater">
<h:commandButton>
<f:ajax render=":repeater:#{stat.index}:the-form:renderme">
</h:commandButton>
</ui:repeat>
</h:panelGroup>
</h:form>
</ui:repeat>
So.. the button here, when clicked, should cause the element renderme to be re-rendered.
In practice, I get "component with id ... not found" although when I look at the html page, the generated id is correct.
Moreover, I tried to use #{component.parent.parent.clientId} which produced the same id and still got the same error message from JSF.
Any idea on why this is failing?
Thanks!
This doesn't work for the simple reason because viewRoot.findComponent("repeater:0:the-form:renderme") as requested by <f:ajax render> doesn't return anything. Such a component does not exist in the component tree. This ID only exists in the generated HTML output. Instead, it's viewRoot.findComponent("repeater:the-form:renderme") which would return something, but this does in turn not exist in HTML DOM tree where JavaScript needs to do the update based on ajax response. Even then, this is not exactly what you need.
This is where JSTL can come to rescue. It's capable of dynamically building the JSF component tree and of dynamically assigning IDs to components generated in a loop:
<c:forEach ... varStatus="stat">
<h:form id="the-form_#{stat.index}">
<h:panelGroup id="renderme">
<ui:repeat id="inner-repeater" ...>
<h:commandButton ...>
<f:ajax render=":the-form_#{stat.index}:renderme">
</h:commandButton>
</ui:repeat>
</h:panelGroup>
</h:form>
</c:forEach>
This will only cause problems when you bind <c:forEach> value to a view scoped bean and you use Mojarra version older than 2.1.18. You'd need to upgrade to at least Mojarra 2.1.18 then.
See also:
JSTL in JSF2 Facelets... makes sense?

f:setPropertyActionListener doesn't set the value however action is triggered

I need to set a boolean field whenever p:fieldset is toggled. I tried out following code but the field is never set by f:setPropertyActionListener although p:ajax listener is invoked on toggle. I tried out following code.
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="..">
<f:setPropertyActionListener target="#{viewScope.rendrUsrProjctsList}" value="#{true}"/>
</p:ajax>
</p:fieldset>
However when I tried modifying the code as below then field is successfully set:
<p:fieldset legend="(Optional) Link.." toggleable="true">
<p:ajax event="toggle" listener="#{view.viewMap.put('rendrUsrProjctsList', true)}" />
<p:ajax event="toggle" listener=".."/>
</p:ajax>
</p:fieldset>
I want to ask:
Why 1st way doesn't work ?
Is it bad attaching multiple p:ajax to
single parent as done in 2nd way ?
The <f:setPropertyActionListener> works as being an ActionListener implementation only on components implementing ActionSource interface, such as UICommand, i.e. <h:commandXxx>, <p:commandXxx>, etc. The <p:ajax> does not implement this interface and therefore the <f:setPropertyActionListener> is basically completely ignored.
As to your workaround, you could do so although I'd rather just use a concrete view scoped bean or wrap it in a composite with a backing component.

<h:commandLink> not working inside a <h:dataTable>

I will try to explain myself:
I'm working on a JSF project using java, JSF 2.0 and RichFaces 4.2.1.
When I access my jsf it just loads a search filter and a commandLink. The commandLink will launch a method in my backingBean to load data that it will be displayed in a dataTable.
<h:commandLink id="btnRecords">
<f:ajax render="myCompAjax" event="click" listener="#{myBean.loadRecords}" />
<h:graphicImage value="img/ico_new.gif" alt="#{bundle['button.search']}" />
</h:commandLink>
The datatable is not visible at first, but once you click on the commandLink a flag in the backingBean will change and the table displays with data I just loaded.
<a4j:outputPanel ajaxRendered="true" id="myCompAjax">
<h:dataTable id="recordsTable" value="#{myBean.records}"
var="item" rendered="#{myBean.flagShowTable}">
<h:column headerClass="thPijama" >
<f:facet name="header">
<table><tr class="thPijama"><td></td></tr></table>
</f:facet>
<h:commandLink action="#{myBean.goNextPage}">
<h:outputText value="Go Next Page" />
<h:inputHidden value="#{item}" />
</h:commandLink>
</h:column>
</h:dataTable>
</a4j:outputPanel>
Problem is the commandLink action inside of the dataTable isn't working at all. I just want to navigate to another jsf. In fact, what it does is hiding the dataTable and leaving the filter unchanged. The action method remains unreachable.
Of course, it works if I set the same commandLink outside the dataTable.
I cannot use Session Scope Beans because the people I work for don't approve it.
Can anyone help me?
Thanks for the hint.
I cannot use Session Scope Beans because the people I work for don't approve it.
Are you implying that placing the bean in the session scope instead of the request scope actually solved the problem? If so, then just put the bean in the view scope.
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
// ...
}
This way the bean will live as long as you're interacting with the same view by ajax requests. The bean is not been shared in other browser tabs/windows in the same session (which is among the architects indeed the major reason to forbid its use in case of simple views).
See also:
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4 applies to you

Losing inputs submitted in composite component

I have a problem with submitting composite components.
Most of my composite components contain both the input components and the "submit" button.
When I tried to put the button still in the same h:form but not in the same composite component, the submitted value seemed to be "lost" somewhere. And, for instance, my validators got called on original values.
Example :
<composite:interface>
<composite:attribute name="titreContext" required="true"/>
</composite:interface>
<composite:implementation>
<p:outputPanel id="selectionTitreDetailsPanel" styleClass="selectionTitreDetails">
<p:outputPanel id="selectionTitreDetailsPanelInner" rendered="#{not empty cc.attrs.titreContext.selected}">
<p:panelGrid columns="2" id="panelId">
<h:outputText id="idLabel" value="Id :"/>
<h:outputText id="id" value="#{cc.attrs.titreContext.selected.titeluid}"/>
<p:tooltip for="id" value="Identifiant unique"/>
</p:panelGrid>
<p:panelGrid columns="2" id="titelePanel">
<p:outputLabel for="selectTitele" value="Titre :"/>
<p:selectOneMenu id="selectTitele" value="#{cc.attrs.titreContext.selected.titele}" effect="fold" styleClass="fullWidth">
<f:selectItems value="#{constants.getTitelesForTypman(cc.attrs.titreContext.selected.titele.typman)}" var="titele" itemLabel="#{titele.titelelil}" itemValue="#{titele}" styleClass="fullWidth"/>
<p:column styleClass="fullWidth">#{titele.titelelil}</p:column>
</p:selectOneMenu>
</p:panelGrid>
[...]
<p:commandButton id="confirmerModifications" icon="small_edit" type="submit" value="Confirmer les modifications"
action="#{elutersEditionContext.confirmeModifsSelection}" process="mandatsTerritorial"
update="mandatsTerritorial #{cc.attrs.notifUpdates}"/>
</composite:implementation>
works.
But putting the p:commandButton out of the composite :
<h:form>
<mylib:mycomponent /*parameters *//>
<p:commandButton /*parameters*/ />
</h:form>
does not work. When I debug my validators, I can see that the modified values where not even submitted. Neither getLocalValue, getSubmittedValue nor getValue is changed.
Is there a syntax in composite component declaration to use to correct this situation ?
By the way : when I was writing my components as composite components rather than custom components, retrieving #{asen} in the backing bean just worked.
Thanks in advance.
I am using :
PrimeFaces 3.4.1
CODI 1.0.5
OpenWebBeans 1.1.6
MyFaces 2.1.9
Tomcat 7.0.32
(update) This very strange problem was caused by h:form nesting.
Very strange because h:form nesting did not perturbate the processing of the first level of composite components, but caused this strange "input lost" in nested composite.
Nesting looked like this :
<h:form>
...
<p:tabView ...>
<p:tab>
<h:form>
<my:composite ....>
</h:form>
</p:tabView>
</h:form>
You're using a relative client ID in the process attribute of the <p:commandButton>:
<p:commandButton ... process="mandatsTerritorial" />
A relative client ID is relative to the parent NamingContainer component. It will be searched as direct child of the NamingContainer component. If the child is by itself a NamingContainer, then its children would not be searched.
Composite components are by itself in fact also NamingContainer components. If the button is placed in the composite, then this will be searched as direct child of the <cc:implementation>. In your particular case, only the component with id="mandatsTerritorial" will be processed on form submit, including all of its children (note that this component is nowhere visible in the code posted so far, but I'd imagine that you omitted it for brevity).
If the button is placed in <h:form>, then this will be searched as direct child of the <h:form>. However as this is apparently been placed inside the composite (which is, as said, another NamingContainer component), it wouldn't be found and hence basically nothing would be processed. You'd need to fix the process to point to the right client ID. E.g.
<h:form>
<mylib:mycomponent id="mycomponent" />
<p:commandButton ... process="#this mycomponent:mandatsTerritorial" />
</h:form>
This way it will process itself (mandatory to invoke the action!) and the component with id="mandatsTerritorial" inside the <cc:implementation> of the composite with id="mycomponent".
As a completely different alternative, which would work just fine in this particular construct, is to remove the process attribute altogether. It defaults to #form already which will thus process the entire form.
Update as per your question update: nesting forms is invalid in HTML. Using the JSF <h:form> representation doesn't change that; you'd still end up with nested forms in HTML. The browser behaviour is unspecified as to which data would be submitted to the server. Make sure that you don't nest <h:form> in JSF as well.

Resources