0

I've build a webpage with two maps inside two tabs. Instead of the classic structure with an 'ul>li>a" with an href and anchor, I've used radio buttons instead. My structure is as following:

<div class="tabs">
  <input type="radio" name="tabs" id="tabone" checked="checked">
  <label for="tabone">title</label>
  <div class="tab">Content</div>

  <input type="radio" name="tabs" id="tabtwo">
  <label for="tabtwo">title</label>
  <div class="tab">Content</div>
</div>

To open and hide content panels, I'm using the following css:

.tabs .tab {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
  -webkit-box-ordinal-group:3;
      -ms-flex-order:2;
          order:2;
}
.tabs input[type="radio"]:checked + label + .tab {
  clip: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  position: static;
  width: 100%;
}

And here is the jquery part :

 $('#tabone').click(function() {
        $(this).attr('checked', true);
        $('#tabtwo').attr('checked', false);
    })
    $('#tabtwo').click(function() {
        $(this).attr('checked', true);
        $('#tabone').attr('checked', false);
    })

Now I'm trying to open tabs depending on the url : If I type : mysite.com/#tabtwo I want to load the page directly with tabtwo openned.

I managed to add the hash part and now my jquery looks like this:

$("input[type=radio]").click(function() {
    window.location.hash = $(this).attr("data-href");
    if(window.location.hash === "#tabone"){
        $(this).attr('checked', true);
        $('#tabtwo').attr('checked', false);
    }else if(window.location.hash === "#tabtwo"){
        $(this).attr('checked', true);

        $('#tabone').attr('checked', false);
    }
});

The clicked radio button adds the attr checked to the tab but it always open with first tab. If I add "checked=checked" to both radio buttons, it works, I can type mysite.com/#tabtwo from outside and it open directly the second tab. But of course now even if I type mysite.com/#tabone it still open the second tab !!

As I already built my webpage with those radio buttons, I'm looking for a solution with that structure if possible..

blogob
  • 490
  • 5
  • 19

2 Answers2

0

Finaly, I saw this topic, and used the provided code to make it work.

Solution 1 :

I had to change my radio buttons to classic ul>li tabs.

 <div class="tabs">
   <ul class="nav nav-tabs" id="myTab" role="tablist">
      <li class="nav-item">
        <a class="nav-link active" id="left-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="log-in" aria-selected="true">My first tab</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="right-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="forgot-password" aria-selected="false">My second tab</a>
      </li>
    </ul>
     <div class="tab active" id="tab1"></div>
     <div class="tab" id="tab2"></div>
</div>

And changed my js code like so :

1-first, to display maps correctly inside the tabs

 $('.nav-item a').on('click', function() {
            setTimeout(function() {
                map.invalidateSize();
                map2.invalidateSize();
            }, 0);
        });

2-then, to toggle tabs and let external url open the desired tab

$(document).ready(function() {

    $('#left-tab').click(function(event) {
        event.preventDefault();
        $('.tabs .nav-item a').removeClass('active');
        $('.tabs .tab').removeClass('active');
        $(this).addClass('active');
        $('#tab1').addClass('active');
    })
    $('#right-tab').click(function(event) {
        event.preventDefault();
        $('.tabs .nav-item a').removeClass('active');
        $('.tabs .tab').removeClass('active');
        $(this).addClass('active');
       $('#tab2').addClass('active');
    })
    function onHashChange() {// this let me open tabs from an external url
        var hash = window.location.hash;

        if (hash) {

            $(`[data-toggle="tab"][href="${hash}"]`).trigger('click');
        }
    }

    window.addEventListener('hashchange', onHashChange, false);
    onHashChange();
});

The problem is partially solved.

  • Once on the page, if I click on the tabs, the url/hash does not change anymore.
  • Also, the tab opens at the place where the ID is located, which is normal, but in my example I would on the contrary want to disable the anchor jump.

Solution 2 :

So I had to make a few changes :

$(document).ready(function() {


    $('#left-tab').click(function(e) {
        window.location.hash = $(this).attr("href"); //this put back the hash
        if (location.hash) { // this allow to stay on top of the page
              setTimeout(function() {

                window.scrollTo(0, 0);
              }, 1);
            }
        e.preventDefault()

        $('.tabs .nav-item a').removeClass('active');
        $('.tabs .tab').removeClass('active');
        $(this).addClass('active');
        $('#tab1').addClass('active');
    })
    $('#right-tab').click(function(e) {

        window.location.hash = $(this).attr("href");
            if (location.hash) {
              setTimeout(function() {

                window.scrollTo(0, 0);
              }, 1);
            }
        e.preventDefault();

        $('.tabs .nav-item a').removeClass('active');
        $('.tabs .tab').removeClass('active');
        $(this).addClass('active');
       $('#tab2').addClass('active');
    })
    function onHashChange() { // this let me open tabs from an external url

        var hash = window.location.hash;    

        if (hash) {
            // using ES6 template string syntax
            $(`[data-toggle="tab"][href="${hash}"]`).trigger('click');
        }
    }

    window.addEventListener('hashchange', onHashChange, false);
    onHashChange();

});

Now it works better. When I come from an external url, like mysite.com#tab2, it loads the page with tab2 openned. Then when I click on tab1, it opens the tab1, staying on top of the page. But, it's stil not perfect, it's still glitchy.

Solution 3 :

So I looked for others solutions, and found this topic and @jumois' answer that consist in using

'different id for the target element than what is specified in the anchor.'

So I changed my code again like this :

 $(document).ready(function() {


        $('#lefttab').click(function(e) {
               $(window).on("hashchange", function(){
            var hash = this.location.hash;
            var mytab = $(hash + "-tab");
        });
            $('.tabs .nav-item a').removeClass('active');
            $('.tabs .tab').removeClass('active');
            $(this).addClass('active');
            $('#tab1-tab').addClass('active');
        })
        $('#righttab').click(function(e) {

           $(window).on("hashchange", function(){
            var hash = this.location.hash;
            var mytab = $(hash + "-tab");
        }); 
            $('.tabs .nav-item a').removeClass('active');
            $('.tabs .tab').removeClass('active');
            $(this).addClass('active');
           $('#tab2-tab').addClass('active');
        })

        function onHashChange() {    
            var hash = window.location.hash;    
            if (hash) {
                // using ES6 template string syntax
                $(`[data-toggle="tab"][href="${hash}"]`).trigger('click');
            }
        }
        window.addEventListener('hashchange', onHashChange, false);
        onHashChange();

    });

Of course I had to change the html part also:

<div class="tabs">
    <ul class="nav nav-tabs" id="myTab" role="tablist">
            <li class="nav-item">
                <a class="nav-link active" id="lefttab" data-toggle="tab" href="#tab1" role="tab" aria-controls="log-in" aria-selected="true">My first tab </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" id="righttab" data-toggle="tab" href="#tab2" role="tab" aria-controls="forgot-password" aria-selected="false">My second tab</a>
            </li>
        </ul>
<div class="tab active" id="tab1-tab"></div>
<div class="tab " id="tab2-tab"></div>
</div>

Now it looks much better. I can open a tab from an external url, like mysite.com#tab2 and there is no "jump to anchor" glitchy effect anymore.

blogob
  • 490
  • 5
  • 19
0

There is a solution that works with existing radio button markup using PHP to control which button/tab is in a 'checked' state via a variable passed from a query string in the url. This example is based on "workotabs", which I find neat, robust and flex-friendly. This is the original markup:

<div class="worko-tabs">
    <input class="state" type="radio" title="tab-one" name="tabs-state" id="tab-one" checked/>
    <input class="state" type="radio" title="tab-two" name="tabs-state" id="tab-two" />
    <input class="state" type="radio" title="tab-three" name="tabs-state" id="tab-three  /> 
    <div class="tabs flex-tabs">
        <label for="tab-one" id="tab-one-label" class="tab">TAB 1</label>
        <label for="tab-two" id="tab-two-label" class="tab"> TAB 2</label>
        <label for="tab-three" id="tab-three-label" class="tab">TAB 3</label>
<div id="tab-one-panel" class="panel active"></div>
<div id="tab-two-panel" class="panel"></div>
<div id="tab-three-panel" class="panel"></div>
</div>

(https://codepen.io/axelaredz/pen/KJzVXK)

Amend this to:

    <input class="state" type="radio" title="tab-one" name="tabs-state" id="tab-one" <?php if ($tab == '') { echo 'checked'; } else { echo ''; } ?> />
    <input class="state" type="radio" title="tab-two" name="tabs-state" id="tab-two" <?php if ($tab == '2') { echo 'checked'; } else { echo ''; } ?> />
    <input class="state" type="radio" title="tab-three" name="tabs-state" id="tab-three" <?php if ($tab == '3') { echo 'checked'; } else { echo ''; } ?> /> 
    <div class="tabs flex-tabs">
        <label for="tab-one" id="tab-one-label" class="tab">TAB 1</label>
        <label for="tab-two" id="tab-two-label" class="tab">TAB 2</label>
        <label for="tab-three" id="tab-three-label" class="tab">TAB 3</label>
<div id="tab-one-panel" class="panel <?php if ($tab == '') { echo 'active'; } else { echo ''; } ?>"></div>
<div id="tab-two-panel" class="panel <?php if ($tab == '2') { echo 'active'; } else { echo ''; } ?>"></div>
<div id="tab-three-panel" class="panel <?php if ($tab == '2') { echo 'active'; } else { echo ''; } ?>"></div>

The inserted PHP snippets check the value of a variable '$tab'. If empty, the first tab is 'checked' as the default; if the value is 2 or 3 etc.(add others for as many tabs as you need) 'checked' is added to the corresponding tab markup. The 'else' condition ensures that the $tab value is cleared for states that are not true on page load to prevent caching problems. (NOTE: The same code is added to the tab panels but adding 'active' instead of 'checked' to the relevant markup. You only need to do this is you change the style of the tab panels when they are 'active'. Otherwise you can leave out the PHP insertions from that section).

Then put the following line of PHP into the page header above the html tag:

<?php $tab = filter_var($_GET['tab'], FILTER_SANITIZE_SPECIAL_CHARS, 'UTF-8') ?>

This creates the $tab variable and gets its value from the referring URL query string. (The 'filter/sanitize' bit is important for security).

Now all you need to do is append ?tab=2 or ?tab=3 etc. to your target URL and the correct tab will be open when the page loads. A referring url without any query string will still serve the first tab by default.

  • thank you very much for you detailed answer;;I finaly chose a jquery solution, but I'll look at your solution !! thanks ! – blogob Nov 02 '20 at 21:06