Slide 1

Slide 1 text

BUILDING APPS WITH EMBER (A POSTMORTEM)

Slide 2

Slide 2 text

Sean Creeley @screeley [email protected]

Slide 3

Slide 3 text

WHAT WE BUILT

Slide 4

Slide 4 text

Why Ember?

Slide 5

Slide 5 text

No comparing and contrasting.

Slide 6

Slide 6 text

@screeley Angular is faster than Ember, here's the link to prove it: bit.ly/11mNonE @screeley Backbone is 1,500 lines of code, Ember has 27,000. Talk about bloat. @screeley neckbeard, neckbeard, neckbeard. I hate you.

Slide 7

Slide 7 text

@screeley You are a gentleman and a scholar, i <3 you #yolo

Slide 8

Slide 8 text

EMBER INTRO

Slide 9

Slide 9 text

APPLICATION window.Dolphin = Em.Application.create({ rootElement: $('#dolphin'), ready: function(){} });

Slide 10

Slide 10 text

ROUTER Dolphin.Router.map(function() { this.route('about'); this.resource('company', function(){ this.route('team'); }); }); / /about /company /company/team

Slide 11

Slide 11 text

TEMPLATES
{{outlet}}

Welcome to Dolphin!

Helping Dolphins become the smartest species since 2013

application.handlebars index.handlebars

Slide 12

Slide 12 text

MODELS Dolphin.CompanyTeamRoute = Em.Route.extend({ model: function(){ return {name: 'sean'} } });

{{name}}

company/team.handlebars

Slide 13

Slide 13 text

MODELS Dolphin.CompanyTeamRoute = Em.Route.extend({ model: function(){ return [ {name: 'sean'}, {name: 'kawandeep'}, {name: 'andy'}] } });
    {{#each controller}}
  • {{name}}
  • {{/each}}

Slide 14

Slide 14 text

MODELS Dolphin.CompanyTeamRoute = Em.Route.extend({ model: function(){ return Dolphin.User.find({is_team: true}); } });

Slide 15

Slide 15 text

CONTROLLERS Dolphin.CompanyTeamController = Em.ArrayController.extend({ sortAscending: ['years_coding'], totalYears: function(){ return this.reduce(function(total, user) { return total + user.get('years_coding'); }, 0); }.property('@each.years_coding') });

Slide 16

Slide 16 text

VIEWS Dolphin.CompanyTeamView = Em.View.extend({ didInsertElement: function () { // fade images in. this.$().find('img').animate({ opacity: 1 }, 2000); } });

Slide 17

Slide 17 text

ARRAYS var arr = Em.A(["a", null, "b", "c"]); arr.contains("a"); // true arr.compact(); // ["a", “b”, "c"] arr.without("a"); // ["b", "c"] arr.some(function(){}); arr.every(function(){}); arr.map(function(){}) arr.reduce(function(){}, 0) arr.forEach(function(){}) arr.reject(function(){})

Slide 18

Slide 18 text

BUILTINS Ember.isNone Ember.isEmpty Ember.isArray Ember.keys Ember.computed.equal Ember.computed.match Ember.computed.or Ember.without

Slide 19

Slide 19 text

POSTMORTEM

Slide 20

Slide 20 text

#1 Do things the Ember way.

Slide 21

Slide 21 text

#2 Naming Conventions are EVERYTHING

Slide 22

Slide 22 text

/#/about App.AboutRoute App.AboutView App.AboutController about.handlebars

Slide 23

Slide 23 text

#3 Think like Russian Dolls

Slide 24

Slide 24 text

comment post blog

Slide 25

Slide 25 text

this.resource('blog', {path:'/blogs/:blog_id'}, function(){ this.resource('post',{path:'/posts/:post_id'}, function(){ this.route('comment', {path: '/comment/:id'}); }); }); /blog/:id/post/:id/comment/:id

Slide 26

Slide 26 text

application.handlebars blog.handlebars post.handlebars comment.handlebars

Slide 27

Slide 27 text

#4 You will never use “text/x-handlebars”

Slide 28

Slide 28 text

<div> {{outlet}} </div> Em.TEMPLATES['blog'] = Em.Handlebars.compile( '
{{outlet}}
');

Slide 29

Slide 29 text

#5 You needs to use “needs”

Slide 30

Slide 30 text

App.CommentController = Em.ObjectController.extend({ needs:["blog", "post"], postBinding: "controllers.post", blogBinding: "controllers.blog", });

Slide 31

Slide 31 text

#6 jQuery is not the enemy.

Slide 32

Slide 32 text

App.CommentView = Em.View.extend({ template: Em.Handlebars.compile( '{{name}}

{{{body}}}

'), didInsertElement: function(){ this.$().find('p').animate({ opacity: 1 }, 1000); } });

Slide 33

Slide 33 text

#7 Ember Data is like ten thousand spoons when all you need is a knife.

Slide 34

Slide 34 text

#8 Understand Ember Data's protocol and protect yourself.

Slide 35

Slide 35 text

{ "blogs": [ { "id": 1, "name": "Embedly Blog" }, { "id": 1, "name": "Embedly Blog" }, .... ] } /api/blogs

Slide 36

Slide 36 text

{"users": [ { "id": 1, "name": "Sean", "email": "[email protected]" }, { "id": 2, "name": "Kawandeep", "email": "[email protected]" }, .... ]} /api/users

Slide 37

Slide 37 text

#9 deferReadiness is your friend.

Slide 38

Slide 38 text

App.deferReadiness(); // Wait for all the javascript files to load. $(document).ready(function(){ App.User.current(function(user, profile, organizations){ // Set everything else up. App.set('user', user); // Will start everything up. App.advanceReadiness(); }); });

Slide 39

Slide 39 text

#10 Save high level objects on the Application.

Slide 40

Slide 40 text

var Clip = Em.Namespace.create(); Clip.Copy = Em.View.extend({ didInsertElement: function(){ this.$().attr('data-clipboard-text', Dolphin.get('org.api_key')); var clip = new ZeroClipboard( this.$().get(0), { moviePath: "/scripts/vendor/zero/zero- clipboard.swf" }); } });

Slide 41

Slide 41 text

#11 Objects, objects everywhere.

Slide 42

Slide 42 text

App.AuthedRoute = Em.Route.extend({ redirect: function(){ if (Em.isNone(Shine.get('user'))){ this.transitionTo('login'); return false; } return true; } });

Slide 43

Slide 43 text

#12 Promise to use promises.

Slide 44

Slide 44 text

App.OrganizationRoute = App.AuthedRoute.extend({ model: function(){ var promise = Em.Deferred.create(); App.Organization.find( {slug:params.slug}).then(function(results){ App.set('org', results.objectAt(0)); promise.resolve(results.objectAt(0)); }); return promise; } });

Slide 45

Slide 45 text

#13 “states” move the world.

Slide 46

Slide 46 text

#14 Ember gives you debugging tools, use them.

Slide 47

Slide 47 text

App = Ember.Application.create({ LOG_STACKTRACE_ON_DEPRECATION : true, LOG_BINDINGS : true, LOG_TRANSITIONS : true, LOG_TRANSITIONS_INTERNAL : true, LOG_VIEW_LOOKUPS : true, LOG_ACTIVE_GENERATION : true }); {{debugger}} {{log controller}}

Slide 48

Slide 48 text

#15 Let Handlebars helper you.

Slide 49

Slide 49 text

Em.Handlebars.registerBoundHelper( 'prettyCents', function (as_cents) { var as_dollars = as_cents / 100; return '$' + as_dollars; });

Slide 50

Slide 50 text

#16 Use Ember's standard library.

Slide 51

Slide 51 text

#17 USE GRUNT

Slide 52

Slide 52 text

#18 It's probably not Ember's fault, you just think it is.

Slide 53

Slide 53 text

QUESTIONS? @screeley @embedly