Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the back and forward buttons with the History API

I have the following test application: http://dev.driz.co.uk/ajax/

You can click the links to load in other pages using jQuery AJAX and there are two types, globalTabs and localTabs which load in content into different panels. NOTE: That each page is actually the full page but we only grab the content we want using jQuery find method.

To enhance this I am using the HTML5 History API (History.js for cross-browser).

The titles and urls change fine and the history stack is being pushed to successfully and when I use the back and forward buttons the url and title does revert back.

Now the complicated part is loading back in the content from the previous state and more complicated loading the correct type e.g. global or local ajax. To achieve this I am thinking I need to pass BOTH the data and the type to the push state so that it can be reused again for the popstate...

Can anyone help point me in the right direction? I have all the first parts working, just a case of getting this passing of the ajax type to the pushState and then reusing it with the popstate change.

To improve on this I rewriting it as follows to show my plan for passing the type and data:

NOTE: the uppercase History is because I'm using History.js

var App = {

    init: function() {

        $(document).ready(function() {

            $('.globalTabs li a').live('click', function (e) {
                e.preventDefault(); 
                App.globalLoad( $(this).attr('href') );
            }); 

            $('.localTabs li a').live('click', function (e) {
                e.preventDefault();
                App.localLoad( $(this).attr('href') );
            });

        });

        window.addEventListener('popstate', function(event) {

            // Load correct content and call correct ajax request...

        });

    },

    localLoad: function ( url ) {

        $.ajax({
            url: url,
            success: function (responseHtml) {
                $('.localContent').html($(responseHtml).find('#localHtml'));

                $data = { $(responseHtml).find('#localHtml'), 'local'};

                History.pushState($data, $(responseHtml).filter('title').text(), url);
            }
        });

    },

    globalLoad: function ( url ) {

        $.ajax({
            url: url,
            success: function (responseHtml) {
                $('.mainContent').html($(responseHtml).find('#globalHtml'));

                $data = { $(responseHtml).find('#globalHtml'), 'global'};

                History.pushState($data, $(responseHtml).filter('title').text(), url);
            }
        });

    }

};

App.init();

UPDATE: To clarify this question, they're are two problems I seek help with.

1.) Get the back and forward buttons working with the ajax requests so they load the correct data back into the content area.

2.) Loading the content into the correct area by also passing the content with the pushState method so that it knows if it's a global div or local div request.

like image 737
Cameron Avatar asked Aug 17 '12 09:08

Cameron


People also ask

Can I use history back ()?

back() is the same as history.go(-1) . history. back() is the same as clicking "Back" your browser.

What is the syntax and use of history back () method?

The History back() method in HTML is used to load the previous URL in the history list. It has the same practical application as the back button in our web browsers. This method will not work if the previous page does not exist. This method does not contain any parameter.

What is history API?

The DOM Window object provides access to the browser's session history (not to be confused for WebExtensions history) through the history object. It exposes useful methods and properties that let you navigate back and forth through the user's history, and manipulate the contents of the history stack.


1 Answers

the data object is wrong, that is why you get that problem. An object is defined by key,values pair:

object = {key:'value'};
$data = { text:$(responseHtml).find('#globalHtml'), type:'global', url:'the_url'};

not

$data = { $(responseHtml).find('#globalHtml'), 'global'};

Using the object definition you will get your data back using History.getState()

History.Adapter.bind(window,'statechange',function(){
    var data = History.getState().data;
    if(data){
        var html = data.text;
        var type = data.type;
        var type = data.url;
        if(html && type){
            if(type == 'global'){
                // just change html
                $('.mainContent').html(html);
                // call the App object's function
                if(url) App.localLoad(url);
            }else{
                $('.localContent').html(html);
            }
        }
    }
})

NOTE:

  • when statechange event get's fired if any data is present it will fire the ajax calls
  • to simulate the ajax call without making it just change the title also, I think that will cover it

EDIT

  • the data object is actually taken from History.getState().data not History.getState()
  • added another param to the stored object to preserve url
  • using the url and the type you can make a call to the same function as in the onClick event

PROBLEM:

Uncaught TypeError: Converting circular structure to JSON

An object is referencing itself somewhere; hence the message "circular structure.". That means you are trying to stringify a object that has a reference to itself, this usualy happens with DOM elements. You should really consider changing

$data = { $(responseHtml).find('#localHtml'), 'local'};

to:

$data = { html:$(responseHtml).find('#localHtml').html(), type:'local'};

Notice the keys for the object (html and type) and the html function call (.html()), this way you wont send unnecessary data, just the html. If you need to use the html data when loading it as a DOM object just use this:

var DOM_Element_loaded = $('<div>').html(html_loaded);

now you can use DOM_Element_loaded to search/manipulate data in the html loaded without needing to attach it to the body.

like image 142
cuzzea Avatar answered Sep 23 '22 05:09

cuzzea