I have Primefaces TabView with two Tab like:
<p:tabView dynamic="true" cache="false"
onTabShow="scrollBottom(#{stanzaBean.activeIndex})"
tabChangeListener="#{messaggioBean.onTabChange}"
activeIndex="#{stanzaBean.activeIndex}" >
it works fine, except that when I change the Tab the activeIndex isn't updated on the Server and it returns always the default value.
I'm using primefaces 2.2.1.
Thank you.
Going by the PrimeFaces ShowCase example, if you give each tab an id:
<p:tabView tabChangeListener="#{indexBean.onTabChange}" >
<p:tab title="tab 0" id="tab0"></p:tab>
<p:tab title="tab 1" id="tab1" ></p:tab>
<p:tab title="tab 2" id="tab2"></p:tab>
</p:tabView>
you can get that tab id in the tabChangeListener.
public void onTabChange(TabChangeEvent event) {
System.out.println("tab id = " + event.getTab().getId());
}
Then you'll know which tab was selected.
Edit:
There is an open PrimeFaces issue 1640 TabView: Wrong activeIndex in TabChangeListener, always 0 on the problem you are having.
Edit 2:
With PrimeFaces 5.0 and up the tabChangeListener is no longer available on the tabView element but should be used via an explicit ajax tag with a tabChange event.
<p:tabView id="analysisSections" value="#{analysisBean.analysis.sections}" var="section" activeIndex="#{analysisBean.activeIndex}">
<p:ajax event="tabChange" listener="#{analysisBean.onTabChange}"/>
Also you can directly get index of tab:
public void onTabChange(TabChangeEvent event) {
activeIndex = ((TabView) event.getSource()).getIndex();
}
with all these changes, activeIndex works properly.
this worked for me:
public void onTabChange(TabChangeEvent event) {
Tab activeTab = event.getTab();
tabPanelIndex = ((TabView)event.getSource()).getChildren().indexOf(activeTab);
}
Although the question was related to PrimeFaces 2.2.1, I like to mention that in modern PrimeFaces versions (tested with version 6.2) there is no need to trigger a separate event when attribute dynamic is set to true and cache is set to false. By using this attribute combination the active index is automatically updated on the server when another tab is selected.
Facelet:
<p:tabView activeIndex="#{stanzaBean.activeIndex}"
cache="false"
dynamic="true">
Bean:
#Named
#ViewScoped
public class StanzaBean implements Serializable {
private int activeIndex;
public int getActiveIndex() {
return activeIndex;
}
/**
* Automatically called whenever a tab changes and dynamic="true"
* and cache="false".
*/
public void setActiveIndex(int activeIndex) {
this.activeIndex = activeIndex;
// do other stuff when tab changes
}
}
Related
This question already has answers here:
How to dynamically add and remove a tab in p:tabView component
(2 answers)
Closed 7 years ago.
I am programmatically add a new tab whenever a menu item is clicked. I have googled for all the questions on dynamic Tab creation and found a lot of unanswered queries. So my question is, is it possible to create tabs dynamically? Below is the code I am working on for the past week and not a tab in sight..
I am using Primefaces 5.0, JSF 2.2 Mojarra
Dynamic menu -
DefaultMenuItem windowItem = new DefaultMenuItem(node);
windowItem.setCommand("#{windowContainer.add}");
windowItem.setImmediate(true);
WindowContainer Backing Bean
#ManagedBean
#ViewScoped
public class WindowContainer implements Serializable {
private List<Window> windows;
#PostConstruct
public void init() {
windows = new ArrayList<Window>();
windows.add(new Window("window"+windows.size(),"first tab"));
}
public void add() {
windows.add(new Window("window" + windows.size(), "some content"));
RequestContext req = RequestContext.getCurrentInstance();
req.update("WindowContainer");
}
public void remove(Window window) {
windows.remove(window);
}
public List<Window> getWindows() {
return windows;
}
public void setWindows(ArrayList<Window> windows) {
this.windows = windows;
}
Windows is simple tab with only outputtext .
The View
<p:tabView id= "WindowContainer" value="#{windowContainer.windows}" var="window">
<p:tab title="#{window.title}">
<p>#{tab.content}</p>
<p:commandButton value="Close" action="#{windowContainer.remove(window)}" />
</p:tab>
</p:tabView>
<p:menu>
<p:submenu label="Ajax">
<p:menuitem value="Add Tab" actionListener="#{menuView.addTab}" update="WindowContainer" />
</p:menu>
Try like this update="WindowContainer" .Inside quotes give tabview id.
I am using an accordion panel with three tabs.
Each tab has required fields and <p:ajax> tags for accordionPanel:
<p:ajax event="tabChange" update=":contentForm:growl"/>
<p:ajax event="tabClose" update=":contentForm:growl"/>
By default all tabs are closed. When I click to open any tab, it performs vaidation of all inputs in all tabs.
How do I skip field validation and do ajax query during open/close tab?
(I need an Ajax query to save opened tabs indexes to Bean: activeIndex="#{tabBean.activeTabs}")
I have resolved this problem. I have created saver-class:
import javax.faces.event.AjaxBehaviorEvent;
import org.primefaces.component.accordionpanel.AccordionPanel;
public class ActiveIndexSaver {
private String activeTabs = "-1,0";
public String getActiveTabs() {
return activeTabs;
}
public void setActiveTabs(String activeTabs) {
this.activeTabs = activeTabs;
}
public void saveIndexes(AjaxBehaviorEvent abe){
AccordionPanel accordion = (AccordionPanel)abe.getComponent();
activeTabs = accordion.getActiveIndex();
}
}
After that I wrote Inject of the bean above to page-bean and getter for him:
#Inject
private ActiveIndexSaver activeIndexSaver;
....
public ActiveIndexSaver getActiveIndexSaver() {
return activeIndexSaver;
}
And finally, html:
<p:accordionPanel ... activeIndex="#{tabBean.activeIndexSaver.activeTabs}">
<p:ajax event="tabChange" immediate="true" listener="#{tabBean.activeIndexSaver.saveIndexes}"/>
<p:ajax event="tabClose" immediate="true" listener="#{tabBean.activeIndexSaver.saveIndexes}"/>
......
Versions:
NetBeans: 7.2.1
PrimeFaces: 3.5.3
GlassFish: 3.1.2
JDK 1.6
I've been trying to find related issues and have found topics that are close, but not quite what I'm looking for. I'm trying to do something similar to the p:schedule demo from PrimeFaces ShowCase where I want a dialog to appear showing the details of the event clicked.
I think the issue is coming from calling the listener method from the backing bean. When I go to type in the listener method in the p:ajax tag, NetBeans forces me to pass in a parameter like:
listener="#{cmodel.onEventSelect(e)}"
which I don't think is necessary as I don't have a value to pass in anyways.
I'm thinking either:
Something is up with NetBeans that doesn't recognize the method as a listener. (Since i keep seeing multiple examples of people calling the method without needing to pass a parameter.)
or
I'm not registering the method as a listener properly in the Model.
Also, I have directly copied and pasted the demo from the ShowCase into a project and it didn't work which is making me lean more towards an issue with NetBeans. (that is, the dialog appears but with no information on the event that was selected)
So to summarize; events are showing up as they should on the schedule itself, I just cant get the dialog to show the event details of the event that was selected.
Any help would be greatly appreciated!
View Layer:
<h:form>
<p:schedule id="nelsonsSchedule" value="#{cmodel.scheduleModel}" showHeader="true"
leftHeaderTemplate="none" rightHeaderTemplate="prev, next today"
draggable="false" timeZone="UTC" styleClass="schedule">
<p:ajax event="eventSelect" listener="#{cmodel.onEventSelect}"
update="eventDialog eventDetails" oncomplete="eventDialog.show()"/>
</p:schedule>
<p:dialog id="eventDialog" widgetVar="eventDialog" header="EventDetails">
<p:panel id="eventDetails">
<h:outputLabel value="#{cmodel.selectedEvent.title}" />
</p:panel>
</p:dialog>
</h:form>
Backing Bean:
#ManagedBean(name = "cmodel")
#SessionScoped
public class CalendarModel implements Serializable {
private ScheduleModel scheduleModel;
private List<ScheduleEvent> allScheduledGames;
private DefaultScheduleEvent gameEvent;
public ScheduleEvent selectedEvent;
List<Game> allGames;
#PersistenceContext
private EntityManager em;
public CalendarModel() {
}
#PostConstruct
public void init() {
allScheduledGames = new ArrayList<ScheduleEvent>();
allGames = new ArrayList<Game>();
allGames = em.createNamedQuery("Game.findAll").getResultList();
/*create list of games to put into the ScheduleModel*/
for (int i = 0; i < allGames.size(); i++) {
gameEvent = new DefaultScheduleEvent(allGames.get(i).getOpponent() +
"\n\n\n" + allGames.get(i).getTimeOfGame(),
allGames.get(i).getDateOfGame(),
allGames.get(i).getDateOfGame());
if(allGames.get(i).getHomeAway().equals("away")){
gameEvent.setStyleClass("away");
} else{
gameEvent.setStyleClass("home");
}
gameEvent.setData(allGames.get(i));
allScheduledGames.add(gameEvent);
}/*end for*/
scheduleModel = new DefaultScheduleModel(allScheduledGames);
}/*end init()*/
public void onEventSelect (SelectEvent e) {
selectedEvent = new DefaultScheduleEvent();
selectedEvent = (ScheduleEvent) e.getObject();
}
In case anyone runs into the same issue - It was NetBeans. I upgraded to 7.3 and don't have the problem anymore. Although another has come up where itellisense doesn't recognize a hashmap from the backing bean, but that's for another question.
I'm using JSF 2.0 and Richfaces 3.3.2.
I'm having an issue on one of my pages.
First of all I have a main page which contains a rich:tabPanel with several rich:tabs, no problem there switching between them.
On the first tab of my page I have another tabPanel with some other tabs.
They all have an actionListener which will call the ViewScoped ManagedBean to edit some Data, which will be displayed on the clicked tab. The method to edit the data calls a method on an ApplicationScoped Bean which is correctly injected (It works in other tabs). When switching a tab on the second layer and the action-method is called, the ApplicationScoped Bean is null.
This only happens when I switch tabs (so it does not happen on the first tab, which is displayed by default) so I think it's related to the actionListener, but i can't figure out why. Unfortunately I can't provide the actual code but this is the rough structure of my page.
mainPage.xhtml
...
<rich:tabPanel>
<rich:tab>
<ui:include src="tabs/tab1.xhtml" />
</rich:tab>
otherTabs
</rich:tabPanel>
...
tab1.xhtml
...
<rich:tabPanel>
<rich:tab actionListener="#{viewScopedBean.method}">
<ui:include src="subtabs/subtab1.xhtml" />
</rich:tab>
<rich:tab actionListener="#{viewScopedBean.method2}">
<ui:include src="subtabs/subtab2.xhtml" />
</rich:tab>
</rich:tabPanel>
ViewScopedBean.java
#ManagedBean
#ViewScoped
public class ViewScopedBean {
#ManagedProperty(value="#{applicationBean}")
private ApplicationBean applicationBean;
private Data data;
public void init() {
...
data = applicationBean.retrieveData();
...
}
public void method(ActionEvent e) {
...
data = applicationBean.retrieveData();
...
}
public void method2(ActionEvent e) {
...
data = applicationBean.retrieveData();
...
}
// getters/setters
}
ApplicationBean.java
#ManagedBean
#ApplicationScoped
public class applicationBean {
public Data retrieveData() {
...
}
}
When clicking subtab2 I get a NullPointerException at the line data = applicationBean.getData(), so the applicationBean is null. This happens everytime on every tab I'm switching to, but never in the init() method, so the applicationBean should not be null.
I could not find any solution or hints on this problem and hope someone has an idea.
Thanks in advance
regards
I'm using t:dataScroller to scroll some data from a t:dataTable and it is working fine except for one thing: every time an action that causes the screen to be refreshed is triggered the t:dataScroller's index is set to 1.
To be more clear: when i'm in the second page (index == 2) and a screen refreshing action triggers, after the refresh, the data of the dataTable is still from index 2 but the dataScroller shows that the page being displayed is the first one.
I'm using the dataScroller this way:
<t:dataScroller for="myDataTable" id="myDataScroller" paginator="true"
paginatorMaxPages="#{myBean.paginatorMxPgs}"
pageCountVar="pgCount" pageIndexVar="#{myBean.curPg}"
actionListener="#{myBean.pgListener}">
<f:facet name="prv">
<h:panelGroup rendered="#{myBean.curPg > 1}" />
</f:facet>
<f:facet name="nxt">
<h:panelGroup rendered="#{myBean.curPg != pgCount}"/>
</f:facet>
</t:dataScroller>
i'm using tomahawk20-1.1.11.jar and myfaces-api-2.0.4.jar
For setting scroller to firstpage set actionlistener on submit button.
<t:commandButton actionListener="#{IFussBean.resetDataScroller}"
action="#{IFussBean.searchLocation}"
image="images/submit-button.png">
</t:commandButton>
Binding:
if it is datatable
<t:dataTable id="data"
headerClass=""
footerClass=""
rowClasses="text_holder"
columnClasses="search_img,search_txt"
var="item"
value="#{IFussBean.searchVideoList}"
preserveDataModel="false"
rows= "6"
binding="#{IFussBean.iFussData}"
>
Declare HtmlDataTable in your Bean,define its setter getter as below:
private HtmlDataTable iFussData;
Getter and setter
public HtmlDataTable getiFussData() {
return iFussData;
}
public void setiFussData(HtmlDataTable iFussData) {
this.iFussData = iFussData;
}
Now define ActionListener Method in Bean:
public void resetDataScroller(ActionEvent e) {
if(iFussData!= null) {
iFussData.setFirst(0);
}
}
Your page will set to first page when you'll do new search.
/**********************************************************************************************************************************/
if you are using <rich:dataGrid> and your scroller is <t:dataScroller> then
<rich:dataGrid
id="data"
var="item"
columns="3"
elements="6"
width="600px"
value="#{IFussBean.searchVideoList}"
binding="#{IFussBean.iFussDataGrid}"
>
Declare HtmlDataGrid in Bean:
private HtmlDataGrid iFussDataGrid;
Its getter and setter
public HtmlDataGrid getiFussDataGrid() {
return iFussDataGrid;
}
public void setiFussDataGrid(HtmlDataGrid iFussDataGrid) {
this.iFussDataGrid = iFussDataGrid;
}
Now define its action listener in Bean which will invoke on pressing command button for search :
public void resetDataScroller(ActionEvent e) {
if(iFussDataGrid != null) {
iFussDataGrid.setFirst(0);
}
}
Invoke ActionListener on command button
<h:commandButton styleClass="submit-button" actionListener="#{IFussBean.resetDataScroller}" action="#{IFussBean.searchLocation}" image="images/submit-button.png"/>
It also give desire result.