skip to Main Content

What’s the simplest way with this jQuery change function to enable bookmarked hash links to work, i.e to be able to use example.com/#theme1 or example.com/#theme2 links?

The jQuery #theme-selector changes the hash and shows/hides the relevant divs with the class, i.e. .theme1 or .theme2, but when going to example.com/#theme1 from a bookmarked link, all divs are shown.

In addition, if I refresh example.com/#theme1, the hash remains #theme1, but all divs are shown.

Some other questions on SO deal with bookmarkable hashes, but they’re many years old. And some libraries that appear useful are ten years old, too, like https://github.com/asual/jquery-address

Unfortunately, running the snippet here won’t show browser hash changes, nor will JSFiddle.


Update 10/26/23

@SKJ’s answer works in an html file opened with a browser, and shows bookmarkable links and retains the hash on refresh. But for some reason, it doesn’t work on a live server. On the live server, there are no console errors; the dropdown #theme-selector works and filters the divs, but bookmarkable links don’t work, and on a page reload, the URL hash is ignored and the selector resets to all-themes and all divs show.

But…. I have some older plain Javascript where these filters work and also bookmarkable links work; but I’m trying to simplify and replace it with jQuery (and I’ve also changed the html markup), hence this SO question.

So what is it in this plain Javascript https://pastebin.com/JUDizTXA that works for bookmarkable links and refresh-proof URL hashes? What can be adapted to this new jQuery to enable bookmarkable links refresh-proof URL hashes?

  jQuery(document).ready(function(jQuery){
    
        jQuery("#theme-selector").change(function () {
    
        var urlhash = document.getElementById('theme-selector').value;
    
        window.location.hash = urlhash;
    
    });
    
    
    jQuery("#theme-selector").change(function () {
    
    themeclass = window.location.hash.substr(1);
    
    jQuery('.blockcontent').hide();
    jQuery('.' +themeclass).show();
    jQuery('.theme-header').hide();
    jQuery('.' +themeclass).show();
    
        });
    
    });
 .blockcontent {
    display:inline-block;
    width:150px;
    border:1px solid #acacac;
    }
    
    .theme-header {
    display:none;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

 <label for="theme-selector">Filter by Theme:</label>
    
    <select name="theme-selector" id="theme-selector" value="">
    
    <option value="all-themes">All Themes</option>
    <option value="theme1">Theme 1</option>
    <option value="theme2">Theme 2</option>
    <option value="theme3">Theme 3</option>
    
    </select>
    
    <br>
    
    <div id="theme-description-container">
    <div class="theme1 theme-header">Theme 1 Description</div>
    <div class="theme2 theme-header">Theme 2 Description</div>
    <div class="theme3 theme-header">Theme 3 Description</div>
    </div>
   
    <br>
    
    <div class="blockcontent all-themes theme1">
    theme1<br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do 
    </div>
    
    <div class="blockcontent all-themes theme2">
    theme2<br><br>sed do eiusmod tempor incididunt sed do eiusmod eiusmod
    </div>
    
    <div class="blockcontent all-themes theme3 theme2">
    theme2 and theme3<br><br>consectetur adipiscing elit,consect adipiscing elit, 
    </div>
    
    <div class="blockcontent all-themes theme3">
    theme3<br><br>consectetur adipiscing elit,consect etur adipiscing elit, 
    </div>

2

Answers


  1. You need to use $(location).attr('hash'); to get the current hash.

    I commented my code.

    NOTE : instead of using document.getElementById('theme-selector'), you can just use $(this).

    EDIT : Change event handler should be defined before calling the .trigger(‘change’)

    jQuery(document).ready(function(jQuery) {
    
      
      jQuery("#theme-selector").change(function () {
        var urlhash = document.getElementById('theme-selector').value;
        window.location.hash = urlhash;
    
      });
    
    
     jQuery("#theme-selector").change(function () {
    
      themeclass = window.location.hash.substr(1);
    
      jQuery('.blockcontent').hide();
      jQuery('.' +themeclass).show();
      jQuery('.theme-header').hide();
      jQuery('.' +themeclass).show();
    
     });
     
       var urlhash = $(location).attr('hash'); // current hash
      
      // we check if current hash exist
      if (urlhash && urlhash !== "") {
         urlhash = urlhash.replace('#', ''); // remove # from hash
         
         // trigger change on selected option corresponding to hash
         $("#theme-selector option[value='" + urlhash + "']").prop("selected",true).trigger("change");
      }
    
    });
    .blockcontent {
        display:inline-block;
        width:150px;
        border:1px solid #acacac;
        }
        
        .theme-header {
        display:none;
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
     <label for="theme-selector">Filter by Theme:</label>
        
        <select name="theme-selector" id="theme-selector" value="">
        
        <option value="all-themes">All Themes</option>
        <option value="theme1">Theme 1</option>
        <option value="theme2">Theme 2</option>
        <option value="theme3">Theme 3</option>
        
        </select>
        
        <br>
        
        <div id="theme-description-container">
        <div class="theme1 theme-header">Theme 1 Description</div>
        <div class="theme2 theme-header">Theme 2 Description</div>
        <div class="theme3 theme-header">Theme 3 Description</div>
        </div>
       
        <br>
        
        <div class="blockcontent all-themes theme1">
        theme1<br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do 
        </div>
        
        <div class="blockcontent all-themes theme2">
        theme2<br><br>sed do eiusmod tempor incididunt sed do eiusmod eiusmod
        </div>
        
        <div class="blockcontent all-themes theme3 theme2">
        theme2 and theme3<br><br>consectetur adipiscing elit,consect adipiscing elit, 
        </div>
        
        <div class="blockcontent all-themes theme3">
        theme3<br><br>consectetur adipiscing elit,consect etur adipiscing elit, 
        </div>
    Login or Signup to reply.
  2. I have encountered this problem many times. This is the solution we use. It will handle the <select> changes and will trigger the changes if the theme is part of the url from direct links or bookmarked pages etc. Hopefully it is a little more succinct and efficient:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <style>
                .blockcontent {
                    display: inline-block;
                    width: 150px;
                    border: 1px solid #acacac;
                }
        
                .theme-header {
                    display: none;
                }
            </style>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        </head>
        <body>
            <label for="theme-selector">Filter by Theme:</label>
            
            <select name="theme-selector" id="theme-selector" value="">
                <option value="all-themes">All Themes</option>
                <option value="theme1">Theme 1</option>
                <option value="theme2">Theme 2</option>
                <option value="theme3">Theme 3</option>
            </select>
            <br>
            <div id="theme-description-container">
                <div class="theme1 theme-header">Theme 1 Description</div>
                <div class="theme2 theme-header">Theme 2 Description</div>
                <div class="theme3 theme-header">Theme 3 Description</div>
            </div>
            <br>
            <div class="blockcontent all-themes theme1">
                theme1<br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
            </div>
            <div class="blockcontent all-themes theme2">
                theme2<br><br>sed do eiusmod tempor incididunt sed do eiusmod eiusmod
            </div>
            <div class="blockcontent all-themes theme3 theme2">
                theme2 and theme3<br><br>consectetur adipiscing elit,consect adipiscing elit,
            </div>
            <div class="blockcontent all-themes theme3">
                theme3<br><br>consectetur adipiscing elit,consect etur adipiscing elit,
            </div>
            <script>
                $(document).ready(function () {
                    // Add event listener to theme-selector <select> element
                    // Pass in the event object as 'e' variable
                    $("#theme-selector").change(function (e) {
                        // themeclass is the option selected value
                        const themeclass = e.target.value;
                        window.location.hash = themeclass;
                        // Select both classes at once. 
                        // No need to do them separately as this involves more DOM searches which is inefficient
                        $('.blockcontent, .theme-header').hide();
                        $('.' + themeclass).show();
                    });
            
                    // Now that you have an event listener set up handle direct links/bookmarked pages
                    const urlhash = window.location.hash;
                    if (urlhash !== "") {
                        // Use jQuery val() method to select <option value="urlhash">
                        // Trigger change on that value
                        $('#theme-selector').val(urlhash.slice(1)).trigger('change');
                    }
                });
            </script>
        </body>
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search