9 Replies Latest reply on May 7, 2009 7:50 PM by atulkc

    Closing inactive tabs in rich tabPanel by user action

    atulkc

      Hi All,

      In our application we have a tabPanel with multiple tabs. All the tabs but one can be closed by clicking on 'x' in the tab header. Below given is the code snippet:

      <rich:tabPanel id="tabs" selectedTab="#{viewManager.selectedTab}" switchType="ajax" >
      <!-- First tab that cannot be closed -->
      <rich:tab name="one" rendered="true">
       <f:facet name="label">
       <h:panelGrid columns="1" cellpadding="2" columnClasses="rich-tab-header">
       <h:outputText value="One" />
       </h:panelGrid>
       </f:facet>
      <h:outputText value="Contents of First tab"/>
      </rich:tab>
      
      <!-- Secont tab that can be closed -->
      <rich:tab name="Two" rendered="#{viewManager.secondTabRendered}">
      <f:facet name="label">
       <h:panelGrid columns="2" cellpadding="2" columnClasses="rich-tab-header">
       <h:outputText value="Two" />
       <a4j:commandButton value="x" reRender="tabs" action="#{viewManager.secondTabRendered('0')}">
      
       </a4j:commandButton>
       </h:panelGrid>
       </f:facet>
      <h:outputText value="Contents of second tab"/>
      </rich:tab>
      ...
      ...
      ...
      <!-- multiple such tabs that can be closed -->
      </rich:tabPanel>
      


      "viewManager" is a session scoped backing bean that has appropriate getter/setter methods to achieve hiding/rendering of different tabs.

      The intention here that when user clicks 'x' in the tab header then the tab should be closed and user returns to the first tab. Well, this is perfectly achieved using this code when the tab is active. When the tab is active clicking on 'x' actually closes the active tab and returns the user to first tab.

      Our intention is also to allow user to close the tabs even if the tab is inactive, meaning when the second tab is inactive (user is currently in first tab) then user should be able to click on 'x' of second tab header and close that tab without ever having to go to that tab (similar to firefox tab behavior). However, with the above code we are not able to achieve that. Clicking on 'x' of the inactive tab is resulting in making the inactive tab active. So clicking on 'x' of second tab actually takes user to second tab in place of closing it. Is there a way by which we can make rich faces not interpret this action as tab change but tab close?

      Any pointers/help is appreciated.

      Regards,
      Atul

        • 1. Re: Closing inactive tabs in rich tabPanel by user action
          ilya_shaikovsky

          there two problems. That tab gets switched if you clicking the button. And it could be resolved by using Event(stop); in the button onclick.

          But the second problem.. content of the inactive tabs not decoded (including header).. so the action will not be called implemented as you pasted.

          All you need to perform in general to implement you case is.. include the link to every header and define onclick="deleteFunc(tabName);". Then define jsFunction with name deleteFunc outside the tabPanel and add the param which will puts the tabName to request map. And define listener on jsFunction which will delete the panel. B.t.w. using this approach do not forget to reRender tabPanel, because if you delete current tab - new tab should be fetched.

          • 2. Re: Closing inactive tabs in rich tabPanel by user action
            atulkc

            Ah...wonderful. By making above two changes it works like a charm. Thanks Ilya.

            --Atul

            • 3. Re: Closing inactive tabs in rich tabPanel by user action
              atulkc

              After I made this change I realized that tab panel has started behaving strangely. When I try switching between tabs I get following message in log and no tabs are rendered on the client:

              14:18:08,566 INFO [ContainerBase] j_id24:tabs: tab panel has no enabled or rendered tabs!


              This problem is consistently reproducible. If you try switching/closing the tab for more than 4-5 times you will run in to this issue. Below given is the code snippet:
              <h:form>
              <a4j:jsFunction name="closeTabTwo" action="#{tabTwoBackingBean.clear}" reRender="tabs">
               <a4j:actionparam name="param1" value="Two" assignTo="#{viewManager.closeTab}" />
              </a4j:jsFunction>
              
              <!-- multiple a4j Js functions, one for each tab as the action to clean up for each tab is different -->
              
              
              <rich:tabPanel id="tabs" selectedTab="#{viewManager.selectedTab}" switchType="ajax" >
              <!-- First tab that cannot be closed -->
              <rich:tab name="one" rendered="true">
               <f:facet name="label">
               <h:panelGrid columns="1" cellpadding="2" columnClasses="rich-tab-header">
               <h:outputText value="One" />
               </h:panelGrid>
               </f:facet>
              <h:outputText value="Contents of First tab"/>
              </rich:tab>
              
              <!-- Secont tab that can be closed -->
              <rich:tab name="Two" rendered="#{viewManager.secondTabRendered}">
              <f:facet name="label">
               <h:panelGrid columns="2" cellpadding="2" columnClasses="rich-tab-header">
               <h:outputText value="Two" />
               <a4j:commandButton value="x" onclick="Event.stop(event); closeTabTwo('Two');">
               </a4j:commandButton>
               </h:panelGrid>
               </f:facet>
               <h:outputText value="Contents of second tab"/>
              </rich:tab>
              ...
              ...
              ...
              <!-- multiple such tabs that can be closed -->
              </rich:tabPanel>
              </h:form>
              


              viewManager is session scoped bean that has 'setCloseTab' method that takes a String argument. Based on the name of the tab viewManager sets the flag to render/un-render the respective tab.

              Is there something wrong that I am doing here?

              Regards,
              Atul

              • 4. Re: Closing inactive tabs in rich tabPanel by user action
                atulkc

                Please note that tab one is hard coded to be rendered always, so there is no reason why tabpanel should complain that there are no enabled or rendered tabs.

                Also, another strange behavior that I have noticed is that the contents of tab one disappear partially, meaning if there are 4 data tables in tab one some times only 2 appear and other 2 disappear. If I refresh the page by clicking browser refresh then all the contents are displayed. After refresh even the tabs that disappear come back.

                --Atul

                • 5. Re: Closing inactive tabs in rich tabPanel by user action
                  ilya_shaikovsky

                  please checkout latest snapshot of the richfaces-demo. I've included sample for tabs deletion.. feel free to review it.

                  • 6. Re: Closing inactive tabs in rich tabPanel by user action
                    atulkc

                    I am sorry, I don't see the sample for tabs deletion in online richfaces demo. Am I looking at the wrong URL?

                    http://livedemo.exadel.com/richfaces-demo/richfaces/tabPanel.jsf?tab=usage&cid=4965546

                    This is very important for our project, it would be really helpful if I could get any leads on this problem.

                    Thanks,
                    Atul

                    • 7. Re: Closing inactive tabs in rich tabPanel by user action
                      nbelaevski

                      It's not online yet, you can get 3.3.1-snapshot WAR file from here: http://snapshots.jboss.org/maven2/org/richfaces/samples/richfaces-demo/3.3.1-SNAPSHOT/

                      • 8. Re: Closing inactive tabs in rich tabPanel by user action
                        atulkc

                        Thanks, I downloaded the war file and checked the tab deletion implementation. It is mostly similar to what I have done with following two differences:
                        1) I do not have 'actionListener' for the a4j:jsFunction but in stead have an action.
                        2) In place of using f:param I am using a4j:actionparam.

                        I need this because while closing tab is one aspect I also need to clean up resources held by the backing bean supporting that tab, hence two actions: action of a4j:jsFunction and a4j:actionparam.

                        I don't think these changes would cause the problem I am noticing. Do you think having two actions can cause this problem?

                        --Atul

                        • 9. Re: Closing inactive tabs in rich tabPanel by user action
                          atulkc

                          Finally I was able to figure out (using my custom PhaseListener) what was going wrong. I was using a4j:commandButton in the tab header to close the tab. On a4j:commandButton's onclick I was calling a4j:jsFunction to send request to my backing bean. However, what used to happen was while a4j:jsFunction request was being processed on server another request (from a4j:commandButton's action) landed up on server and before the first request's lifecycle was over the second was being processed. This used to cause some unexpected behavior (concurrency issues in JSF lifecycle?). The funny part is, I did not have any action on a4j:commandButton (then why did it result in a request remains a mystery to me).

                          Anyways, changing from a4j:commandButton to h:graphicImage did the trick for me.

                          Thanks,
                          Atul