Ember.js - Tips I didn't learn from the docs

Ember.js - Tips I didn't learn from the docs

Given at EmberNYC 10/30

0a3a4e125aba1e3e86d45ff6f708f203?s=128

Katie Gengler

October 31, 2014
Tweet

Transcript

  1. Tips the docs didn’t teach me ! (but maybe I

    just didn’t read carefully enough)
  2. @katiegengler FundingGates

  3. pauseTest test( "header links to customer index", function () {

    visit( '/' ); click( '.spec-customer-index-link' ); ! return pauseTest(); //return keeps the rest of the test from running andThen(function () { equal( currentPath(), "customers" ); }); });
  4. Ember.Test.registerHelper( 'pauseTest', function () { stop() //keeps QUnit from continuing

    return new Ember.RSVP.Promise(function(){ }); }); Included in Ember for versions > 1.9 canary Can register it yourself until then: Demo: http://emberjs.jsbin.com/zatuqixuci/16/edit?html,js,output
  5. catch/finally var post = store.createRecord('post', { title: 'Rails is Omakase',

    body: 'Lorem ipsum' }); ! var self = this; ! var onSuccess = function(post) { self.transitionToRoute('posts.show', post); }; ! var onFail = function(post) { // deal with the failure here }; ! post.save().then(onSuccess, onFail); This example comes from the Ember.js guides
  6. var post = store.createRecord('post', { title: 'Rails is Omakase', body:

    'Lorem ipsum' }); ! var self = this; ! var onSuccess = function(post) { self.transitionToRoute('posts.show', post); }; ! var onFail = function(post) { // deal with the failure here }; ! post.save().then(onSuccess).catch(onFail); Using catch instead will handle failures not just in the save, but ones that happen in the success handler too.
  7. var post = store.createRecord('post', { title: 'Rails is Omakase', body:

    'Lorem ipsum' }); ! var self = this; self.send(‘showSpinner’); var onSuccess = function(post) { self.transitionToRoute('posts.show', post); self.send(‘hideSpinner’); }; ! var onFail = function(post) { // deal with the failure here self.send(‘hideSpinner’); }; ! post.save().then(onSuccess).catch(onFail); Duplication is bad.
  8. var post = store.createRecord('post', { title: 'Rails is Omakase', body:

    'Lorem ipsum' }); ! var self = this; self.send(‘showSpinner’); var onSuccess = function(post) { self.transitionToRoute('posts.show', post); }; ! var onFail = function(post) { // deal with the failure here }; ! var cleanUp = function() { self.send(‘hideSpinner’); }; ! post.save().then(onSuccess).catch(onFail).finally(cleanUp); Cleaned up with cleanUp
  9. Don’t do this {{#each invoices}} {{name}} {{#if ../isEditing}} <a>Remove</a> {{/if}}

    {{/each}}
  10. Do this instead {{#each invoice in invoices}} {{invoice.name}} {{#if isEditing}}

    <a>Remove</a> {{/if}} {{/each}}
  11. Override init export default Ember.Controller.extend({ setDefaultFilter: function(){ this.set(‘defaultFilter’, ‘name’); }).on(‘init’)

    }); I thought this syntax was nicer, but it has subtly different behavior than doing this in an overridden init. Anything set here will fire watchers.
  12. export default Ember.Controller.extend({ init: function(){ this._super(); this.set(‘defaultFilter’, ‘name’); } });

    Overriding init is preferable for initializing things, but remember to call this._super();
  13. Unwrap service/controller //curentUser initializer export default { name: 'currentUser', !

    initialize: function (container, application) { application.inject('controller', 'currentUser', 'service:current-user'); application.inject('route', 'currentUser', 'service:current-user'); } }; var reminder = this.store.createRecord( 'reminder' ); reminder.setProperties({ customer: customer, contactName: customer.get( 'contactFullName' ), sentTo: customer.get( 'email' ), user: this.get( 'currentUser.model' ) }); If using a controller/ service to contain, say, currentUser, you need to unwrap the model from the controller to set it on a relationship w/ ember-data
  14. Prep for the future Avoid referencing globals ! var equal

    = Ember.computed.equal; ! Ember.Controller.extend(function(){ isACat: equal(‘animalType’, ‘Cat’); }); ! Also remove globals from templates This looks prettier too. In prep for the day you can import equal from Ember.computed.equal;
  15. Prep for the future Add .readOnly to computedProperties that are

    don’t have explicit setters ! Ember.Controller.extend(function(){ isACat: function(){ return this.get(‘animalType’) == ‘Cat’; }).property(‘animalType’).readOnly() }); If you set a computed property that does not have an explicit setter, you wipe out the computed property. Calling readOnly() on properties that are readOnly can prevent debugging pain.
  16. Don’t cause objects to be instantiated before their time Ember.Application.initializer({

    name: 'currentUser', ! initialize: function ( container, application ) { var store = container.lookup( 'store:main' ); var userMeta = $( "meta[name='fg-user']" ).attr( 'content' ); var attributes = JSON.parse( userMeta ); var currentUserId = attributes.user.id; if ( attributes ) { store.pushPayload( 'user', attributes ); ! var user = store.getById( 'user', currentUserId ); application.register( 'user:current', user, { instantiate: false, singleton: true }); application.inject( 'controller', 'currentUser', 'user:current' ); application.inject( 'route', 'currentUser', 'user:current' ); } ! } }); Looking up the store in the initializer can cause the store to be initialized before it would normally be initialized.
  17. //Application Route export default Ember.Route.extend({ activate: function () { var

    attributes = loadUserFromMeta(); this.store.pushPayload( 'user', attributes ); ! var user = this.store.getById( 'user', attributes.user.id ); this.currentUser.set( 'model', user ); } } //curentUser initializer export default { name: 'currentUser', ! initialize: function (container, application) { application.inject('controller', 'currentUser', 'service:current-user'); application.inject('route', 'currentUser', 'service:current-user'); } }; A way around this — creating a currentUser service and setting the model of it in the activate of the ApplicationRoute
  18. Thanks! @katiegengler or katie@kmg.io