Access label of currently active tab?

  • 1
  • Question
  • Updated 4 years ago
Is there a way that I can access the label of the current tab and render it in a template? jQuery, perhaps?

I saw this thread, and Zach's answer:

var TABSET_ID = 'FruitTabs';
var TAB_ID = 'Bananas';
var $ = skuid.$;
var tabset = $('#'+TABSET_ID);
var tabPanels = tabset.children('.ui-tabs-panel');
var targetTabIndex = tabPanels.filter('#'+TAB_ID).index() - 1;
tabset.tabs('option','active',targetTabIndex);
So, could I use something like...

var $ = skuid.$;
var tabset = $('#MyTabsetID');


var currentlabel = tabset.tabs [ .... something here??]

OR var currentlabel = tabset.children.ui-tabs-panel ??
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb

Posted 4 years ago

  • 1
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Hi Matt -

The key to this is that you need to locate the <a> tag for the tab and get its innerHtml or text. The anchor tab is actually not inside of the panel itself but instead it's a child of a UL element that is a sibling to the panel but higher up in the DOM.  There are several ways to locate this but one would be:

// this can be written more efficiently but accomplishes the goal for this purpose
// see the code snippet on the sample page for a full version
 $('a[href="#' + tabId + '"]').text(); 

You could also use the aria-labelledby property value from the tab panel itself and then search the DOM for the the element who's ID matches that value.  This would be a more direct approach but does introduce a little risk if the jQuery UI stuff were to ever change.

I created a sample page (see below) which has a couple of scenarios addressed:

1) First Tab - On page load (document.ready) build a comma delimited list of all tabs within the tabset and set a template field to contain the delimited list.  Note that the template on the 1st tab has a fixed Unique Id of tabnames.

2) All Other Tabs - As each tab is clicked (tabshow), update template field on the tab with its label.  Each tab (except the first) contains a template field with a <span> element that has a class of ".tabname"  The tabshow event is hooked so that each tab is clicked, a generic block of code runs, finds the text for the current tab and updates the span with that text.

A few notes:

1) The sample contains two different "search" approaches - one using the tab id and one using the aria-labelledby attribute.  In each case, the code is not 100% tuned for optimization of DOM searching as it's intended to demonstrate where everything lives while accomplishing the goal of identifying the label text.
2) in this case, since tab labels don't support HTML it doesn't matter but as a general rule, you could use .html() instead of .text() to grab HTML instead of the inner text value of a DOM element.



Hope this helps.
<skuidpage unsavedchangeswarning="yes" tabtooverride="Account" showsidebar="true" showheader="true">
   <models>
      <model id="Account" limit="1" query="true" createrowifnonefound="false" sobject="Account">
         <fields>
            <field id="Name" />
            <field id="CreatedDate" />
         </fields>
         <conditions>
            <condition type="param" value="id" operator="=" field="Id" enclosevalueinquotes="true" />
         </conditions>
         <actions />
      </model>
   </models>
   <components>
      <tabset uniqueid="tabdemo" renderas="" defertabrendering="true" rememberlastusertab="false">
         <tabs>
            <tab name="Reinvent" uniqueid="tabReinvent">
               <components>
                  <template model="Account" multiple="false" allowhtml="true" cssclass="">
                     <contents>All Tabs: &lt;span id="tabnames"&gt;&lt;/span&gt;</contents>
                  </template>
               </components>
            </tab>
            <tab name="your" uniqueid="tabYour" loadlazypanels="true">
               <components>
                  <template model="Account" multiple="false" cssclass="">
                     <contents>Tab Name: &lt;span class="tabname"&gt;&lt;/span&gt;</contents>
                  </template>
               </components>
            </tab>
            <tab name="UI" uniqueid="tabUI" loadlazypanels="true">
               <components>
                  <template model="Account" multiple="false" cssclass="">
                     <contents>Tab Name: &lt;span class="tabname"&gt;&lt;/span&gt;</contents>
                  </template>
               </components>
            </tab>
            <tab name="With" uniqueid="tabWith" loadlazypanels="true">
               <components>
                  <template model="Account" multiple="false" cssclass="">
                     <contents>Tab Name: &lt;span class="tabname"&gt;&lt;/span&gt;</contents>
                  </template>
               </components>
            </tab>
            <tab name="Skuid" uniqueid="tabSkuid" loadlazypanels="true">
               <components>
                  <template model="Account" multiple="false" cssclass="">
                     <contents>Tab Name: &lt;span class="tabname"&gt;&lt;/span&gt;</contents>
                  </template>
               </components>
            </tab>
         </tabs>
      </tabset>
   </components>
   <resources>
      <labels />
      <css />
      <javascript>
         <jsitem name="tabListener" url="" cachelocation="false" location="inline">(function(skuid){
    // jquery shortcut
	var $ = skuid.$;
	
	// helper to locate the text by using tab Id
	var getTabById = function(tab) {
	    // get the id of the tab
	    var tabId = $(tab).attr('id');
	    
	    // this could be optimized but as it is written
	    // it will search up from the tab to find the tabset
	    // then down for the navigate &lt;ul&gt; element
	    // then look for the first &lt;a&gt; element that has an href
	    // property of the tab Id
        return $(tab).closest('.ui-tabs').children('.ui-tabs-nav').find('a[href="#' + tabId + '"]:first').text();
	};
	
	// helper to locate the text using aria-labelledby attribute
	var getTabByAriaLabelledBy = function(tab) {
	    // get the aria-labelledby attribute value which represents which element points to this element (this elements 'label')
        var tabId = $(tab).attr('aria-labelledby');
	  
	    // this could be optimized but as it is written
	    // it will search up from the tab to find the tabset
	    // then down for the navigate &lt;ul&gt; element
	    // then look for the element who's id is th tabId
        return $(tab).closest('.ui-tabs').children('.ui-tabs-nav').find('#' + tabId).text();
	};
	
	// helper to get the text of the anchor tag which is the label for the tab
	var getTabLabel = function(tab) {
	    // search using the tab's id
        return getTabById(tab);
        
        // search by looking for the tab's 'label'
        //return getTabByAriaLabelledBy(tab);
	};
	
	// document ready function
	$(function(){
	    // hook the tabshow event so that as user clicks on tab
	    // we update the template field with the label from the tab
        $('body').on('tabshow',function(event){
            var tabLabel = getTabLabel(event.target); // lookup the label text for the tab

            // update the text of the span with the name from the tab label
            $(event.target).find('span.tabname').text(tabLabel);
        });
        
        var tabSet = $('#tabdemo') // find the tabset
            , tabs = $(tabSet).children('.ui-tabs-panel') // find all the tabs for the tabeset
            , tabIds = ''; // helper variable that we'll use to build the list of tab labels

        // iterate the tabs
        $.each(tabs, function() {
            // build a comma delimited list of the tab labels
            tabIds += (tabIds ? ', ' : '') + getTabLabel($(this));
        });
        
        // update the span with the concatenated list
        $('#tabnames').text(tabIds);
	});
})(skuid);</jsitem>
      </javascript>
   </resources>
</skuidpage>
 
(Edited)
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Barry, you're the man.
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Thanks again, Barry!

My application requires one template field above the tabset to display the name of the tab. This way, I can eliminate tab names for a long tabset and just use icons, but the user can still see the label of the tab.

Here's the code I ended up with:
(function(skuid){	
var $ = skuid.$;
// helper to locate the text by using tab Id
var getTabById = function(tab) {
   // get the id of the tab
   var tabId = $(tab).attr('id');
   // return the label text
        return $(tab).closest('.ui-tabs').children('.ui-tabs-nav').find('a[href="#' + tabId + '"]:first').text();
};
// update the text of the span with the name from the tab label
var setTabName = function(target){
   var tabLabel = getTabById(target); // lookup the label text for the tab
        // update the text of the span with the name from the tab label
        $('span.tabname').text(tabLabel);
};
// document ready function
    $(function(){
   // hook the tabshow event so that as user clicks on tab
   // we update the template field with the label from the tab
        $('body').on('tabshow',function(event){
            return setTabName(event.target);
        });
        
        // get first tab name to set template on page load
        var tabSet = $('#tabdemo'), // find the tabset
            firstTab = $(tabSet).children('.ui-tabs-panel:first');
        return setTabName(firstTab);
});
})(skuid);

And the XML demo page, if anyone's interested:

<skuidpage unsavedchangeswarning="yes" tabtooverride="Account" showsidebar="true" showheader="true">
   <models>
      <model id="Account" limit="1" query="true" createrowifnonefound="false" sobject="Account">
         <fields>
            <field id="Name"/>
            <field id="CreatedDate"/>
         </fields>
         <conditions>
            <condition type="param" value="id" operator="=" field="Id" enclosevalueinquotes="true"/>
         </conditions>
         <actions/>
      </model>
   </models>
   <components>
<template model="Account" multiple="false" cssclass="" allowhtml="false">
                     <contents>&lt;h1&gt;&lt;span class="tabname"&gt;&lt;/span&gt;&lt;/h1&gt;</contents>
                  </template>
      <tabset uniqueid="tabdemo" renderas="" defertabrendering="true" rememberlastusertab="false">
         <tabs>
            <tab name="Reinvent" uniqueid="tabReinvent">
               <components>
                  
               </components>
            </tab>
            <tab name="your" uniqueid="tabYour" loadlazypanels="true">
               <components>
                  
               </components>
            </tab>
            <tab name="UI" uniqueid="tabUI" loadlazypanels="true">
               <components>
                  
               </components>
            </tab>
            <tab name="With" uniqueid="tabWith" loadlazypanels="true">
               <components>
                  
               </components>
            </tab>
            <tab name="Skuid" uniqueid="tabSkuid" loadlazypanels="true">
               <components>
                  
               </components>
            </tab>
         </tabs>
      </tabset>
   </components>
   <resources>
      <labels/>
      <css/>
      <javascript>
         <jsitem location="inline" name="tabNameDisplay" cachelocation="false" url="">(function(skuid){
var $ = skuid.$;
// helper to locate the text by using tab Id
var getTabById = function(tab) {
   // get the id of the tab
   var tabId = $(tab).attr('id');
   // return the label text
        return $(tab).closest('.ui-tabs').children('.ui-tabs-nav').find('a[href="#' + tabId + '"]:first').text();
};
// update the text of the span with the name from the tab label
var setTabName = function(target){
   var tabLabel = getTabById(target); // lookup the label text for the tab
        // update the text of the span with the name from the tab label
        $('span.tabname').text(tabLabel);
};
// document ready function
    $(function(){
   // hook the tabshow event so that as user clicks on tab
   // we update the template field with the label from the tab
        $('body').on('tabshow',function(event){
            return setTabName(event.target);
        });
        
        // get first tab name to set template on page load
        var tabSet = $('#tabdemo'), // find the tabset
            firstTab = $(tabSet).children('.ui-tabs-panel:first');
        return setTabName(firstTab);
});
})(skuid);</jsitem>
</javascript>
   </resources>
</skuidpage>
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Is there a better way to get the name of the first tab? I'm just making things up as I go, here... :)
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Hey Matt - Unfortunately there isn't a tabshow event fired for the first tab that is displayed.  The way you found the first tab (document ready & first) would be the best way to approach if you don't have the option "Remember user's last tab" enabled.  If you do have it enabled, the first tab isn't necessarily what is displayed on initial page load.

To make sure you get the correct tab in all cases, I'd suggest the following:
firstTab = $(tabSet).children('.ui-tabs-panel:visible');
(Edited)
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
So... I realized that if I'm not displaying the tab names, they're not in the html for jQuery to find. What's the best way to find a tab's unique ID?
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Hey Barry,

I'm not actually leaving the tab label empty. I'm doing this: https://community.skuidify.com/skuid/topics/toggle-tab-labels-on-off
So, the label on teach tab looks something like:

{{#$Model.ShowTabs.data.0.Chart_Tab_Names__c}}Case Summary{{/$Model.ShowTabs.data.0.Chart_Tab_Names__c}}

If the user has Chart_Tab_Names__c = true, the label shows up, otherwise, we just see the icon.

I'd like to be able to show the tab label above the tabset in a template either way.

I decided to go ahead and use the unique ID. I had to include a 'replace', because I wanted spaces in my display, but you can't have spaces in the unique id.

Here's my new code:

(function(skuid){	var $ = skuid.$;
// helper to locate the text by using tab Id
var getTabById = function(tab) {
   // get the id of the tab
   var tabId = $(tab).attr('id');
   return tabId.replace("_"," ");
};
// update the text of the span with the name from the tab label
var setTabName = function(tab){
   var tabLabel = getTabById(tab); // lookup the label text for the tab
        $('span.tabname').text(tabLabel);
};
// document ready function
    $(function(){
   // hook the tabshow event so that as user clicks on tab
   // we update the template field with the label from the tab
        $('body').on('tabshow',function(event){
            return setTabName(event.target);
        });
        
        // get first tab name to set template on page load
        var tabSet = $('#tabdemo'), // find the tabset
            firstTab = $(tabSet).children('.ui-tabs-panel:visible');
        return setTabName(firstTab);
});
})(skuid);
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Conditional labels, I like it!

One other approach you could take to avoid all the merge syntax and the replace is the following. 

1) Put your text in the Tab Label field as normal (no merge syntax)

2) On document ready, check your ShowTabs model for true/false and show/hide the labels

$(function(){    // hook the tabshow event so that as user clicks on tab
    // we update the template field with the label from the tab
    $('body').on('tabshow',function(event){
        return setTabName(event.target);
    });
    
    // show/hide labels
    var showTabsModel = skuid.model.getModel('ShowTabs')
        , showTabsRow = showTabsModel.getFirstRow()
        , showLabels = showTabsRow__Chart_Tab_Names__c;
    
    // get all the labels
    var tabLabels = $('#tabdemo').find('.ui-tabs-anchor').find('div.nx-template');
    
    if (showLabels) {
        tabLabels.show();
    } else {
        tabLabels.hide();
    }
    
    // get first tab name to set template on page load
    var tabSet = $('#tabdemo') // find the tabset
         , firstTab = $(tabSet).children('.ui-tabs-panel:visible');
         
    setTabName(firstTab);
});
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Nice approach! I think this would allow me to update the tab labels when the value for Chart_Tab_Names__c changes. What is the event handle for that?

Also, I think we want
 showLabels = showTabsRow.Chart_Tab_Names__c;
not 
 showLabels = showTabsRow__Chart_Tab_Names__c;

Correct?
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Correct, typo on my part, sorry about that.

For the toggling here is what I would do:

1) Add a model action on ShowTabs model for when field Chart_Tab_Names__c is updated
2) In the action call a snippet (e.g. toggleLabels)
3) In the snippet check the value and show/hide accordingly
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Loving it!

Thanks for all your help, Barry!