Transitions

Navigate Programmatically With `router.transitionTo`

Transitions

Use the router service to navigate from code — works in routes, components, and services. Pass dynamic segments and query params as needed.

4 min read Level 2/5 #ember#routing#transitions
What you'll learn
  • Inject the router service
  • Call router.transitionTo with a route name
  • Pass dynamic segments and queryParams

<LinkTo> handles 90% of navigation declaratively. For the rest — after form submission, on auth changes, after a delay — use the router service to navigate from code.

Inject the Router Service

// app/components/login-form.js
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { action } from '@ember/object';

export default class LoginForm extends Component {
  @service router;
  @service auth;

  @action
  async submit(event) {
    event.preventDefault();
    await this.auth.login(this.args.email, this.args.password);
    this.router.transitionTo('dashboard');
  }
}

transitionTo accepts a route name (dotted like admin.users), not a URL.

Dynamic Segments

this.router.transitionTo('post', postId);
this.router.transitionTo('comment', postId, commentId);

Pass segments as positional arguments in the order they appear in app/router.js.

Query Params

this.router.transitionTo('posts', {
  queryParams: { page: 2, sort: 'newest' },
});

replaceWith vs transitionTo

this.router.replaceWith('signin');   // no browser history entry
this.router.transitionTo('signin');  // adds a history entry

Use replaceWith for redirects (failed auth, deprecated URLs) so the user’s back button does not return to the broken page.

Aborting a Transition

In a route’s beforeModel:

beforeModel(transition) {
  if (!this.auth.isLoggedIn) {
    transition.abort();
    this.router.transitionTo('signin');
  }
}
Query Parameters →