Things I wish someone had told me when I was learning Ember.js

WhiteBoardOrig

This article is really old and shouldn’t be used anymore. Check out the ember guides instead.

  1. Learn the nuances between a route and a resource.  A resource is a definition of a thing. a route is something that thing can do. Nesting resources just means that you may have a dependency or parent / child relationship.
  2. If something doesn’t need to interact with any other controller, view, or component, it should be a component to maintain your sanity.
  3. Make a /packages/ directory, one for each namespace.  Grouping files by name helps enforce the naming conventions that are all over the place.  Do the same with your sources.  e.g; /packages/application/applicationRoute.js
  4. follow the [namespace][Type] naming convention, so that you can super+p any file by typing it’s namespace. e.g; /packages/application/applicationView.js.  The only exceptions are components due to limitations of the framework. (expects a components folder and a templates/components folder).
  5. Don’t use AMD, CJS, or browserify.  This forces you to work within the conventions of the framework, as all references to other namespaces are available within your declarations in nearly all scenarios (controllers can use needs: [], route actions bubble, view’s have ViewTargetActionSupport mixins available, etc.)  I personally use grunt-neuter.
  6. Think declaratively and reactively about how you want your logic to flow.  An example of this would be defining a ‘currentIndex’ property, and binding to when that index changes via observers or computed properties.
  7. Avoid pub/sub and Ember.Evented as much as you can.  It’s tempting to go the easy route with pub/sub to communicate with other components.  It’s almost universally a bad idea to do this, since there are so many ways to communicate with other parts of your application.
  8. avoid any logic within your templates.  They should be focused strictly on presentation.  Create computed properties on your controllers for defining the state of a view, and use those in if statements if you absolutely must.
  9. don’t use the {{each}} syntactic sugar.  use {{each foo in object}}.
  10. Long names are okay.  You shouldn’t be worried about using computedCurrentIndex vs idx in your definitions.  Think of the other developers who might someday look at this.  Do be that guy who tries to save a few bytes in javascript because they want to eliminate characters.  If you’re not using Uglify already in your grunt toolchain, What the hell is wrong with you?
  11. Treat your javascript as annotated source code, rather than something that gets interpreted.  What gets spit out of uglify doesn’t really impact any of your compiled code; go hog wild.
  12. components are effectively a controller, view, and template without a specific route.
  13. learn how to use the {{render}}, {{#view}} and {{view}} handlebars helpers.   {{render}} is invaluable for partials that may or may not need state. {{#view}} lets you define a yield block in your template or define it inline if need be.   {{view}} can be used for any self contained views you may need to otherwise {{render}} as a partial.
  14. Avoid Ember.Containeras much as you can.  If something cannot be accurately represented within an Ember.Object, try again.  The API is ugly and frankly Ember.Objects give you just about all of the value of them, short of their singleton-like nature (which you can manage with an IIFE and an instance if you must).
  15. this.send('someActionName') within the context of an any controller or route will trigger that action on the controller first, and will bubble.  Use this to your advantage wherever possible.  Need to communicate with routes to a parent of your own? this.send('action') all day long.  Need to be able to override actions in a specific controller or route? just return false from the route, or return true to continue propagation.
  16. jQuery events, short of very specific events or library integrations, should be eliminated in favor or route/controller actions, or handled by a view directly.  This will save you from having to fight the framework later on when you start running into edge cases, dangling references, or worse; zombie events.
  17. Initializers are to be abused whenever possible.  Use them with aplomb. App.Initializer('namespace', initialize: function () {}); – learn what App.delayReadiness() and App.advanceReadiness() are (iOS developer? this is a retain/release cycle for your application’s boot up.  once the retain cycle hits zero, your app is going to start up. Want fixtures? Load them via an initializer and inject them into an Ember.Namespace).
  18. Mixins are great for abstracting common things.  The easiest example would be defining a keyboard event as a mixin, then just executing methods on a “keystrokes” hash in your mixed-in class.   Voila- now every controller or route or what have you can support specific keyboard combinations.   Need to handle pagination? make a consistent mixin api and use it across the application. These are the towels that make you DRY. (groan)
  19. if you find yourself using this._super() pretty much anywhere other than in route.init() or controller.init(), ask yourself long and hard if that inheritance chain can’t be handled in a mixin.  You can probably refactor that for the sanity of everyone.
  20. within the context of a route you can access methods such as this.modelFor('namespace') or this.controllerFor('namespace').  If those elements are currently active, they will return their models or controllers.  Don’t make extra http requests if you can avoid it.
  21. make sure that within a route’s setupController hook, that you set the model on the controller before doing ANYTHING else in that hook. e.g; controller.set('model', model);.  Nothing else will work and it’ll throw an error otherwise. You may see model and content interchangeably used. Use model, not content, it’s getting depreciated.
  22. when you define a resource within your router, you’ll get route.index, route.error, route.loading routes for free, regardless of if you define them (you ought to, especially index).
  23. resources defined in your router have two layers; the base resource (defined as whatever your namespace is + route, controller, or view.) will be loaded FIRST, and then any sub-routes of that resource are loaded.  This means that an App.FooRoute, App.FooController, and App.FooView are loaded before App.FooIndexRoute and App.FooIndexController are set up.  use this.modelFor('foo') to grab the parent’s model if you need data.  Your separation of concerns here is that you want to have the parent resource manage it’s model, and any routes defined under it take care of performing actions with that model.  This one took me ages.
  24. Need to handle view transitions, in the visual sense?  Define a mixin that implements two methods: didInsertElement (be sure to call this._super()!), which in turn calls didAppear.  Each view’s didAppear hook can then set up any transitional properties necessary to animate the view appearing.
  25. in the vast majority of cases, you’ll be binding a lot of classes.  learn the semantics of the {{bind-attr}} helper when it relates to classes.
  26. figure out a good way to bind properties to inline-styles.  You may balk at this, but what do you think jquery.transit, TWEEN, and jquery.animate() do?  now imagine you could databind to those animation flags, using rAF.  https://github.com/yderidde/bindstyle-ember-helper
  27. when using a component in a template, remember that the assignment is {{my-component INTERNAL_BINDING=EXTERNAL_BINDING}}.  Don’t be afraid to pass in an entire controller’s context if that component is complex.
  28. on that note, don’t be afraid to nest components into one another.  There’s no reason why you shouldn’t do that.

 

This list is by no means exhaustive, but it’s a good starting point of little tricks i’ve picked up along the way. Have one to add? leave a comment or ping me on twitter @landongn