Kevin Bullaughey
Kevin Bullaughey

Reputation: 2576

Is it possible to hide substates from showing up in the URL when using the Ember Router v2?

I would like to have a route substate not show up in the URL, but still be able to take advantage of having a route class on which I can define renderTemplate, model, setupController, etc. hooks. Is this possible with the v2 router? I am using Ember release candidate 2.

Here's an example.

Suppose I have the routes:

/exercise/:exercise_id
/exercise/:exercise_id/correct
/exercise/:exercise_id/incorrect

I would like all of these to show up in the URL as:

/exercise/:exercise_id

As I don't want the student to just directly type in /correct onto the end of the ULR and get to the correct answer. And although I have a way to prevent that from working, the full route still shows up in the URL. From the student's perspective, I only want them to think about the state as /exercise/:exercise_id.

Of course I could just store the state correct vs. incorrect in some controller variable, but then I loose the convenience of having route classes, ExerciseCorrectRoute and ExerciseIncorrectRoute, which I want to behave differently, and so the hooks, like renderTemplate and setupController, are nice to have defined cleanly in separate places.

Thoughts?

Kevin

UPDATE:

I went with Dan Gebhardt's suggestion because I like to keep things as much as possible within the framework's considered design cases, as this seems to reduce headaches given Ember is still evolving. Also I didn't get a chance to try out inDream's hack.

Although I still think it would be nice if the router added a feature to mask substates from the URL.

Upvotes: 0

Views: 414

Answers (2)

inDream
inDream

Reputation: 1277

You can reference to my answer in Ember.js - Prevent re-render when switching route.

Reopen the location API you're using and set window.suppressUpdateURL to true if you want to handle the state manually.

Ember.HistoryLocation:

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

    Ember.$(window).bind('popstate.ember-location-'+guid, function(e) {
      if(window.suppressUpdateURL)return;
      // Ignore initial page load popstate event in Chrome
      if(!popstateFired) {
        popstateFired = true;
        if (self.getURL() === self._initialUrl) { return; }
      }
      callback(self.getURL());
    });
  }
});

Ember.HashLocation:

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

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

        set(self, 'lastSetURL', null);

        callback(path);
      });
    });
  }
});

Upvotes: 0

Dan Gebhardt
Dan Gebhardt

Reputation: 3281

Every route must be associated with a URL for Ember's current router.

Instead of using multiple routes, I'd recommend that you use conditionals in your exercise template to call the appropriate {{render}} based on the state of the exercise. In this way you can still maintain separate templates and controllers for each state.

Upvotes: 1

Related Questions