Capturing 'shown' event from bootstrap tab
Asked Answered
H

6

34

I have some 'static' HTML on my page:

<div id="DIVISIONS">
    <ul class="nav nav-tabs" id="DIVISIONTABS">
        @* <li> nodes will be injected here by javascript *@
    </ul>
    <div class="tab-content" id="DIVISIONTABPANES">
        @* <div class="tab-pane"> nodes will be injected here by javascript *@
    </div>
</div>

On page load, I create a tab 'framework', i.e. create the bootstrap tabs and tab content containers.

I trigger the process with:

$(window).bind("load", prepareDivisionTabs);

And "prepareDivisionTabs" does this:

function prepareDivisionTabs() {
    // Retrieve basic data for creating tabs
    $.ajax({
        url: "@Url.Action("GetDivisionDataJson", "League")",
        cache: false
    }).done(function (data) {
        var $tabs = $('#DIVISIONTABS').empty();
        var $panes = $('#DIVISIONTABPANES').empty();
        for (var i = 0; i < data.length; i++) {
            var d = data[i];
            $tabs.append("<li><a href=\"#TABPANE" + d.DivisionId + "\" data-toggle=\"tab\">" + NMWhtmlEncode(d.Name) + "</a></li>");
            $panes.append("<div id=\"TABPANE" + d.DivisionId + "\" class=\"tab-pane\"></div>")
        }
        renderDivisionTabPaneContents(data);
    }).fail(function (err) {
        alert("AJAX error in request: " + JSON.stringify(err, null, 2));
    });
}

For info, the "renderDivisionTabPaneContents" in the above does this:

function renderDivisionTabPaneContents(data) {
    for (var i = 0; i < data.length; i++) {
        var d = data[i];
        renderDivisionTabPaneContent(d.DivisionId);
    }
}

function renderDivisionTabPaneContent(id) {
    var $tabPane = $('#TABPANE' + id);
    $tabPane.addClass("loader")
    $.ajax({
        url: "/League/GetDivisionPartialView?divisionId=" + id,
        cache: false
    }).done(function (html) {
        $tabPane.html(html);
    }).fail(function (err) {
        alert("AJAX error in request: " + JSON.stringify(err, null, 2));
    }).always(function () {
        $tabPane.removeClass("loader")
    });
}

All good so far. My page loads, my tab contents are rendered, and when I click the different tabs, the relevant content is shown.

Now, rather than loading all content at the start, I want to load tab content just-in-time by using the 'shown' event of the tabs. To test this, I've wanted to just make sure I could get a javascript alert when the tab was shown. So, I create the following to trigger the attachment of tab shown events:

$(function () {
    attachTabShownEvents();
})

which calls:

function attachTabShownEvents() {
    $(document).on('shown', 'a[data-toggle="tab"]', function (e) {
        alert('TAB CHANGED');
    })
}

I'd therefore expect so see the "TAB CHANGED" alert after the change of tab. But ... I see no alerts.

Could anybody help me out here?

Hairsplitting answered 2/11, 2013 at 12:11 Comment(4)
Have you tried replacing $(window).bind("load", prepareDivisionTabs); with $(prepareDivisionTabs);?Fidole
I'll give it a go and report back, but that part of the process seems fine at the moment as the tabs created during "prepareDivisionTabs" are working correctly. It's just the subsequent event handler that I try to add that is not working. UPDATE: Just made the suggested change and the behaviour is identical (i.e. tabs work in terms of screen behaviour, but still do not fire the 'shown' event).Hairsplitting
Oh, and I believe the event bind should be shown.bs.tab, not shownFidole
"shown.bs.tab" cracked it! Many thanks 'windy'.Hairsplitting
F
97

The correct event binding for tab change is shown.bs.tab.

$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
    alert('TAB CHANGED');
})

Update 11-01-2020 --- Bootstrap 4.5

This is still the correct answer however, this is a bit of additional helpful information found all the way at the bottom of the official bootstrap docs page at: https://getbootstrap.com/docs/4.5/components/navs/#tabs

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  e.target // newly activated tab
  e.relatedTarget // previous active tab
})

You can determine which tab has been selected each time the code fires with e.target.

If you have unique IDs on your elements then you could do something like the following so code only runs when the appropriate tab is clicked.

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  switch (e.target.id){
      case "mainTab":{
           doMainTabStuff();
           break;
      }
      case "configTab":{
           doConfigTabStuff();
           break;
      }
  }
})
Fidole answered 2/11, 2013 at 12:29 Comment(5)
This is the way to do it... Ignore most of the other suggestions on SO they don't work ;)Hidie
How would you adapt this to work for one specific tab?Gruelling
@Gruelling $(selector).on('shown.bs.tab', function (e) { alert('TAB CHANGED'); })Depolarize
$(selector).on('shown.bs.tab', function (e) { alert('TAB CHANGED'); }) , This one is not working for meWeighting
$(selector) is the parent div of the ul elementIncompressible
C
4
<a data-toggle="tab" href="#some_special_tab_anchor">

<div id="some_special_tab_anchor" class="tab-pane fade">
    special tab content
</div>

            $( 'a[data-toggle="tab"]' ).on( 'shown.bs.tab', function( evt ) {

                var anchor = $( evt.target ).attr( 'href' );
                alert("TAB SHOWN = "+anchor);

                // take action based on what tab was shown
               if(anchor === "some_special_tab_anchor"){
                  // do my special thing :)
               }

            });
Compatriot answered 26/10, 2018 at 2:58 Comment(1)
Glad I could help :)Compatriot
P
0

Use my Nuget package for lazyloading bootstrap tabs here, its very simple, just add "lazyload" class to the "ul" element of bootstrap tabs, then add "data-url" equal to url to load to the any tabs anchor element (a). thats it.

https://www.nuget.org/packages/MT.BootstrapTabsLazyLoader.js/

Punke answered 14/6, 2015 at 10:44 Comment(0)
B
0

'show' and 'shown' events didn't work for me. My solution is not exactly specifically OP's situation, but the general concepts are there.

I had the same issue with bootstrap forcing its own onclick events on tabs (menu buttons and content panels). I wanted to lazy load stuff into a panel depending on what menu button was clicked, and some buttons show a panel on the current page, others were to load a page into an iframe.

At first, I stuffed data into a hidden form field tag, which was the same issue. The trick is to detect some sort of change and act on that. I solved the problem by forcing a change and using an alternate event listening on the buttons without having to touch bootstrap.

1) stash iframe target in button as data attribute:

$('#btn_for_iframe').attr('data-url',iframeurl);

2) bind alternate event onto fire off thingy, and inside, swap out the iframe source

$('#btn_for_iframe').on('mouseup',function(){
   console.log(this+' was activated');
   $('#iframe').attr('src',$('#btn_for_iframe').attr('data-url'));
});

3) force 'change' event on panel shows, then load iframe src

$('#iframe_panel_wrapper').show().trigger('change');

or you can put the change trigger in the mouseup above.

Bootstrap answered 22/9, 2015 at 2:43 Comment(0)
C
0
$(document).ready(function(){
    $(".nav-tabs a").click(function(){
        $(this).tab('show');
    });
    $('.nav-tabs a').on('shown.bs.tab', function(event){
        alert('tab shown');
    });
});
Compatriot answered 26/10, 2018 at 2:49 Comment(0)
S
0

vanilla js (Bootstrap 5.3)

myTabBtn.addEventListener('shown.bs.tab', function(e) {
    e.preventDefault();
    // your code
});
Sourwood answered 22/5, 2023 at 7:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.