Hashbang URLs using Ember.js
Asked Answered
K

2

15

I am trying to set up my Router to use "hashbang" URLs (#!).

I tried this, but obviously it doesn't work:

App.Router.map(function() {
    this.route("index", { path: "!/" });
    this.route("otherState", { path: "!/otherState" });
});

Is this possible to do in Ember?

Kaunas answered 18/2, 2013 at 3:47 Comment(1)
I managed to get this to work by overwriting the Ember.HashLocation property to add some '!'s to several strings. I'm not entirely sure if this will end up breaking anything. If no one post a more legit way of doing this, I will add my code as an answer.Kaunas
K
19

Teddy Zeenny's answer is mostly correct, and registerImplementation seems to be a clean way to implement this. I tried to just edit his answer to make it fully answer the question, but my edit got rejected.

Anyway here is the full code to make Ember use hashbang URLs:

(function() {

var get = Ember.get, set = Ember.set;

Ember.Location.registerImplementation('hashbang', Ember.HashLocation.extend({ 

    getURL: function() {
        return get(this, 'location').hash.substr(2);
    },

    setURL: function(path) {
        get(this, 'location').hash = "!"+path;
        set(this, 'lastSetURL', "!"+path);
    },

    onUpdateURL: function(callback) {
        var self = this;
        var guid = Ember.guidFor(this);

        Ember.$(window).bind('hashchange.ember-location-'+guid, function() {
                Ember.run(function() {
                    var path = location.hash.substr(2);
                    if (get(self, 'lastSetURL') === path) { return; }

                    set(self, 'lastSetURL', null);

                    callback(location.hash.substr(2));
                });
        });
    },

    formatURL: function(url) {
        return '#!'+url;
    }

}));

})();

Then once you create your app you need to change the router to utilize the "hashbang" location implementation:

App.Router.reopen({
    location: 'hashbang'
})
Kaunas answered 18/2, 2013 at 23:59 Comment(4)
Great just a few comments: - It's better to reopen App.Router instead of Ember.Router (So you keep ember defaults clean, especially if you're testing) - You don't need to overwrite init and willDestroy since you are extending HashLocation, these functions will be inherited and the code would be simpler.Arhna
Thanks. I changed what you said.Kaunas
This method works perfectly but in last ember throws a deprecation message; what do we have to do to use this without using deprecated code?Curr
Just in case anyone was unaware, Google can also crawl sites that use HTML5 pushState rather than the hash-bang method. Here it is from the horse's mouth: youtube.com/watch?v=yiAF9VdvRPw Here is the Ember doc on using it: emberjs.com/api/classes/Ember.Location.html#toc_historylocationKaunas
A
10

Extending Ember.HashLocation would be the way to go.

For a clean implementation, you can do the following.

Ember.Location.registerImplementation('hashbang', Ember.HashLocation.extend({
  // overwrite what you need, for example:
  formatURL: function(url) {
    return '#!' + url;
  }
  // you'll also need to overwrite setURL, getURL, onUpdateURL...
})

Then instruct your App Router to use your custom implementation for location management:

App.Router.reopen({
  location: 'hashbang'
})
Arhna answered 18/2, 2013 at 10:7 Comment(2)
Good answer. I wasn't using registerImplementation in the solution I had. That definitely makes it cleaner. I edited your answer to include the full code to make this work, as there are several other changes that have to be made other than the one in formatURLKaunas
For some reason my edit to your answer got rejected. Not sure what the deal is. Anyway, I just posted my own answer with the code to fully implement the hashbang URL functionality.Kaunas

© 2022 - 2024 — McMap. All rights reserved.