Skip to content

Instantly share code, notes, and snippets.

@gordonkristan
Last active May 11, 2018 21:53
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gordonkristan/7a6eed365048236428ef to your computer and use it in GitHub Desktop.
Save gordonkristan/7a6eed365048236428ef to your computer and use it in GitHub Desktop.
Ember.js Optional Route Parameters

Ember.js Optional Route Parameters

A topic that comes up quite often in Ember.js discussion forums is optional route parameters. Unfortunately for those who have this problem, there's no built-in way to achieve this functionality. But there is a very nice little hack that will emulate optional route parameters for most sitautions. The actual method is pretty simple, it just requires combining a few tricks. I'll describe the high-level deatils here, and you can find working example code below.

What's needed to pull this off:

  1. You'll need a resource with a sub-route. The sub-route is the 'real' route that you're going to use. All of your logic should be declared in the controller and template for this route. (Also remember that using a resource generates an implicit index route.)
  2. The implicit index route is where you should redirect to if you have no model to provide. It's also where you end up if you go to a URL without providing the parameter. This route immediately redirects to your other sub-route using null as the model. (Do not use undefined, Ember will work differently if you do.)
  3. The sub-route that has all of the logic has a check in the model hook to return a null model if there was no route parameter provided.
  4. The sub-route that has all of the logic also overrides the serialize hook. It checks for an empty model and puts an empty string in the URL instead of putting undefined in the URL.

That's really all there is to it. Just know that if you need to go to your page without a model, send the user to the index route. If you have a model, transition to the other sub-route (the id sub-route in our case). You shouldn't have to do anything with the index sub-route except redirect to the other sub-route.

Note: For those of you using Ember CLI, I've made comments showing which files these classes belong in.

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/x-handlebars" data-template-name="user/id">
{{#if model}}
You got here using a valid ID: {{model.id}}
{{else}}
You got here without providing an ID
<br>
Notice that the route parameter in the URL is empty, not 'undefined'
{{/if}}
<br><br>
Feel free to change the ID in the URL (or eliminate it) to see the code in action
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://builds.emberjs.com/tags/v1.11.0/ember-template-compiler.js"></script>
<script src="http://builds.emberjs.com/tags/v1.11.0/ember.debug.js"></script>
<script src="index.js"></script>
</body>
</html>
// app.js
var App = window.App = Ember.Application.create();
// router.js
App.Router.map(function() {
this.resource('user', function() {
// implicit 'index' route defined by Ember
this.route('id', { path: '/:user_id' });
});
});
// routes/index.js
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('user');
}
});
// routes/user/index.js
App.UserIndexRoute = Ember.Route.extend({
redirect: function() {
// You need the `null` here (don't use `undefined`)
// Ember will check the number of models you pass in
this.transitionTo('user.id', null);
}
});
// routes/user/id.js
App.UserIdRoute = Ember.Route.extend({
model: function(params, transition) {
// This path is for when no parameter is supplied
if (!params.user_id) {
return null;
}
// This is for when there is a valid parameter
// Do with the parameter whatever you need
// Probably an Ember-Data call here
// return this.store.find('user', params.user_id');
return { id: params.user_id };
},
serialize: function(model, params) {
// If we got here without an ID (and therefore without a model)
// Ensure that we leave the route param in the URL blank (not 'undefined')
if (!model) {
return { user_id: '' };
}
// Otherwise, let Ember handle it as usual
return this._super.apply(this, arguments);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment