14

Is it possible to change title of the page in the browser history via JavaScript after the page is loaded? Should be cross-browser (of course) and work on browsers that don't support the HTML5 History API, my primary target browser is Chrome.

I've tried a number of approaches, but none of them seem to work reliably. Here is what I've tried last (history.js):

<html>
    <head>
        <title>Standard title</title>
        <script src="https://rawgit.com/browserstate/history.js/master/scripts/bundled-uncompressed/html4%2Bhtml5/native.history.js"></script>
    </head>
    <body>
        <script>
            window.setTimeout(function(){
                document.title = "My custom title";
                History.replaceState({}, "My custom title", window.location.href);
            }, 3000);
        </script>
    </body>
</html>

If I load the history page in Chrom within 3 seconds after page load, I see Standard title, after 3 seconds I get My custom title.

Why I need this: I have a JavaScript-only app (Angular 1) which runs on different environments (dev, test, production). I'd like to display a title like MyApp (<environmentName>), but I don't want to build separate versions of my app per environment. Instead, the app could request the environment info from the backend via AJAX and update the title of the page. All of this works fine (the page title gets updated), but browser history still shows "standard" title.

Is there a way to change title of the page in the browser history as well?

Terry Li
  • 16,870
  • 30
  • 89
  • 134
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Previously I could get it working by just assigning a value to `document.title`. However, I can no longer reproduce the working behavior, and I'm not sure what requirements it depends on. – John Weisz Dec 05 '16 at 17:42
  • 1
    @JohnWhite I've observed that it works or does not depending on WHEN I actually open the history page - before of after the title is said. – lexicore Dec 05 '16 at 17:46
  • Then wouldn't it be automatic if you removed the timeout and let it update the title as soon as the page load ? – Romain Dec 06 '16 at 09:49
  • @RomainFournereau The timeout emulates "we want to change the title at some point of time". – lexicore Dec 06 '16 at 09:53
  • Noted. I guess you'll have to wait for replaceState() to work with title. Otherwise, I guess a more brutal way would be to somehow make a back and then go right back to the page, updating the title. – Romain Dec 06 '16 at 10:00
  • @RomainFournereau It looks like the only reliable approach at the moment is to render the title on the server side. – lexicore Dec 11 '16 at 09:16

6 Answers6

3

Short answer: there seems no way you can keep different title records for the same url in Chrome.

Disclaimer: I just stumbled upon this question and had no prior experience about it. Nonetheless, the question was so clear and interesting that I couldn't help but do some experiment:

First of all, I agree that the history records (i.e., the page titles) shown in the history tab are NOT so reliable (maybe a bug or cache).

So I decide that I will look into the database file for Chrome history, for example, using DB Browser for SQLite.

To my surprise, Chrome history keeps only one version (the latest) of title for each url. And when I do History.replaceState({}, "My custom title", window.location.href);, the title does get updated in the database.

However, @Bekim's method wouldn't change the title in the database.

Terry Li
  • 16,870
  • 30
  • 89
  • 134
  • That's because document.title is a BOM method. All conventional & traditional browsers fully support the convention - and conventions supersede any arbitration standard. The problem is: the chrome wasn't around when the BOM was conceived. Hell even IE and FF are compliant. But chrome is not to blame it doesn't, they simply didn't have that kind of past experience. !But it does reflect in history back, and forward. – Bekim Bacaj Dec 11 '16 at 00:00
2

The issue is that the second parameter to replaceState(), the title parameter, is currently ignored by essentially all implementing browsers. However, the third parameter on pushState, url, is taken into consideration. Unfortunately, it does not work with replaceState (at least not in Chrome or Edge, according to my tests).

With that in mind, from client side, you could use one of the following workarounds, whichever your taste is:

history.pushState({}, "", "my-custom-appendix");
history.pushState({}, "", "#my-custom-appendix");

In Chrome, this will create additional entries with a title like http://myurl/my-custom-appendix or http://myurl/#my-custom-appendix (respectively). I believe this is the closest you can get from the client, and the side effect is that you'll get a new history entry in the browser history -- for every visit to your app, you'll essentially see (in increasing timestamp order):

You'll see the URL as the title even if you have the second parameter set to a non-empty string (at least that's what's happening on my end).


For a more robust approach, you'd need to use a simple server-side preprocessor AFAIK, like PHP.

John Weisz
  • 30,137
  • 13
  • 89
  • 132
1

That's the easiest thing ever

document.title = "My App " +environmentName;

The history will immediately update the new document title.


to be able to test it positively, try following these few steps.

1st Copy paste the following in your console and execute:

name = '{ "location": ["http://stackoverflow.com/questions/12689408/how-can-jquery-window-location-hash-replace","http://stackoverflow.com/questions/12978739/is-there-a-javascript-api-to-browser-history-information-limited-to-current-dom","http://stackoverflow.com/questions/24653265/angular-browser-history-back-without-reload-previous-page"],"title" : ["Page 1", "Page 2", "Page 3"]}';

    document.title = "Where We've Started";

2nd Copy-Paste the following in your console and execute 3 times

nm = JSON.parse(name);
location = nm.location[0]; 

3rd As soon as the location has loaded, execute the following

nm = JSON.parse(name);
document.title = nm.title[0];

each time increasing the array index as in:

location = nm.location[1];
document.title = nm.title[1];

(the max index is 3, e.g. num 2)
Than click and hold the Back Button to reveal the latest History entries, all sane and updated in order to reflect the new document title.

Warning: If the script is not running after you've stepped back to a given history entry the page title will revert as expected to the existing hard-coded doc title. But since this history control names will be fed by the script in all pages they will also continue to reflect the live document titles provided. This is where people get tricked when moving back to the hard-coded page in history. And think: "damn: something went wrong!"

Figure 1.: End Result of the Demo Code executed on a separate / new window. End Result Image

enter image description here

Bekim Bacaj
  • 5,707
  • 2
  • 24
  • 26
  • Hold the line for a second, something is amiss here -- `document.title` _does_ seem to work every now and then, but I'm unsure what decides whether the history entry is actually updated, or the change only takes effect in the browser header. – John Weisz Dec 05 '16 at 17:38
  • I could reproduce the working behavior previously, but not now. If you could explain what's causing this, and how to overcome it, you are likely in for the bounty. – John Weisz Dec 05 '16 at 17:40
  • @JohnWhite - Here, let me update my answer with a postscriptum - not easy, to DEMO it here in stackoverflow environment, but I'll make my best on clear instructions ...bare with me for a few seconds – Bekim Bacaj Dec 05 '16 at 17:40
  • I'm using the exact same snippet (assigning to `document.title`), and without any modifications the updated title showed up in the history previously, but not now. Again, no modifications were done to my code, it just "stopped working" spontaneously. – John Weisz Dec 05 '16 at 17:44
  • @JohnWhite OK I know, the explanation is on my appended explication - it strikes you as spooky and unexpected revert to the old title - but that's because you've reloaded the page as is without script modification and the document title gets immediately updated to the hardcoded one. – Bekim Bacaj Dec 05 '16 at 18:06
  • Ah, now I understand why I got 5 negative votes in a matter of <5 minutes - they came from bounty hunters - as this question appears to have a bounty. Sorry, I came in to help. – Bekim Bacaj Dec 05 '16 at 19:13
  • @BekimBacaj Ignore the downvotes, it's an unfortunate side effect. – lexicore Dec 05 '16 at 21:00
  • @BekimBacaj Unfortunately I can't confirm setting `document.title` works. Here is an [example](http://output.jsbin.com/cusubamaqo). After 5 seconds `Original Title` is modified to `Modified Title`. History entry stays the same - at least in Chrome. – lexicore Dec 05 '16 at 21:12
  • @lexicore I'm a bit busy right now, but one thing you need to completely drop off from our code is the timer you don't need to wait for nothing, you implement your dynamic change to the document title = history entry as soon as your data are available but not before the onload event has fired on window object. p.s.: the more we learn the more robust and complicated our approach to the problem solution tends to become. – Bekim Bacaj Dec 05 '16 at 21:54
1

Related to angularjs :-

add run method after module :-

.run(function ($rootScope) {

$rootScope.$on('$stateChangeSuccess', function (evt, toState) {
    window.document.title = toState.title + ' - example.com';
});

});

Your state :-

.state('productDetail', {

    title: 'Details of selected product',
    url: '/Detail.html',
    templateUrl: '/product-details.html',
    controller: 'ProductDetailsCtrl'

  })

.state('categoryManager',{

    title: 'Category Manager',
    url: '/category-Manager.html',
    templateUrl: 'categoryManager.html',
    controller: 'categoryManagerCtrl'
   
  });

this will change title according to your state.

Community
  • 1
  • 1
1

Firefox 52. Trivial:

document.title = 'CoolCmd';

Chrome 57 requires some magic. This variant also works for Firefox 52. It does not add unnecessary entries to the browser history.

// HACK Do not change the order of these two lines!
history.replaceState(null, '');
document.title = 'CoolCmd';

MS Edge 14.14393 does not allow to change the title of the document in the history. He even does not add to the history the addresses specified by history.pushState()! LOL

I did not test Safari...

CoolCmd
  • 939
  • 8
  • 13
0

You can use document.write() to write correct title to document in first place while it's still loading. But it would require synchronous request to the server:

<head>
  <script>
  (function () {
    // Get title using sync request.
    var title = "Value from server";
    document.write("<title>"+ title + "</title>");
  })();
  </script>
</head>

Page that include snipped above would appear with "Value from server" title in browser history.

Leonid Vasilev
  • 11,910
  • 4
  • 36
  • 50
  • I really want to avoid a sync request. I've tried this with 3s timeout. This seem to work quite reliably if the title was not set before. However, if the title was already set, it does not get changed in history. This approach seem to have the same effect as setting `document.title`. – lexicore Dec 05 '16 at 18:00