Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Ember.js

Intro to Ember.js

Introduces Ember.js, describing motivations behind single-page apps, Ember.js concepts, and tools helpful in developing JS applications.

Nick Kleinschmidt

June 26, 2013
Tweet

Other Decks in Programming

Transcript

  1. Single-Page Apps • Performance • Capabilities • Code Separation •

    History / URLs • SEO • Error Handling • Performance Degradation Benefits Drawbacks
  2. MV* Conceptual Layout This Deals with data for: Model Controller

    Template / View All Sessions Just this session What is currently visible Credit: Yehuda Katz
  3. 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' }, { <section id="main" class="container"> <div id="forgot-password"> <div class="row"> <div id="content" class="span26"> <div class="row"> <div class="offset2 span22"> <div class="offset6 span8"> <a href="https://www.balancedpayments.com"><img class="logo" src="images/balanced-logo.png" alt="Balanced" /></ a> <form id="forgot-form"> {{view Ember.TextField type="email" name="email" valueBinding="email" placeholder="Email" action="forgotPassword"}} <p class="pull-left instructions">You will recieve an e-mail with reset instructions.</p> <button class="pull-right" {{action "forgotPassword"}} type="button">Submit</button> </form> </div> </div> </div> </div> </div> </div> </section>
  4. 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 } });
  5. 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 } }); } }); } });
  6. 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 } });
  7. 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
  8. Conceptual Model Controller Model View Template Router Controller View Template

    Model Model Data is bound to HTML Events bubble up
  9. 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') });
  10. Model Frameworks • Ember Data • Ember Model • Ember

    Resource • DIY (AJAX + Ember Object)
  11. 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(); } });
  12. 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); } });
  13. 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); } });
  14. Template Generates HTML to describe the user interface <script type="text/x-handlebars"

    id="posts"> <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> </script>
  15. Handlebars Helper var showdown = new Showdown.converter(); Ember.Handlebars.registerBoundHelper('markdown', function(input) {

    return new Handlebars.SafeString(showdown.makeHtml(input)); }); ... <div class='below-the-fold'> {{markdown extended}} </div> Binds to attributes and automatically recomputes
  16. 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(); ! } });
  17. Conceptual Model Controller Model View Template Router Controller View Template

    Model Model Data is bound to HTML Events bubble up
  18. Resources • Ember Guides / API Docs • Stack Overflow

    / Discourse • Peepcode - Fire Up Ember.js ($) • emberwatch.com