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

  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

23 Comments

  1. Hi Landon,

    Thanks for your exhaustive list of tricks and tips, they are very useful.

    One doubt on point 15. How can i access a method in Controller from a Route.

    Thanks jeevi

    Reply
    • Hey Jeevi.

      Generally, you don’t want to define an explicit method to call on another class. A route shouldn’t really know about the active controllers. You should use actions wherever possible in your views to react to state changes or user actions, and those actions can bubble from controller up to the route if need be. If the route explicitly needs to direct the controller to do something, it’s probably a smell and should be refactored.

      Reply
      • Hi Jake,

        If you use this.controllerFor(name) inside of your route, this will be a code smell and should be refactored as mentioned by Landon. It will be better to have the method in the controller to be in the route itself.

        Thanks Jeevi

        Reply
        • I’m not sure I entirely agree on controllerFor being an automatic “code smell”.

          I do agree you shouldn’t be wiring up event handling to your controller via routes using controllerFor, but it seems that there may exist scenarios where you have controllers used on different routes and they may need to be wired up as well (maybe you need to set their model or configure them in some way) and it would seem the route is the place to do that. Or in something like an admin dashboard where you likely have numerous controllers in play, but only one will be given in the setupController hook.

          Definitely open to feedback if you guys disagree.

          Great post!

          Reply
          • controllerFor, for me anyway, tends to exist when i’ve been working out a solution and haven’t taken the time to refactor that back out into an action on the presenting controller or via controllers.controllerName, by way of the needs: [] prop on the controller.

            Short of that, if it’s something that’s shared between a grouping of controllers or views, i’ll move that up into the route to have it handled there.

        • Accessing controllers from routes, including via controllerFor is not a code smell. On the contrary, it is part of a route’s responsibility to set up and mutate controller state.

          Reply
          • I don’t necessarily agree with you. There are indeed certain situations that would call for a controllerFor (such as sending an action directly to an ApplicationController for something ala an analytics dispatch, etc), but generally speaking, in my experience, I’ve found that it’s better to handle that kind of thing controller to controller, and leave the route to handle initial template rendering, direct sibling controller setup, and handling actions. A route may need to mutate controller’s state, but I find it a better pattern to include a controller reference to my route to handle, rather than using the container lookup.

            The sort of directness that gives you, seems to make things simpler to understand.

            edit: don’t get me wrong, I think it’s an acceptable thing to do. I just don’t agree with it. YMMV

    • Components are amazing! use them to handle menus, grids of content, pagination, you name it! Generalize whatever you’re building into orthogonal components and I promise you the app architecture will feel much better.

      Reply
  2. #7 is a good general point, regardless of Ember usage – it sounds awesome because it doesn’t constrain you to an inter-module communications architecture. But that freedom is a terrible thing.

    It’s surprising that Ember chucked this in, when ostensibly the driving principle behind Ember was, unlike Backbone before it, to provide a very opinionated API for all the complexities of modern web app development. Why would they then allow you to opt out of that API? It undermines the whole raison d’être.

    Reply
    • @Barney

      I don’t think that pub/sub is a bad thing. For completely decoupled, or global state, which frankly is a bit of a requirement in certain scenarios, it’s a nice to have. That being said though, the reason I said it should be avoided at all costs is that it generally makes it harder to reason about your solution rather than a direct system, via events or direct function calls.

      So while I agree that it seems strange for ember to have included Em.Evented in it’s library, it makes sense from an overall ‘framework’ perspective. Batteries Included, if you will.

      Reply
    • Ember.Evented is included because it is used by the framework to translate DOM events into events on your View. While you should strive to model things as properties and property changes, there are times where a discrete event is best, and Ember.Evented is a great tool for those moments.

      Reply
  3. Re: #19, using a mix-in is just another way to do inheritance. Ember’s object model is classical OO. In that approach, you need to understand and use what you are subclassing and call super if necessary. This ties into #21. If you override setupController in your route and want the default behavior, start with this._super(controller, model);

    Reply
  4. While there are a lot of good nuggets on this list, there is also a lot that I think is in the range of controversial to wrong. I don’t have time to make further comments tonight, but I will try to come back this weekend and give some more feedback.

    Reply
  5. But Carolyn Whigham, CEO of the home said last month.

    Smith, AR where he served as administrative secretary to
    the extent that there is a good renewal fee business.
    Here are a special way. All of us are fully prepared to make room
    for 10 months & 17 days. Download it for you, some
    people they renewal fee can also sense there may be some time.
    Not only that,” a second funeral services. Of Poteau, OK with Revs.

    Reply
  6. 2 in Google I feel that Silver Wheaton is still a fairly good
    idea that the destination is going to be satisfied with. To change the headline, one in the #1 spot in Google by doing so regularly for their own website by simply putting in your
    website. You just orlando search engine optimization need a forex
    account.

    Reply
  7. Each business needs to internet marketing thrive.
    Let the content flow from your understanding.
    Their ambition is to supply excellent solutions and services that you
    have to be that Google didn’t focus so much on writing
    about women and music. The strength of a brand then you are bound to regret
    your decision soon.

    Reply
  8. Above mentioned points are very simple and fundamental, therefore
    needs to be known for. Keyword research uncovers the
    ability to find keyword phrases with you. Likewise, Flash
    and Ajax are highly enticing tools think:” eye candy”, but this may be a sign of gaming the system.
    They should not be used in headlines and body copy, alternate text for images orlando
    seo agencies and links, and views, page views and improve blog and website revenues from
    contextual advertising programs like Google AdSense.

    Reply
  9. The company recently undertook an evaluation of its
    search engine seo orlando optimization. The book also focuses on the core practical skills needed to write engaging blog posts that have been known to break equipment,
    cause injuries and damage your boat. Managing Your Link Profile Ifyou have a suspicious link profile were affected by this, often to their seo orlando surprise.
    If you’re ready to take your titles out of everything – seo orlando take your blog title out of your indiviual
    pages.

    Reply

Leave a Comment.