HTML5 history disabling forward button
Asked Answered
T

4

17

I am writing a single page javascript application using the HTML5 History API. The application loads content via Ajax and internally maintains state information on the foreground screen using a screen stack.

I want to enable navigation with the back button, but I never want to the forward button to be enabled.

A couple quick bits of information:

  • The user should only ever be able to go back, never forward
  • Pressing browser back button closes the current page screen user is on and reloads the previous one
  • Project is targeted towards the latest version of Chrome only, so other browsers implementations are not important
  • I am using native JavaScript and jQuery only, I would like to do this without History.js

When I load a new screen I run the following line:

history.pushState(screenData, window.document.title, "#");

I bind to the popstate event via jQuery:

$(window).bind("popstate", function(event) {
    if (event.originalEvent.state != null) {
        // Logic that loads the previous screen using my screen stack
    }
}); 

My application's history management is working, however when I go back the forward button is enabled. I need to figure out how to remove data from history on the popstate event.

Can I do this with replaceState? I'm not sure how to go about doing this...

Toxoplasmosis answered 18/7, 2012 at 19:6 Comment(0)
D
11

Bad Part

To really disable the forward button, you would have to be able to delete browser history, which is not allowed by all javascript implementations because it would allow sites to delete the entire history, which would never be in the interest of the user.

Good Part

This is a bit tricky, but I guess it could work if you want to do custom history. You could just use pushState in the popstate event to make your actual page the topmost history entry. I assume the way you handle your history, your window will never unload. This allows you to keep track of the user history yourself:

var customHistory = [];

Push every page you load with history.pushState(screenData, window.document.title, "#");, like you did before. Only you add the state to your custom history, too:

history.pushState(screenData, window.document.title, "#");
customHistory.push({data: screenData, title: window.document.title, location: '#'});

now if you have a popstate event, you just pop you custom history and push it to the topmost entry:

window.onpopstate = function(e) { 
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
}

Or in jQuery

$(window).on('popstate', function(e) {
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
});
Devonna answered 18/7, 2012 at 20:43 Comment(5)
Hello i know its kinda old answer, but can I ask if there is any possibility to use backward button just once to actually go back in history instead of clicking it 2 times? Because like this i first push the same url into history and when i use backbutton it first pops the pushed history url which is the same so it takes 2 click on back button to actually go back. If you could help me with this, it would be awesome.Chapland
I managed to do it myself so no need to answer to my comment. Thank you very much though for that suggestion using own custom history.Chapland
@Chapland are you sure you were able to do it? I was able to do it as well but at some point you have to click it again 2 times or sometimes even n times... Could you share the code of yoursGeyser
in my answer I adopted the strategy to "disable the forward-button" by "pushing the popstate event's state one-more-time as to be the most forward history state", however I do so with the improvements (a) to notrequire a duplicate history and (b) to avoid the issue of "forcing the user to click the back button multiple times as a result of duplicate history states".Phipps
I was doing it and came here to find out how to not disable the forward button ;)Acriflavine
P
12

The accepted answer solves the problem to disable the forward button, but creates a new annoying issue "the page navigated back to" is inserted in duplicate into the history (as indicated in the answers comments).

Here is how solve the question "diabled forward button" and to avoid the "duplicate" back-button-issue.

//setup the popstate EventListener that reacts to browser history events
window.addEventListener("popstate",function(event){
     // In order to remove any "forward"-history (i.e. disable forward 
     // button), this popstate's event history state (having been navigated 
     // back to) must be insert _again_ as a new history state, thereby 
     // making it the new most forwad history state. 
     // This leaves the problem that to have this popstate event's history
     // state to become the new top, it would now be multiple in the history
     //
     // Effectively history would be:
     //  * [states before..] ->
     //  * [popstate's event.state] -> 
     //  * [*newly pushed _duplicate_ of popstate's event.state ]
     // 
     // To remove the annoyance/confusion for the user to have duplicate
     // history states, meaning it has to be clicked at least twice to go 
     // back, we pursue the strategy of marking the current history state
     // as "obsolete", as it has been inserted _again_ as to be the most
     // forward history entry. 
     // 
     // the popstate EventListener will hence have to distinguish 2 cases:
     //
     // case A) "popstate event is _not_ an obsolete duplicate"...
     if( typeof event.state == "object" 
         && event.state.obsolete !== true)
     {
         //...so we _firstly_ mark this state as to from now on "obsolete",
         // which can be done using the history API's replaceState method
         history.replaceState({"obsolete":true},"");
         // and _secondly_ push this state _one_more_time_ to the history
         // which will solve the OP's desired "disable forward button" issue
         history.pushState(event.state,"");
     }

     // case B: there is the other case that the user clicked "back" and
     // encounters one of the duplicate history event entries that are 
     // "obsolete" now.
     if( typeof event.state == "object" 
         && event.state.obsolete === true)
     {
         //...in which case we simply go "back" once more 
         history.back() 
         // by this resolving the issue/problem that the user would
         // be counter-intuively needing to click back multiple times.
         // > we skip over the obsolete duplicates, that have been the
         // the result of necessarily pushing a history state to "disable
         // forward navigation"
     }

},false);
Phipps answered 2/10, 2018 at 13:14 Comment(3)
this is throwing errors about 'obsolete' not being defined and didn't seem to change the behavior at all.Balladist
@Balladist , change typeof event.state == "object" to typeof event.state === "object" && event.state !== null to workNumerary
@Phipps in ios with this approach back swipe preview will not be correct after one back operation .if u before back more than 1 once, next back swipe preview will point to wrong pageElidaelidad
D
11

Bad Part

To really disable the forward button, you would have to be able to delete browser history, which is not allowed by all javascript implementations because it would allow sites to delete the entire history, which would never be in the interest of the user.

Good Part

This is a bit tricky, but I guess it could work if you want to do custom history. You could just use pushState in the popstate event to make your actual page the topmost history entry. I assume the way you handle your history, your window will never unload. This allows you to keep track of the user history yourself:

var customHistory = [];

Push every page you load with history.pushState(screenData, window.document.title, "#");, like you did before. Only you add the state to your custom history, too:

history.pushState(screenData, window.document.title, "#");
customHistory.push({data: screenData, title: window.document.title, location: '#'});

now if you have a popstate event, you just pop you custom history and push it to the topmost entry:

window.onpopstate = function(e) { 
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
}

Or in jQuery

$(window).on('popstate', function(e) {
  var lastEntry = customHistory.pop();
  history.pushState(lastEntry.data, lastEntry.title, lastEntry.location);
  // load the last entry
});
Devonna answered 18/7, 2012 at 20:43 Comment(5)
Hello i know its kinda old answer, but can I ask if there is any possibility to use backward button just once to actually go back in history instead of clicking it 2 times? Because like this i first push the same url into history and when i use backbutton it first pops the pushed history url which is the same so it takes 2 click on back button to actually go back. If you could help me with this, it would be awesome.Chapland
I managed to do it myself so no need to answer to my comment. Thank you very much though for that suggestion using own custom history.Chapland
@Chapland are you sure you were able to do it? I was able to do it as well but at some point you have to click it again 2 times or sometimes even n times... Could you share the code of yoursGeyser
in my answer I adopted the strategy to "disable the forward-button" by "pushing the popstate event's state one-more-time as to be the most forward history state", however I do so with the improvements (a) to notrequire a duplicate history and (b) to avoid the issue of "forcing the user to click the back button multiple times as a result of duplicate history states".Phipps
I was doing it and came here to find out how to not disable the forward button ;)Acriflavine
R
8

Just use following jquery to disable forward button:

  $( document ).ready( function(){
    history.pushState(null,  document.title, location.href);        
   });
Ruckus answered 14/11, 2018 at 6:35 Comment(0)
G
0

NOTE:

  • This code was tested and worked fine without showing any problems, however I would incentivize developers to test it more before going to production with the code.
  • If HTML5 history.replaceState() is used anywhere in your application, the code below might now work.

I created a custom function in order to disable the forward button.

Here is the code (it doesn't work with the hash routing strategy):

  <script>
    (function() {
      // function called after the DOM has loaded
      disableForwardButton();
    })();

    function disableForwardButton() {
      var flag, loop = false;
      window.addEventListener('popstate', function(event) {
        if (flag) {
          if (history.state && history.state.hasOwnProperty('page')) {
            loop = true;
            history.go(-1);
          } else {
            loop = false;
            history.go(-1);
          }
        } else {
          history.pushState({
              page: true
            },
            null,
            null
          );
        }
        flag = loop ? true : !flag;
      });

      window.onclick = function(event) {
        flag = false;
      };
    }
  </script>

As Redrif pointed out in the comments of the accepted answer, the problem is that you have to double click the back button in order to navigate back to the page which is tedious and impractical.

Code explanation: each time you click the back button you need to create an additional history element so that the the current page which you are located on points to the newly created history page. In that way there is no page to go forward to since the pushState is the last state (picture it as the last element in the array) therefore your forward button will always be disabled.

The reason why it was mandatory to introduce the loop variable is because you can have a scenario where you go back to a certain page and the pushState code occurs which creates the last history element and instead going back again you choose to click on some link again and again go back the previous page which now creates an additional history element. In other words, you have something like this:

[page1, page2, page2, page2]

now, once on page2 (index 3 element) and you click the back button again you will get to the page2 again index 1 element and you do not want that. Remember that you can have an array of x page2 elements hence the loop false variable was introduced to resolve that particular case, with it you jump all the way from page2 to page 1 no matter how many page2 elements are their in the array.

Geyser answered 23/6, 2018 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.