Skip to content
tmeasday edited this page Sep 18, 2012 · 8 revisions

Meteor Router API

This is a document explaining a potential API for routing in meteor. This may end up making it's way into core or simply remain separate in this smart package.

The idea is to re-write the package without a reliance on backbone, and to set it up in a way that makes more sense in the meteor world and is more in the spirit of other meteor APIs.

Basics

To find the current page:

Meteor.Router.currentPage();

Note that as in the current version of the package, this variable will usually be accessed via the currentPage helper to render a specific variable, as in:

  <!-- this will render the 'news' template in the current example -->
  {{{render currentPage}}}

To define a route:

Meteor.Router.add({
  'news': function () {
    return 'news';
  }
});

When the user browses to /news, the currentPage will be set to whatever this function returns. Note that the function will be called reactively -- i.e. if it checks any reactive dependencies and they change, then it will be re-run and the currentPage variable may change. (Return something falsy to not change the currentPage variable).

To navigate to a page:

Meteor.Router.to('news');

Changes the URL to http://your.host/news and triggers any relevant functions (as if the user had browsed there directly).

Routing paths + variables

The path may contain :variables which will be provided to the routing function; additionally, this and more is available in the the this object:

Meteor.Router.add({
  'posts/:id': function(id) {
     console.log('we are at ' + this.path);
     console.log("we've matched: " + this.matches);
     console.log("our parameters: " + this.parameters);

     Session.set('currentPostId', id);
     return 'showPost';
  }
});

Route filters

After filters

The current system of filtering in this package is the equivalent of an after_filter in rails. A potential API:

Meteor.Router.addFilter({
  'checkLoggedIn': function(page) {
    if (Meteor.user()) {
      if (Meteor.user().loading) {
        return 'loading';
      } else {
        return page;
      }
    } else {
      return 'signin';
    }
  });
})

And to use it, simply provide a set of names to apply it to via only, or not to apply it to with except:

Meteor.Router.filter({
  'checkLoggedIn': {only: ['dashboard', 'newPost', 'newComment']}
});

Before filters

Before filters are more tricky because it's unclear how to apply them. I don't want to think about this too hard until I know whether this is the sort of thing the router should be doing (I feel like it probably has to though because choosing to show loading or 404 is definitely a routing issue).

Meteor.Router.addFilter({
  'waitForData': function(id, collection, routingFn) {
    var object = collection.findOne(id);
    if (object) {
      return routingFn(object);

    // this is a method a collection that doesn't currently exist, but maybe should
    } else if (collection.loading()) {
      return 'loading';
    } else {
      return '404';
    }
  }
});

Mapping objects/models to routes.

To make it simple to get the URL that corresponds to an object:

Meteor.Router.map({
  "post": function(post) {
    return "posts/" + post._id;
  }
});

And to use it

// returns 'posts/7' for instance
Meteor.Router.for("posts", post);

Or directly:

// takes us to 'posts/7' right now
Meteor.Router.to("posts", post);

Connecting, rails style

Taking this idea even further, we could define

Meteor.Router.connect('posts', Posts, function(post) {
  return {'showPost', post};
});

Which could potentially take care of setting up a map from simple posts to posts/:id, and a routing function which pulls the relevant post from the Posts collection (probably using something like the waitForData filter above). Unsure about if this is a good idea.