I am creating a JSF application with primefaces. Basically I have this view. There is a tab view which for each tab contains a command button and a accordion panel (another kind of tab view). The tabs of the accordion panel among other elements, contain each one command button. My problem is that the first command button (under 1 level of tabs) calls correctly the action method when it is clicked, while the second button (under 2 level of tabs) does not. I should say that both the tabView and accordionPanel are working correctly, since they are displaying the information they should display.
I am posting a simplified version of my view so that you can see what is happening.
<h:form>
<p:tabView id="unitTabs" orientation="left" dynamic="true" cache="false" var="unit" value="#{unitController.getUnitsOfLoggedInUser(loginController.checkedUser)}">
<p:tab id="unitTab" title="#{unit.unitName}">
<p:commandButton value="Add Lecture" action="#{unitController.setTemporary(unit)}" onclick="createLectureDialog.show()">
<p:accordionPanel id="lectureTabs" value ="#{lectureController.getLecturesForUnit(unit)}" var="lecture" dynamic="true" cache="false">
<p:tab title="#{lecture.lectureName}">
<p:commandButton value="Add Criterion" action ="#{lectureController.setTemporary(lecture)}" onclick="createCriterionDialog.show()" >
</p:tab>
</p:accordionPanel>
</p:tab>
</p:tabView>
</h:form>
What am i doing wrong? Thanks
This construct requires that the EL expression in the value attribute of the <p:tabView> and <p:accordionPanel> returns exactly the same value during processing the form submit as it was during the initial display.
If the bean is request scoped and/or the value depends behind the scenes on a request based parameter or variable and it thus returns a different value on every request, then it will fail because JSF cannot locate the button which was been invoked. To fix it, the bean needs to be placed in the view scope and the getter method should not contain any business logic, or any request based parameters or variables should be retained in the subsequent requests.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4.
Related
I try to build a form where a user can enter data step by step. After trying a FlowScoped solution I now try to implement the Primefaces wizard.
Description:
My main.xhtml:
<h:form id="antragErfassenForm">
<p:wizard showStepStatus="false" widgetVar="wiz" showNavBar="false" >
<p:tab id="basic_decision_tab" title="Grundsatzentscheidungen">
<ui:include src="/eAkte/basic_decisions.xhtml" />
</p:tab>
<p:tab id="driving_ways_tab" title="Fahrtwegvarianten">
<ui:include src="/eAkte/driving_ways.xhtml" />
</p:tab>
</p:wizard>
</h:form>
Inside the include files I have buttons to navigate between the tabs.
The next button in the first tab 'basic_decisions.xhtml':
<p:commandLink value="Next" onclick="#{eAkteController.callDrivingWays()}; PF('wiz').next();" />
Depending on the result from callDrivingWays() (which evaluates the data of the first tab) the second tab has a different content.
My problem:
The method callDrivingWays() isn't called when clicking the next button on the first tab. Instead it is already called when the first tab is loaded. That's why I always have an empty second page.
I tried switching the method call callDrivingWays() inside an actionListener inside the button or the flowListener of the Wizard. After that the method is called at the correct time, but when clicking on the next button I get an exception, that my component ID has already been used before.
Does anyone has any suggestions?
Try using the flowListener attribute of p:wizard
<p:wizard flowListener="#{yourBB.yourMethod}" nextLabel="Next" backLabel="Back" showNavBar="false" widgetVar="myWizard">
In your backing bean code instead you can implement the actionListener like this:
public String yourMethod(FlowEvent event) {
if(event.getOldStep().equals("driving_ways_tab")){}
if(event.getNewStep().equals("driving_ways_tab")){}
you need getOldStep and getNewStep to perform some changes according to the tab you are entering, exiting.
does anybody know how to use RequestScoped bean together with rendered attribute in jsf? The rendered attribute is evaluated before applyValues phase and therefore is not correctly evaluated. I don't want to preserve any state. The example could be an outputPanel with a datatable and a button. The datatable gets a list of values. The wrapping outputPanel has the rendered attribute like:
<p:outputPanel rendered="#{not empty requestScopedBean.dataList}">
<p:datatable value="#{requestScopedBean.dataList}">
...
</p:datatable>
<p:commandButton action="#{requestScopedBean.someAction}" />
</p:outputPanel>
After loading the page and clicking on the button, nothing happens, because the view is restored and expressions are evaluated - the bean does have an empty datalist and therefore the panel should not be rendered. This causes that the action method is not even called - because the button doesn't exist.
If you're not interested in having a filled data table at that moment, just add an extra check in rendered attribute if the command button of interest has been invoked. You can do that by checking the presence of button's client ID in request parameter map.
<p:outputPanel rendered="#{not empty requestScopedBean.dataList or not empty param[someButton.clientId]}">
...
<p:commandButton binding="#{someButton}" ... />
</p:outputPanel>
See also:
How to let validation depend on the pressed button?
does anybody know how to use RequestScoped bean together with rendered attribute in jsf? The rendered attribute is evaluated before applyValues phase and therefore is not correctly evaluated. I don't want to preserve any state. The example could be an outputPanel with a datatable and a button. The datatable gets a list of values. The wrapping outputPanel has the rendered attribute like:
<p:outputPanel rendered="#{not empty requestScopedBean.dataList}">
<p:datatable value="#{requestScopedBean.dataList}">
...
</p:datatable>
<p:commandButton action="#{requestScopedBean.someAction}" />
</p:outputPanel>
After loading the page and clicking on the button, nothing happens, because the view is restored and expressions are evaluated - the bean does have an empty datalist and therefore the panel should not be rendered. This causes that the action method is not even called - because the button doesn't exist.
If you're not interested in having a filled data table at that moment, just add an extra check in rendered attribute if the command button of interest has been invoked. You can do that by checking the presence of button's client ID in request parameter map.
<p:outputPanel rendered="#{not empty requestScopedBean.dataList or not empty param[someButton.clientId]}">
...
<p:commandButton binding="#{someButton}" ... />
</p:outputPanel>
See also:
How to let validation depend on the pressed button?
I currently have a giant ui:repeat. Within this ui:repeat, some of the repeated objects have a url to a popup image associated with them. When someone clicks display under that particular object, I need the url to popup in a p:dialog.
<ui:repeat var="thing" value="#{bean.thingList}">
<p:commandLink value="details" onclick="miniImage.show();"
update=":#{p:component('chart')}"
action="#{bean.setCurrentImg(thing.imageUrl)}"
rendered="#{thing.includeImage}">
</p:commandLink>
</ui:repeat>
and at the bottom of the page:
<p:dialog id="chart" widgetVar="miniImage" >
<h:graphicImage value="#{bean.currentImg}"/>
</p:dialog>
And in the backing bean I tried using a simple setter and getter for currentImg.
I am a bit confused on this now and would like to accomplish this without having to submit the entire form as well. Any help is greatly appreciated.
If you're using PrimeFaces 3.3 or newer, you could just add partialSubmit="true" to the command component. You can then control the to-be-processed components in process attribute. In this particular case, just the current component (the command component itself) is sufficient, thus so process="#this":
<p:commandLink ... process="#this" partialSubmit="true" />
This way only the request parameters which are really necessary for the process will be sent.
Unrelated to the concrete problem, I suggest to use oncomplete instead of onclick to open the dialog. Otherwise the dialog is opened before update takes place and may cause poor user experience as the enduser would see the image instantly changing.
I am using prime face version 3.4 , The problem is with the tab view display.
<p:messages id="messages"/>
<p:tabView id="tabView" dynamic="false">
<p:tab id="tab1" title="Navigation">
<p:tab id="tab2" title="Email Address">
<p:tab id="tab3" title="Password">
</p:tabView>
It's a Tabbed page with 3 Tabs(Notification , Email and Password) , If am on Email tab without entering any values i click submit , it displays the error message at the top and default to the first tab , I need to show the Email Tab
With ajax=false, the whole page gets refreshed after you click the button and tab view takes you to the first page just as if you were navigating to that page for the first time.
You could either set Ajax to true or use an integer on your bean as the selected index for the tabview (there's a property called selectedIndex on the tabview if memory doesn't fail me). The second option, however, would only work for view, session and application scoped beans.
Place the <p:messages id="messages"> tag inside the <p:tab id="tab2" title="Email Address"> tag. Note that it will display messages from any validated component inside the same form (or from any of your tabs). You should use <p:message for="componentId"> to show component-specific messages.