Dynamic Segments

`: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.

4 min read Level 2/5 #ember#routing#params
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.

Nested Routes →