Detect URL change and grab URL in EmberJS (using Discourse)

I’m using Discourse (http://www.discourse.org/), which is built on EmberJS, and trying to observe any time the URL changes, e.g. when opening a new topic. I’ve seen the answer for observing the currentPath, for example here: Detect route transitions in EmberJS 1.0.0-pre.4

App.ApplicationController = Ember.Controller.extend({

  routeChanged: function(){
    // the currentPath has changed;
  }.observes('currentPath');
});

But I’m trying to detect any URL change, not just a path change. As mentioned in the comments for that answer:

This observer doesn’t fire when transitioning from for example /pages/1 to /pages/2 because the path is staying the same: pages.page.index

What I’d like to do is actually detect those aforementioned transitions which don’t get triggered by observes('currentPath'). Along those lines, if I do this.get('currentPath'); inside of my function, I get something like topic.fromParams but I actually am interested in the URL path e.g. /t/this-is-my-url-slug.

To put it simply, I’d like to detect when the app goes from:

/t/this-is-my-url-slug

to

/t/another-url-slug

and be able to capture the path: /t/another-url-slug

Sorry but I’m a bit of an Ember n00b and my only experience with it is through Discourse. Any ideas?

Solution: Use router.on('routeDidChange', ...)

In Ember (and Discourse), the best way to listen for any URL change is to use the RouterService and its routeDidChange event:

In a Service or Component:

import { inject as service } from '@ember/service';
import Component from '@ember/component';

export default Component.extend({
  router: service(),

  init() {
    this._super(...arguments);

    this.router.on('routeDidChange', (transition) => {
      const newURL = this.router.currentURL;
      console.log('URL changed to:', newURL);
      // You can now do something with the new URL here
    });
  }
});

Why this works:

  • currentPath reflects route names, not URL paths.
  • routeDidChange fires every time the URL changes, even when the route name does not.
  • router.currentURL gives the actual browser URL path you want.

Bonus: In a Discourse Plugin or App

If you’re working within Discourse’s plugin environment:

import { withPluginApi } from 'discourse/lib/plugin-api';

export default {
  name: 'url-change-listener',

  initialize(container) {
    withPluginApi('0.8.13', (api) => {
      const router = container.lookup('router:main');

      router.on('routeDidChange', () => {
        console.log('New Discourse URL:', router.currentURL);
      });
    });
  }
};

You can also compare the previous URL:

let lastURL = null;

this.router.on('routeDidChange', () => {
  const currentURL = this.router.currentURL;
  if (currentURL !== lastURL) {
    console.log(`Changed from ${lastURL} to ${currentURL}`);
    lastURL = currentURL;
  }
});