Bootstrap: Tab: Cancel "show" event

Created on 20 Apr 2012  路  6Comments  路  Source: twbs/bootstrap

I currently have a setup with a form spread out over a number of tab panes. When a user navigates away from a tab, I only want them to be allowed to do so if the form is filled out correctly.

I thought cancelling the "show" event would do it, but it turns out the action of showing a pane isn't dependant on the success of the "show" event propagating.

I've patched the Tab functionality for my use, but would the powers-that-be consider this patch if I made it a pull request, or should I not bother?

js

Most helpful comment

Actually now that I thought about it and I know it's going to be different for each case, but it seems like one of the problems is if you are using the data-toggle='tab' or data-toggle='pill', that function in the tab data-api is going to get called.

If you do the following:

$('#formTab a').click(function (e) {
    e.preventDefault();
    if($("#form-contact").valid()){
        $(this).tab('show');
    }
});

That is working for me. I'm using jQuery validator and it only checks the displayed form elements. So now it can check for validity and if it is valid, show that tab.

All 6 comments

tabs will show even with css only. If you want to do this you will have to use jquery and target those elements in the page.

Do you have the code that you used? I do not see a fork on your site for this. I'm looking for the same thing.

The change is in the show() function where the work of triggering is only done .on('show.bootstrap'). I had to namespace the show event in the plugin, in case additional event listeners get added.

!function( $ ){

  "use strict"

 /* TAB CLASS DEFINITION
  * ==================== */

  var Tab = function ( element ) {
    this.element = $(element)
  }

  Tab.prototype = {

    constructor: Tab

  , show: function () {
      var $this = this.element
        , self = this
        , $ul = $this.closest('ul:not(.dropdown-menu)')
        , selector = $this.attr('data-target')
        , previous
        , $target

      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
      }

      if ( $this.parent('li').hasClass('active') ) return

      previous = $ul.find('.active a').last()[0]

        $this.on('show.bootstrap',function(){


        $target = $(selector)

          self.activate($this.parent('li'), $ul)
          self.activate($target, $target.parent(), function () {
            $this.trigger({
              type: 'shown'
            , relatedTarget: previous
            })
          })

          $this.off('show.bootstrap');
        });


        $this.trigger({
        type: 'show'
      , relatedTarget: previous
      });
    }

    , activate: function ( element, container, callback) {
          var $active = container.find('> .active')
            , transition = callback
                && $.support.transition
                && $active.is('.fade')

          function next() {

            $active
              .removeClass('active in')
              .find('> .dropdown-menu > .active')
              .removeClass('active in')

            element.addClass('active')

            if (transition) {
                element[0].offsetWidth // reflow for transition
                element.removeClass('out').addClass('in')
            } else {
              element.removeClass('fade')
            }

            if ( element.parent('.dropdown-menu') ) {
              element.closest('li.dropdown').addClass('active')
            }

            callback && callback()
          }

          transition ?
            $active.one($.support.transition.end, next) :
            next();

            var nextLoc = element.siblings().andSelf().index(element);
            var currLoc = $active.siblings().andSelf().index($active);

            if(nextLoc > currLoc){
                $active.removeClass('in').addClass('out');
                $active.next().removeClass('out in');
            }
            else
                $active.removeClass('out in');
        }
      }

Thanks!!

Actually now that I thought about it and I know it's going to be different for each case, but it seems like one of the problems is if you are using the data-toggle='tab' or data-toggle='pill', that function in the tab data-api is going to get called.

If you do the following:

$('#formTab a').click(function (e) {
    e.preventDefault();
    if($("#form-contact").valid()){
        $(this).tab('show');
    }
});

That is working for me. I'm using jQuery validator and it only checks the displayed form elements. So now it can check for validity and if it is valid, show that tab.

you can just call e.preventDefault() on the show event.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alvarotrigo picture alvarotrigo  路  3Comments

iklementiev picture iklementiev  路  3Comments

devfrey picture devfrey  路  3Comments

vinorodrigues picture vinorodrigues  路  3Comments

IamManchanda picture IamManchanda  路  3Comments