I'm migrating app from Primefaces 3.5 to last version, actually 6.2. I have a problem with events on close and on change tabs. I have dynamically created tabs.
On TabChangeEvent tabClientId is different than in UIComponent, but it still works and I can change correctly between tabs. Real problem is when I close tab, then in contextEvent I have tabClientId = [object Object] and tabIndex is null so app explodes here:
int tabindex = Integer.parseInt(params.get(clientId + "_tabindex"));
Someone knows how to fix this?
<p:tabView var="tabview" value="#{tabBean.tabs}"
binding="#{tabBean.tabGlTabView}" id="panelGl"
widgetVar="panelGlJs" dynamic="true" styleClass="contentPanel"
activeIndex="#{tabBean.index}">
<p:tab title="#{tab.title}"
closable="true">
<ui:include src="#{tabBean.tab}" />
</p:tab>
<p:ajax event="tabChange"
onstart="setActive()"
update="#(this)" />
<p:ajax event="tabClose"
listener="#{tabBean.onTabClose}" />
</p:tabView>
Related
I want to close all panels and update a dynamic PrimeFaces 8 p:accordionPanel. I try to close all panels in the p:ajax onstart using the widget var. That does close them, but after the update they are opened again. Without dynamic="true" it does work (even without the onstart). Is this easily fixable in the XHTML, or am I looking at a bug here?
<h:form id="main">
<p:dataTable value="#{appointments.lazy}"
lazy="true"
var="appo"
rowKey="#{appo.id}"
selectionMode="single"
selection="#{appointments.selected}"
rows="10">
<p:column headerText="#{msg.date}">#{appo.startTime}</p:column>
<p:ajax event="rowSelect"
onstart="var a=PF('acc');for(i=0;i<a.panels.length;i++){a.unselect(i)}"
update="main:acc"/>
</p:dataTable>
<p:accordionPanel id="acc"
widgetVar="acc"
dynamic="true"
multiple="true"
activeIndex="">
<p:tab title="#{now}">#{now}</p:tab>
<p:tab title="#{now}">#{now}</p:tab>
</p:accordionPanel>
</h:form>
I ended up using a listener on my p:ajax to reset the active indexes:
public void resetActivePanels() {
org.omnifaces.util.Components
.findComponentsInCurrentForm(AccordionPanel.class)
.get(0)
.setActiveIndex("");
}
This also eliminates the need to close each panel first on start:
<p:ajax event="rowSelect"
listener="#{appointments.resetActivePanels()}"
update="main:acc"/>
I want to know how to do show a panelgroup if is selected specific tab of accordionPanel Primefaces.
<p:accordionPanel id="myAccordion" activeIndex="1">
<p:tab title="first" id="tab0">
...
</p:tab>
<p:tab title="second" id="tab2">
...
</p:tab>
</p:accordionPanel>
<h:panelGroup id="myPanelGroup" rendered="#{myAccordion.activeIndex=='0'}">
...
</h:panelGroup>
Thank you.
H
Just check prime face showcase they have ajax event for your reference
<p:ajax event="tabChange" listener="#{tabbedView.onTabChange}" update=":form:msgs" />
<p:ajax event="tabClose" listener="#{tabbedView.onTabClose}" update=":form:msgs" />
Once you get your tab index you can do whatever you want to do and update your panel according your need.
https://www.primefaces.org/showcase/ui/panel/accordionPanel.xhtml
The problem is really simple. I have a tabview with multiple tabs:
<h:form>
<p:tabView id="tabView">
<p:tab>
<p:inputText required="true"></p:inputText>
</p:tab>
<p:tab>
<p:inputText required="true"></p:inputText>
</p:tab>
</p:tabView>
<p:commandButton value="submit" action="#{myBB.submit}" update="tabView"/>
</h:form>
What I would like is to switch to the tab with missing field when the client-side validation fails. I thought that this must be a common use-case for form in tabs, but I cannot find any solution.
The only thing I can think of is call some oncomplete action on the submit button which would go through the DOM and find the invalid components, but it seems overly complicated for a thing which I believe should be default behavior.
So I've found a way to do that. After the ajax completes, I created an oncomplete method to search through the tabs and select the correct one.
First I had to modify the source a bit(just added ids and widgetVar):
<h:form>
<p:tabView id="tabView" widgetVar="tabViewWv">
<p:tab id="tab1">
<p:inputText required="true"></p:inputText>
</p:tab>
<p:tab id="tab2">
<p:inputText required="true"></p:inputText>
</p:tab>
</p:tabView>
<p:commandButton ... oncomplete="switchToInvalidTab()"/>
</h:form>
and the javascript:
function switchToInvalidTab() {
var lastIndex = 0;
var tabParent = '#mainForm\\:tabView\\:';
var tabs = ['tab1', 'tab2']; //can add more, but the order must be the same as in form
tabs.some(function (tabName){
if ($(tabParent + tabName)) { //tab may not exist in my app
if ($(tabParent + tabName).find(':input').hasClass('ui-state-error')){
PF('tabViewWv').select(lastIndex);
return true;
}
lastIndex++;
}
return false;
});
}
There are more tabs in my app and some of them doesn exist sometimes and this code works for all cases. Maybe it helps someone
I am trying to do a Primefaces On-Demand Loading tabbed panel component which has a inputTextArea component inside it. I follow this tutorial Primefaces Tutorial.
My .xhtml form looks like this:
<h:form>
<h:outputText
value="Write a comment" />
<p:tabView dynamic="true" cache="true">
<p:tab title="Possitive">
<h:panelGrid columns="2" cellpadding="10">
<p:inputTextarea rows="5" cols="130" />
</h:panelGrid>
</p:tab>
<p:tab title="Negative">
<h:panelGrid columns="2" cellpadding="10">
<p:inputTextarea rows="5" cols="130" />
</h:panelGrid>
</p:tab>
</p:tabView>
<p:commandButton value="Publish"></p:commandButton>
</h:form>
But these inputTextBox are always loaded, nevertheless i did not click on them. Can they be loaded only on demand and how to do this?
Thanks in advance for the help!
Primefaces builds JSF tree for all tabs. Both inputTextarea(s) are created on server side. It can be solved by ui:include. Put the content of p:tab into extra file and use ui:include to fetch the content:
<p:tabView>
<p:tab title="Possitive">
<ui:include src="#{tabViewBean.getTabSource('tabPositive')}"/>
</p:tab>
<p:tab title="Negative">
<ui:include src="#{tabViewBean.getTabSource('tabNegative')}"/>
</p:tab>
</p:tabView>
TabViewBean holds active tab name and is used for resolving tab sources as well. If a tab is NOT ACTIVE then the method tabViewBean.getTabSource() returns another file with EMPTY content:
public String getTabSource(String tabName)
{
return tabName.equals(activeTabName) ?
getTabSourceForTabName(tabName) :
"EmptyTab.xhtml";
}
public String getTabSourceForTabName(String tabName)
{
if ("tabPositive".equals(tabName)) return "TabPositive.xhtml";
if ("tabNegative".equals(tabName)) return "TabNegative.xhtml";
}
You should have EmptyTab.xhtml somewhere. Set listener in p:tabView to listen the tab change event :
<p:tabView listener="#{tabViewBean.tabChangeListener}">
tabChange listener sets the name of active tab:
public void tabChangeListener(UIComponentBase tabView)
{
activeTabName = getTabNameByIndex(tabView.getActiveIndex());
}
public String getTabNameByIndex(int index)
{
if (i==0) return "tabPositive";
if (i==1) return "tabNegative";
}
Inside one tab, I can cilck on a button to display an "h:groupPanel". If I do this, and then change the active tab, the groupPanel that has just appeared is still visible, and appears on top of the now current tab.
The code for the tabView is:
<p:tabView dynamic="true" cache="false" id="characterTabView">
<p:tab title="View" id="viewTab">
<ui:include src="/sections/character/view.xhtml" />
</p:tab>
<p:tab title="Upgrade" id="upgradeTab">
<ui:include src="/sections/character/upgrade.xhtml" />
</p:tab>
</p:tabView>
The "upgrade" page looks like
<h:panelGroup id="searchCompetencies" rendered="#{characterBean.rightPanel == 'searchResult'}">
<h:panelGroup styleClass="characterUpgradeLeft">
<ui:include src="/sections/character/searchViewLeft.xhtml" />
</h:panelGroup>
<h:panelGroup id="competencyCreation" rendered="#{characterBean.rightPanel == 'competencyCreation'}">
<!-- The panel that is made visible -->
</h:panelGroup>
And the page in which the component is made visible (searchViewLeft):
<p:fieldset legend="Create competency" styleClass="createCompetencyStart">
<h:form>
<p:commandButton value="Create competency" type="button" onclick="toggleCreate()" update="upgradeTab" />
</h:form>
</p:fieldset>
where "toggleCreate" changes the value of "characterBean.rightPanel".
Would you have any idea as to what I am missing here?
Thanks a lot :)