12

I am trying to make ajax work with the back button and am missing something central. Where are the previous page states stored?

CASE 1:

Click "make me red". ajax event occurs and page turns red. Hash = #red

Click "make me yellow". ajax event occurs and page turns yellow. Hash = #yellow

Click back button. Hash is now back to #red. But I also want the page to be red. It's still yellow.

CASE 2:

Click "make me red". ajax event occurs and page turns red. Hash = #red

Click "Go to other site". It goes to Google.

Click back button. We're back to site, hash = #red, but I also want the page to be red!

<!DOCTYPE html>
<html>
<style>
    .red{background:red}
    .yellow{background:yellow}
</style>
<head>
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function(){
        $('.ajax_thing').click(function(){
            location.hash=$(this).attr('action_type');
            return false
        })
        var originalTitle=document.title
        function hashChange(){
            var page=location.hash.slice(1)
            if (page!=""){
                $('#content').load(page+".html #sub-content")
                document.title=originalTitle+' – '+page
            }
        }
        if ("onhashchange" in window){ // cool browser
            $(window).on('hashchange',hashChange).trigger('hashchange')
        }else{ // lame browser
            var lastHash=''
            setInterval(function(){
                if (lastHash!=location.hash)
                    hashChange()
                lastHash=location.hash
            },100)
        }
    })

    </script>
</head>
<body>
<menu>
       <li><a class="ajax_thing" id = "red_action" action_type="red">Make me red</a></li>
        <li><a class="ajax_thing" id = "yellow_action" action_type="yellow">Make me yellow</a></li>
</menu>
        <li><a href = "http://www.google.com">Go to other site</a></li>
</body>
</html>
<script>

$("#red_action").click(function(e) {
  // ajax here. on success:
    $("body").removeClass("yellow");
    $("body").addClass("red");
})

$("#yellow_action").click(function(e) {
  // ajax here. on success:
    $("body").removeClass("red");
    $("body").addClass("yellow");
})

</script>
user984003
  • 28,050
  • 64
  • 189
  • 285
  • 1
    You should look at https://github.com/browserstate/history.js/ – gmaliar Jul 21 '13 at 07:05
  • I do not see any `ajax request` and also you forgot a lot of `semicolons` – Victor Castillo Torres Jul 21 '13 at 07:05
  • 1
    It works so the missing semicolons must be ok. I grabbed most of the code from somewhere else. I don't do the actual ajax request since I wanted this to work for everyone here exactly as it is. But I change the dom, which is what the ajax request would do. Do you think that an actual ajax request is what would magically make it work? – user984003 Jul 21 '13 at 07:08
  • 1
    "It works so the missing semicolons must be ok." ... o_O – eyelidlessness Jul 21 '13 at 07:32
  • 2
    while it is good practice to use the statement _separator_ `;`, there are they are not mandatory in all cases. (the argument "must be ok" is kinda silly of course, but I don't see any lines where the missing `;` is a problem). If you want specifics, head over to http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript – Nanne Jul 21 '13 at 09:07

2 Answers2

13

Rather than using your JavaScript to drive your URLs, let your URLs drive your JavaScript. Let the window.onhashchange event handler do all the work. Everything else should just change the hash.

You don't even need click handlers for links, just set the url to the right hash:

<a href="#red">Red</a>

Then, your hashchange handler takes care of the rest:

function hashChange() {
    var page = location.hash.slice(1);
    if (page) {
        $('#content').load(page+".html #sub-content");
        document.title = originalTitle + ' – ' + page;
        switch (page) {
            // page specific functionality goes here
            case "red":
            case "yellow":
                $("body").removeClass("red yellow").addClass(page);
                break;
        }
    }
}

The only reason to change the hash at all is if you want to be able to come back to the page and have it load the same state based on the URL. So, you already have the requirement to let the URL drive the JavaScript, right? Else why are you changing the hash? Moving functionality out of click handlers, and into the hashchange event only simplifies things.

gilly3
  • 87,962
  • 25
  • 144
  • 176
  • But that still doesn't load the content. Also, the ajax is not href driven. In my actual code it's a button that calla ajax and adds a tag. – user984003 Jul 21 '13 at 08:33
  • @user984003 - I don't understand. Why wouldn't the content be loaded? Why does it matter that you use a button instead of a link? – gilly3 Jul 21 '13 at 09:01
  • The way I understand your answer, I need to write code to specifically change the state back to the way it was, e.g. setting the background to red. But the user might have added a tag, changed the rating, and added the item to a cart, all via ajax. I need a way to get this state in one swoop. pushState or history.js seems to be what people are recommending. – user984003 Jul 22 '13 at 09:59
  • 2
    Logged in to say that this is an incredible solution with almost mind-bending problem-solving. – seanlevan May 24 '15 at 01:45
6

When using AJAX it's important to update the history manually using history.pushState

Then create a function testing for an onpopstate event and updating the content as required.

https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Manipulating_the_browser_history

j00lz
  • 281
  • 1
  • 12
  • 2
    Welcome to Stack Overflow. Please summarise the links in your answer; that way, if the links go stale the answer won't be completely useless. – michaelb958--GoFundMonica Jul 21 '13 at 07:38
  • 2
    This seems to be what people are recommending or, for all browsers, history.js. (I actually ended up doing something simpler where I just reload the page if a change has occurred, keeping track of changes with a hash) – user984003 Jul 22 '13 at 10:04