Slide 1

Slide 1 text

Intro to Ember.js Nick Kleinschmidt [email protected] - @kleinsch

Slide 2

Slide 2 text

• Single-Page Applications • Ember.js Core Concepts • Ember.js Ecosystem • Q&A Overview

Slide 3

Slide 3 text

Single-Page Apps • Performance • Capabilities • Code Separation • History / URLs • SEO • Error Handling • Performance Degradation Benefits Drawbacks

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

MV* Conceptual Layout This Deals with data for: Model Controller Template / View All Sessions Just this session What is currently visible Credit: Yehuda Katz

Slide 6

Slide 6 text

HTML UI Layout Framework-Specific UI Layout Ext.apply(this, { width: this.themeInfo.width, items: [{ xtype: 'checkbox', boxLabel: 'disabled', margin: '0 0 0 10', listeners: { change: this.toggleDisabled, scope: this } }, { xtype: 'container', layout: { type: 'table', columns: 4, tdAttrs: { style: 'padding: 5px 10px;' } }, items: [{ xtype: 'component', html: 'Text Only' }, { xtype: 'button', text: 'Small' }, { xtype: 'button', text: 'Medium', scale: 'medium' }, { xtype: 'button', text: 'Large', scale: 'large' }, {

Slide 7

Slide 7 text

URL Support • balancedpayments.com/marketplaces • balancedpayments.com/#/marketplaces • balancedpayments.com/#

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Promises Callback Promise User.find(1).then( function(user) { // do something with our user }, function(user) { // handle the error } ); User.find(1, { success: function(user) { // do something with our user }, error: function(error) { // handle the error } });

Slide 10

Slide 10 text

Promises Callback Promise var user = User.find(1).then(function(user) { ! return user.loadAccount(); }).then(function(account) { ! return account.update(); }).then(function() { ! // account updated }); User.find(1, { success: function(user) { user.loadAccount({ success: function(account) { account.update({ success: function() { // account updated } }); } }); } });

Slide 11

Slide 11 text

Promises Callback Promise var user = User.find(1) ... user.then( function(user) { // do something with our user }, function(user) { // handle the error } ); User.find(1, { success: function(user) { // do something with our user }, error: function(error) { // handle the error } });

Slide 12

Slide 12 text

Bindings App.wife = Ember.Object.create({ householdIncome: 80000 }); App.husband = Ember.Object.create({ householdIncomeBinding: 'App.wife.householdIncome' }); App.husband.get('householdIncome'); // 80000 // Someone gets raise. App.husband.set('householdIncome', 90000); App.wife.get('householdIncome'); // 90000 App.Person = App.Model.extend({ first_name: 'Nick', last_name: 'Kleinschmidt', name: function () { return this.get('first_name') + ' ' + this.get('last_name'); }.property('first_name', 'last_name') }); var nick = App.Person.create(); nick.get('name'); // Nick Kleinschmidt Two-Way Bindings Derived Properties

Slide 13

Slide 13 text

Conceptual Model Controller Model View Template Router Controller View Template Model Model

Slide 14

Slide 14 text

Conceptual Model Controller Model View Template Router Controller View Template Model Model Data is bound to HTML Events bubble up

Slide 15

Slide 15 text

Model Represents persistent application state App.Post = DS.Model.extend({ title: DS.attr('string'), author: DS.attr('string'), intro: DS.attr('string'), extended: DS.attr('string'), publishedAt: DS.attr('date') }); Balanced.Transaction = Balanced.Model.extend({ account: Balanced.Model.belongsTo('Balanced.Account', 'account'), amount_dollars: function () { if (this.get('amount')) { return (this.get('amount') / 100).toFixed(2); } else { return ''; } }.property('amount'), account_name_summary: function () { if (this.get('account')) { return this.get('account.name_summary'); } else { return 'None'; } }.property('account') });

Slide 16

Slide 16 text

Model Frameworks • Ember Data • Ember Model • Ember Resource • DIY (AJAX + Ember Object)

Slide 17

Slide 17 text

Controller • Stores application state • Proxies the model to transform or augment it for templates • Handles events App.PostController = Ember.ObjectController.extend({ isEditing: false, edit: function() { this.set('isEditing', true); }, doneEditing: function() { this.set('isEditing', false); this.get('store').commit(); } });

Slide 18

Slide 18 text

Router Handles syncing application state with the URL App.Router.map(function() { this.resource('about'); this.resource('posts', function() { this.resource('post', { path: ':post_id' }); }); }); App.PostsRoute = Ember.Route.extend({ model: function() { return App.Post.find(); } }); App.PostRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); } });

Slide 19

Slide 19 text

Routing Hierarchy App.Router.map(function() { this.resource('about'); this.resource('posts', function() { this.resource('post', { path: ':post_id' }); }); }); App.PostsRoute = Ember.Route.extend({ model: function() { return App.Post.find(); } }); App.PostRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); } });

Slide 20

Slide 20 text

Template Generates HTML to describe the user interface <div class="container-fluid"> <div class="row-fluid"> <div class="span3"> <table class='table'> <thead> <tr><th>Recent Posts</th></tr> </thead> {{#each model}} <tr><td> {{#linkTo 'post' this}}{{title}} <small class='muted'>by {{author}}</small>{{/linkTo}} </td></tr> {{/each}} </table> </div> <div class="span9"> {{outlet}} </div> </div> </div>

Slide 21

Slide 21 text

Handlebars Helper var showdown = new Showdown.converter(); Ember.Handlebars.registerBoundHelper('markdown', function(input) { return new Handlebars.SafeString(showdown.makeHtml(input)); }); ...
{{markdown extended}}
Binds to attributes and automatically recomputes

Slide 22

Slide 22 text

View Translates primitive events (click, key pressed) into semantic events (doSearch, saveTransaction) Todos.EditTodoView = Ember.TextField.extend({ ! classNames: ['edit'], ! valueBinding: 'todo.title', ! change: function () { ! ! var value = this.get('value'); ! ! if (Ember.isEmpty(value)) { ! ! ! this.get('controller').removeTodo(); ! ! } ! }, ! focusOut: function () { ! ! this.set('controller.isEditing', false); ! }, ! didInsertElement: function () { ! ! this.$().focus(); ! } });

Slide 23

Slide 23 text

Conceptual Model Controller Model View Template Router Controller View Template Model Model Data is bound to HTML Events bubble up

Slide 24

Slide 24 text

Live Demo https://github.com/tildeio/bloggr-client

Slide 25

Slide 25 text

Ember.js Ecosystem

Slide 26

Slide 26 text

Workflow & Deployment Grunt - Build JS applications using JS Web Framework Asset Pipeline

Slide 27

Slide 27 text

Testing + + JSCover Istanbul

Slide 28

Slide 28 text

Who’s Using Ember.js?

Slide 29

Slide 29 text

Who’s Using Ember.js? Open Source!

Slide 30

Slide 30 text

Resources • Ember Guides / API Docs • Stack Overflow / Discourse • Peepcode - Fire Up Ember.js ($) • emberwatch.com