Location.hash returns empty string

1.8k Views Asked by At

I am currently using jQuery, Twitter Bootstrap and CanJS for my web application. I'm trying to implement routing with CanJS. I'm using Bootstrap's tab, and when I click on a tab, it was supposed to bring #tabSearch, #tabUser or #tabPermissions, but the hash is returned with an empty string. What am I doing wrong?

I´m using this to change the tabs:

     TabControl = can.Control.extend({}, {
        init: function (element, options) {
        element.find('a[href="' + options.defaultTab + '"]').tab('show');
        this.userSearch = null;
        this.userForm = null;
    }
    , 'a[data-toggle="tab"] show': function (e) {
        this.options.tabChangeCallback(e);
    }
});

     UserTab = new TabControl('#tabctrlUser', {
       defaultTab: '#tabSearch',
       tabChangeCallback: function (e) {

        if (e.context.hash == '#tabSearch') {                
            if (!this.userSearch) {
                this.userSearch = new FormUserQuery('#tabSearch', {});
            } 
        } else if (e.context.hash == '#tabUser') { 
            if (!this.userForm) {
                this.userForm = new FormUser('#tabUser', {});
            }
            this.userForm.renderView(currentUser);
        } else if (e.context.hash == '#tabPermissions') {                
            new FormPermissions('#tabPermissions', {});

        }
    }
});

Here is the HTML part:

<ul id="tabctrlUser" class="nav nav-tabs">
     <li><a href="#tabSearch"  data-toggle="tab">Pesquisar</a></li>
     <li><a href="#tabUser"  data-toggle="tab">Cadastrar/Alterar</a></li>
     <li><a href="#tabPermissions"  data-toggle="tab">Acessos</a></li>
</ul>
<div class="tab-content">
     <div class="tab-pane" id="tabSearch"></div>
     <div class="tab-pane" id="tabUser"></div>
     <div class="tab-pane" id="tabPermissions"></div>
</div>
2

There are 2 best solutions below

0
On BEST ANSWER

You need to use can.route or can.Control.Route, the way you do it is complicated take a look at this question Also there's 2 good articles about routing

look at this gist

http://jsfiddle.net/Z9Cv5/2/light/

var HistoryTabs = can.Control({
  init: function( el ) {

    // hide all tabs
    var tab = this.tab;
    this.element.children( 'li' ).each(function() {
      tab( $( this ) ).hide();
    });

    // activate the first tab
    var active = can.route.attr(this.options.attr);
    this.activate(active);
  },
  "{can.route} {attr}" : function(route, ev, newVal, oldVal){
    this.activate(newVal, oldVal)
  },
  // helper function finds the tab for a given li
  tab: function( li ) {
    return $( li.find( 'a' ).attr( 'href' ) );
  },
  // helper function finds li for a given id
  button : function(id){
    // if nothing is active, activate the first
    return id ? this.element.find("a[href=#"+id+"]").parent()  : 
                this.element.children( 'li:first' );
  },
  // activates 
  activate: function( active, oldActive ){
    // deactivate the old active
    var oldButton = this.button(oldActive).removeClass('active');
    this.tab(oldButton).hide();
    // activate new
    var newButton = this.button(active).addClass('active');
    this.tab(newButton).show();
  },
  "li click" : function(el, ev){
    // prevent the default setting
    ev.preventDefault();
    // update the route data
    can.route.attr(this.options.attr, this.tab(el)[0].id)
  }
});

// configure routes
can.route(":component",{
  component: "model",
  person: "mihael"
});

can.route(":component/:person",{
  component: "model",
  person: "mihael"
});

// adds the controller to the element
new HistoryTabs( '#components',{attr: 'component'});
new HistoryTabs( '#people',{attr: 'person'});
2
On

I am not familiar with CanJS, but this could have something to do that anchor click event happens before navigation, and location.hash is set after. E.g. if (as a test) you define your link as

<a href="#tabSearch" onclick="tabChangeCallback()">Pesquisar</a>

And in plain vanilla JS try

function tabChangeCallback() {
  alert(location.hash)
}

It will display blank.

But if you try something like

function tabChangeCallback() {
   setTimeout(function() {
       alert(location.hash)
   }, 100)
}

It will display the hash. So in your case either set your code to be executed on timeout after main event or (and I think it's a better option) instead of hash you should read href attribute of the anchor element that caused the event.

Update The plain JS example below shows how to get the hash value without timeout:

function tabChangeCallback(e) {

     var elem = e ? e.target : event.srcElement

     alert(elem.getAttribute("href"))
}