5

I'm using document.open() + write() + close() to create a new page from the client. This works, but it will replace the current history element with the new page, so when the user clicks back they don't see the page they were just on. Example:

  1. At Home Page
  2. Click button to navigate to page shown below.
  3. Click on the click me button on that page.
  4. Click back - this returns user to home page which I don't want.

I've tried inserting a history element with history.pushState() but that doesn't work either. It allows the document.open page to have a new url. Clicking back returns the user to the URL of the page I want displayed, but it is still the "New Page".

Full HTML page code below. This type of example doesn't work in fiddles but can be tested locally.

<html>
<body>
<button onclick="clickme()">Click me</button>
<script>
function clickme() {
    history.pushState(null, null, "Results/");
    document.open("text/html");
    document.writeln("New Page");
    document.close();
}
</script>
</body>
</html>

Note: Looking for a solution with cross browser support, including the latest Chrome 45 which may has tightened security a bit.

Mike
  • 335
  • 4
  • 20

4 Answers4

2

I did find a workaround but still not exactly what I want.

function clickme() {
    results = window.open();
    results.document.writeln("New Page");
    results.document.close();
}

This obviously makes an entire new tab/window to display the results instead of a new page in the history of the current tab. It is pretty much the same thing in a cell phone since back takes you to the original page, but not on a desktop browser.

Mike
  • 335
  • 4
  • 20
1

I would create an actual web page for page 3 instead of pushing fake history events.

history.pushState isn't supported in older IE's (9 and below) and is buggy on some Androids, this may not be an issue for your project. http://caniuse.com/#search=history.pushState

If you can't change the back end to redirect to page 3, you could do this in javascript:

  1. save your html in localStorage
  2. redirect to page 3
  3. insert your html when page 3 loads.

page 2:

 function clickme() {
    var html = 'my generated html';
    localStorage.savedHtml = html;
    window.location = 'page3.htm';
 }

page 3:

<html>
<head>
    <!-- I'm assuming you're using jquery -->
    <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
<div id="restoredHtml"></div>
<script>
    $(function(){
        var savedHtml = localStorage.savedHtml || 'No html to restore';   
        $('#restoredHtml').html(savedHtml);
        localStorage.removeItem('savedHtml');
    });
</script>
</body>
</html>
ProgrammerGuy
  • 439
  • 3
  • 15
  • Thanks. I will try this. – Mike Sep 10 '15 at 23:02
  • Yes this does work. Thanks. It relies on local storage, but I can use my backup plan of a new tab if local storage not supported, and this method to detect if it is: http://stackoverflow.com/questions/11214404/how-to-detect-if-browser-supports-html5-local-storage – Mike Sep 12 '15 at 18:16
  • Note: Reason for not creating a real page is that the javascript generated web page was performing lots of math that I didn't feel like porting to the backend. There are thousands of lines of javascript across many pages that use this method. All pages are ~20 years old originally hosted by GeoCities when I couldn't really submit a form. – Mike Sep 12 '15 at 18:19
  • That's a good reason to not do something, time is a precious resource. :)Good idea to check for localStorage support and use the popup method as a fallback. – ProgrammerGuy Sep 12 '15 at 23:39
0

You can store a string object on pushState and than read back the object value so you can construct a page from that value instead of the browser stream.

So first we add a new element with pushState()

var markup = "New page content";
history.pushState( { pageContent : markup } , null, "Results/");
document.open("text/html");
//Write the markup using document object
document.writeln(markup);
document.close();

Than you can attach a listener on onpopstate event and check if state has pageContent, and if it has than construct the document from that :

window.onpopstate = function(event) {

  if(event.state.hasOwnProperty("pageContent")){
        document.open("text/html");
        //Write the markup using document object
        document.writeln(event.state.pageContent);
        document.close();
  }
};
Rosmarine Popcorn
  • 10,761
  • 11
  • 59
  • 89
  • Still trying this. In Chrome, I can only get the onpopstate event to fire if the javascript even is part of markup. – Mike Sep 07 '15 at 20:37
  • @Mike can you be more specific about the issue ? – Rosmarine Popcorn Sep 08 '15 at 13:32
  • To recap, user is on page 1. The click a link to go to page 2 which is a form. They fill out the form and click a button which triggers some calculation and then generates a new page 3 using document.open/writeln/close. This all works fine. Using history.pushState() I can make it seem like this generated page 3 has a real URL with its own entry in history. But on Chrome when the user clicks back from page 3 they are on page 2 on the history stack, but they still see the contents of page 3 - the page I generated using document.writeln. If I put a onpopstate event on page 2, it doesn't fire. – Mike Sep 09 '15 at 15:10
0

Is there a specific reason that you need to use document.open, document.write and document.close? Wouldn't it be easier to keep a single page that can maintain the state, and swap the markup in and out?

The following code will let you use the forward and back buttons in Chrome:

<body>
  <div id="content-area">
  </div>
  <button onclick="clickme()">Change Page</button>
<script>
    var state = 1;
    function changeContent(state) {
        var contentArea = document.getElementById("content-area");
        contentArea.innerHTML = "Page " + state;
    }
    function clickme() {
        state = state+1;
        history.pushState(state, null, "/Page" + state + "/");
        changeContent(state);
    }
    window.onpopstate = function(event) {
        if (event.state != null) {
            state = event.state;
        } else {
            state = 1;
        }
        changeContent(state);
    };
    changeContent(state);
</script>
</body>
brenzy
  • 1,976
  • 11
  • 20