150

Can any one give a working example for history.replaceState? This is what w3.org says:

history.replaceState(data, title [, url ] )

Updates the current entry in the session history to have the given data, title, and, if provided and not null, URL.


Update

This works perfectly:

history.replaceState( {} , 'foo', '/foo' );

URL is changing, but title is not changing. Is that a bug or am I missing something? Tested on latest Chrome.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Serjas
  • 2,184
  • 4
  • 21
  • 35
  • 3
    I generally don't push add-on libraries for JavaScript questions, but in this case I'll make an exception. The [History.js](https://github.com/balupton/history.js) library is a small shim that cleans up a lot of bizarre misbehavior in the History API across modern browsers. It even provides optional support for old versions of IE. – Pointy Oct 11 '12 at 04:42
  • 2
    MDN has a pretty good writeup on [Manipulating the browser history](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#The_replaceState().C2.A0method) – sachleen Oct 11 '12 at 04:44
  • @Pointy history.js works great. I have updated the code in my question. No my problem is i cant go back to previous page with browser back button – Serjas Oct 11 '12 at 06:26
  • @Pointy i tried this `History.pushState({state:1}, document.title, window.location.href); History.replaceState( {state:2} , title, url );` – Serjas Oct 11 '12 at 06:35
  • Well what I found is that you need to deal with the fact that calling any of those History APIs will *generate* a statechange event. I have my code set a flag on the body element so that the statechange handler knows to ignore those events. – Pointy Oct 11 '12 at 13:55
  • 4
    According to [Mozilla](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#The_pushState().C2.A0method), the `title` parameter isn't actually used. – gen_Eric Oct 16 '12 at 15:00
  • 6
    The first answer really shouldn't be the accepted answer, given the question asks for a `replaceState` example, and the accepted answer is in no way a `replaceState` example. – CorayThan Mar 05 '14 at 21:49

9 Answers9

73

Indeed this is a bug, although intentional for 2 years now. The problem lies with some unclear specs and the complexity when document.title and back/forward are involved.

See bug reference on Webkit and Mozilla. Also Opera on the introduction of History API said it wasn't using the title parameter and probably still doesn't.

Currently the 2nd argument of pushState and replaceState — the title of the history entry — isn't used in Opera's implementation, but may be one day.

Potential solution

The only way I see is to alter the title element and use pushState instead:

document.getElementsByTagName('title')[0].innerHTML = 'bar';
window.history.pushState( {} , 'bar', '/bar' );
Sev
  • 1,982
  • 1
  • 16
  • 27
  • For jquery users.. try $("title").html(_title); – suraj jain Sep 05 '16 at 13:11
  • 3
    this could result in users needing to "double click" the back button depending on how you implement this. A simpler solution might be to keep using ```replaceState()``` and simply set the document title manually ```document.title = "title"``` – newshorts Nov 07 '16 at 18:49
43

Here is a minimal, contrived example.

console.log( window.location.href );  // whatever your current location href is
window.history.replaceState( {} , 'foo', '/foo' );
console.log( window.location.href );  // oh, hey, it replaced the path with /foo

There is more to replaceState() but I don't know what exactly it is that you want to do with it.

Trott
  • 66,479
  • 23
  • 173
  • 212
9

history.pushState pushes the current page state onto the history stack, and changes the URL in the address bar. So, when you go back, that state (the object you passed) are returned to you.

Currently, that is all it does. Any other page action, such as displaying the new page or changing the page title, must be done by you.

The W3C spec you link is just a draft, and browser may implement it differently. Firefox, for example, ignores the title parameter completely.

Here is a simple example of pushState that I use on my website.

(function($){
    // Use AJAX to load the page, and change the title
    function loadPage(sel, p){
        $(sel).load(p + ' #content', function(){
            document.title = $('#pageData').data('title');
        });
    }

    // When a link is clicked, use AJAX to load that page
    // but use pushState to change the URL bar
    $(document).on('click', 'a', function(e){
        e.preventDefault();
        history.pushState({page: this.href}, '', this.href);
        loadPage('#frontPage', this.href);
    });

    // This event is triggered when you visit a page in the history
    // like when yu push the "back" button
    $(window).on('popstate', function(e){
        loadPage('#frontPage', location.pathname);
        console.log(e.originalEvent.state);
    });
}(jQuery));
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • 31
    Why does the accepted answer explain "pushState" instead of "replaceState"? – Giwrgos Tsopanoglou Aug 13 '13 at 11:19
  • 2
    @GiwrgosTsopanoglou: I answered this a year ago, so I'm not sure why :-P Anyway, `replaceState` changes the current page state. It lets you change the state object and URL of the *current* page state. – gen_Eric Aug 13 '13 at 13:00
  • 2
    It was just odd that I was looking for information on replaceState and I ended up reading about pushState :P – Giwrgos Tsopanoglou Aug 13 '13 at 13:03
6

look at the example

window.history.replaceState({
    foo: 'bar'
}, 'Nice URL Title', '/nice_url');

window.onpopstate = function (e) {
    if (typeof e.state == "object" && e.state.foo == "bar") {
        alert("Blah blah blah");
    }
};

window.history.go(-1);

and search location.hash;

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
avalkab
  • 436
  • 3
  • 18
2

The second argument Title does not mean Title of the page - It is more of a definition/information for the state of that page

But we can still change the title using onpopstate event, and passing the title name not from the second argument, but as an attribute from the first parameter passed as object

Reference: http://spoiledmilk.com/blog/html5-changing-the-browser-url-without-refreshing-page/

Mahesh
  • 3,727
  • 1
  • 39
  • 49
2

According to MDN History doc
There is clearly said that second argument is for future used not for now. You are right that second argument is deal with web-page title but currently it's ignored by all major browser.

Firefox currently ignores this parameter, although it may use it in the future. Passing the empty string here should be safe against future changes to the method. Alternatively, you could pass a short title for the state to which you're moving.

Munir
  • 51
  • 1
  • 9
Munir Khakhi
  • 170
  • 10
  • The second argument _does **not**_ refer to the title of the web-page — the MDN doc that you linked says _"pass a short **title for the state** to which you're moving."_. This agrees with the W3C [history interface](http://w3c.github.io/html/browsers.html#the-history-interface) documentation says _"Pushes the given data onto the session history, with the given title,"_. The data in that phrase is the _state_ data, so again the title refers to the state(data). – Stephen P Jul 21 '16 at 20:22
1

I really wanted to respond to @Sev's answer.

Sev is right, there is a bug inside the window.history.replaceState

To fix this simply rewrite the constructor to set the title manually.

var replaceState_tmp = window.history.replaceState.constructor;
window.history.replaceState.constructor = function(obj, title, url){
    var title_ = document.getElementsByTagName('title')[0];
    if(title_ != undefined){
        title_.innerHTML = title;
    }else{
        var title__ = document.createElement('title');
        title__.innerHTML = title;
        var head_ = document.getElementsByTagName('head')[0];
        if(head_ != undefined){
            head_.appendChild(title__);
        }else{
            var head__ = document.createElement('head');
            document.documentElement.appendChild(head__);
            head__.appendChild(title__);
        }
    }
    replaceState_tmp(obj,title, url);
}
THE AMAZING
  • 1,496
  • 2
  • 16
  • 38
0

Suppose https://www.mozilla.org/foo.html executes the following JavaScript:

const stateObj = { foo: 'bar' };

history.pushState(stateObj, '', 'bar.html');

This will cause the URL bar to display https://www.mozilla.org/bar2.html, but won't cause the browser to load bar2.html or even check that bar2.html exists.

Ahish
  • 73
  • 1
  • 7
0

Consider this as URL: http://localhost:4200/inspections/report-details/60c88e4e76b14c00193f5bef

let reportId = '60c88e4e76b14c00193f5bef', scope = "dynamic"

window.history.replaceState(null, null, `inspections/report-details/${reportId}?damagePart=` + scope );

This will yield output http://localhost:4200/inspections/report-details/60c88e4e76b14c00193f5bef?damagePart=dynamic/

IAfanasov
  • 4,775
  • 3
  • 27
  • 42