Livsey.org

Musings on Technology & Startup Life

Breaking Up Your Routes in Ember.js

The router is the core of any Ember.js application and it can get big, fast. Keeping your entire application’s router in one file is going to lead to madness. Thankfully it’s quite a simple problem to resolve.

Lets imagine an application with a number of discrete sections - a blog, a list of members and an area to browse uploaded files. We have an init.js which sets up the application:

init.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  // ...

  App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
      home: Ember.Route.extend({
        route: "/"
      }),
      blog: Ember.Route.extend({
        route: "/blog",
        posts: Ember.Route.extend({
          route: "/"
        }),
        post: Ember.Route.extend({
          route: "/:id",
        })
      }),
      members: Ember.Route.extend({
        route: "/members",
        list: Ember.Route.extend({
          route: "/"
        }),
        member: Ember.Route.extend({
          route: "/:id"
        })
      }),
      files: Ember.Route.extend({
        route: "/files",
        list: Ember.Route.extend({
          route: "/"
        }),
        file: Ember.Route.extend({
          route: "/:id"
        })
      })
    })
  })

  // ...

Looks pretty straightforward, but that’s without any outlet management, serializing/deserializing, action handlers etc…

Breaking this up is pretty simple. Anywhere we say Ember.Route.extend we’re defining an anonymous class, so in order to split up the router we can just give the class a name and move it to a file of its own.

routes/homepage.js
1
2
3
  App.HomePageRoutes = Ember.Route.extend({
    route: "/"
  });
routes/blog.js
1
2
3
4
5
6
7
8
9
  App.BlogRoutes = Ember.Route.extend({
    route: "/blog",
    posts: Ember.Route.extend({
      route: "/"
    }),
    post: Ember.Route.extend({
      route: "/:id",
    })
  });
routes/members.js
1
2
3
4
5
6
7
8
9
  App.MembersRoutes = Ember.Route.extend({
    route: "/members",
    list: Ember.Route.extend({
      route: "/"
    }),
    member: Ember.Route.extend({
      route: "/:id"
    })
  });
routes/files.js
1
2
3
4
5
6
7
8
9
  App.FilesRoutes = Ember.Route.extend({
    route: "/files",
    list: Ember.Route.extend({
      route: "/"
    }),
    file: Ember.Route.extend({
      route: "/:id"
    })
  });

Now our main router definition looks like:

init.js
1
2
3
4
5
6
7
8
  App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
      home: App.HomePageRoutes,
      blog: App.BlogRoutes,
      members: App.MembersRoutes,
      files: App.FilesRoutes
    })
  })

Clean, simple and everything in its own place.

Update: As Jo Liss points out, you can specify the base route when you assemble the router as opposed to hard coding it in each section. I really like this, feels very similar to how engines are mounted in Rails.

init.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
      home: App.HomePageRoutes.extend({
        route: "/"
      }),
      blog: App.BlogRoutes.extend({
        route: "/blog"
      }),
      members: App.MembersRoutes.extend({
        route: "/members"
      }),
      files: App.FilesRoutes.extend({
        route: "/files"
      }),
    })
  })

Comments