`:id` in the Path, Param in `model()`
Dynamic Segments
A path segment prefixed with a colon becomes a route parameter — receive it in the model hook and load the matching record.
What you'll learn
- Declare a path with a colon parameter
- Read params in model()
- Type the params in TypeScript
A dynamic segment is a URL slot whose value comes from the user — /posts/42, /users/abc. Declare it with a colon in the path.
Declare a Dynamic Segment
// app/router.js
Router.map(function () {
this.route('post', { path: '/posts/:post_id' });
}); :post_id is the parameter name. You can name it whatever you want — but it ends up as a key on the params object.
Receive It in model()
// app/routes/post.js
import Route from '@ember/routing/route';
import { service } from '@ember/service';
export default class PostRoute extends Route {
@service store;
async model(params) {
return this.store.findRecord('post', params.post_id);
}
} If the record load fails, Ember bubbles to the nearest error substate (covered later).
Multiple Segments
this.route('comment', {
path: '/posts/:post_id/comments/:comment_id',
}); async model(params) {
const post = await this.store.findRecord('post', params.post_id);
const comment = await this.store.findRecord('comment', params.comment_id);
return { post, comment };
} Typed Params
// app/routes/post.ts
import Route from '@ember/routing/route';
interface Params {
post_id: string;
}
export default class PostRoute extends Route {
async model(params: Params) {
return this.store.findRecord('post', params.post_id);
}
} Note: URL segments arrive as strings. Coerce to a number with Number(params.post_id) if needed.