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

Introduction to Ember.js

Ben Hughes
October 02, 2012

Introduction to Ember.js

Getting started with Ember.js.

Ben Hughes

October 02, 2012
Tweet

More Decks by Ben Hughes

Other Decks in Technology

Transcript

  1. INTRODUCTION TO
    EMBER.JS
    Ben Hughes
    SDJS, October 2012
    http://benhugh.es
    @rubiety
    Wednesday, October 3, 12

    View Slide

  2. Wednesday, October 3, 12

    View Slide

  3. WHY LEARN
    EMBER.JS?
    “It's not Ember that's hard. It's the concepts.”
    - http://trek.github.com/
    Wednesday, October 3, 12

    View Slide

  4. Wednesday, October 3, 12

    View Slide

  5. GAME PLAN:
    •Ember Objects & Templates
    •Ember Views & Controllers
    •Ember Routers / State Managers
    •Strengths / Weaknesses
    Wednesday, October 3, 12

    View Slide

  6. CONVENTIONS:
    •Top-level Application Namespace (Object) “App”
    •Classes are upper-case properties (App.User)
    •Instances are lower-case properties (App.user)
    •Camel-casing
    Wednesday, October 3, 12

    View Slide

  7. EM.OBJECT
    The Core of Ember.js
    Wednesday, October 3, 12

    View Slide

  8. EM.OBJECT - FEATURES
    •Computed Properties
    •Observers
    •Bindings
    •Auto-Updating Templates
    Wednesday, October 3, 12

    View Slide

  9. EM.OBJECT - CLASSES
    App.User = Ember.Object.extend({
    firstName: null,
    lastName: null
    });
    var user = App.User.create({
    firstName: "Ben",
    lastName: "Hughes"
    });
    user.get("firstName"); # "Ben"
    user.get("lastName"); # "Hughes"
    Wednesday, October 3, 12

    View Slide

  10. EM.OBJECT - INSTANCES
    var user = Ember.Object.create({
    firstName: "Ben",
    lastName: "Hughes"
    });
    Wednesday, October 3, 12

    View Slide

  11. WITHOUT CLASS
    var user = Ember.Object.create({
    firstName: "Ben",
    lastName: "Hughes"
    });
    Wednesday, October 3, 12

    View Slide

  12. COMPUTED PROPERTIES
    App.User = Ember.Object.extend({
    firstName: null,
    lastName: null,
    fullName: function() {
    return this.get("firstName") + " " + this.get("lastName");
    }.property("firstName", "lastName")
    });
    var user = App.User.create({
    firstName: "Ben",
    lastName: "Hughes"
    });
    Wednesday, October 3, 12

    View Slide

  13. GETTING/SETTING
    user.set("firstName", "Benjamin");
    user.setProperties({
    firstName: "Benjamin"
    });
    user.get("firstName"); // "Ben"
    user.get("lastName"); // "Hughes"
    Wednesday, October 3, 12

    View Slide

  14. ADVANCED COMPUTED
    PROPERTIES
    var project = Ember.Object.create({
    todos: [ Ember.Object.create({done: false}) ],
    remaining: function() {
    return this.get("todos").filterProperty('done', false).get("length");
    }.property("[email protected]")
    });
    project.get("remaining"); # 1
    Wednesday, October 3, 12

    View Slide

  15. OBSERVERS
    // Explicit:
    user.addObserver("fullName", function() {
    alert("Changed Full Name");
    });
    user.set("firstName", "Benjamin");
    // Implicit:
    App.User.reopen({
    fullNameChanged: function() {
    alert("Changed Full Name");
    }.observes('fullName')
    });
    Wednesday, October 3, 12

    View Slide

  16. BINDINGS
    App.wife = Ember.Object.create({
    householdIncome: 80000
    });
    App.husband = Ember.Object.create({
    householdIncomeBinding: "App.wife.householdIncome"
    });
    App.husband.get("householdIncome"); // 80000
    App.husband.set("householdIncome", 90000);
    App.wife.get("householdIncome"); // 90000
    Wednesday, October 3, 12

    View Slide

  17. FEATURES GUIDE
    •Use Computed Properties to create a new
    property synthesizing other properties.
    •Use Observers to react to changes in another
    property.
    •Use Bindings to ensure objects in two different
    layers are always in sync.
    Wednesday, October 3, 12

    View Slide

  18. TEMPLATES
    Auto-updating templates bound to objects with Handlebars.js
    Wednesday, October 3, 12

    View Slide

  19. JAVASCRIPT REQUIREMENTS



    Wednesday, October 3, 12

    View Slide

  20. HANDLEBARS TEMPLATES
    • Placed in <br/>• Can be named (stored for later use), or unnamed (evaluate<br/>immediately in-line)<br/>• Deliberately limited semantics (supports auto-updating)<br/>Wednesday, October 3, 12<br/>

    View Slide



  21. <br/>Hello, {{App.user.fullName}}<br/>


    App.user.set("firstName", "Benjamin");
    App.user = App.User.create({firstName: "Ben", lastName: "Hughes"});
    BASIC EXAMPLE
    Wednesday, October 3, 12

    View Slide



  22. <br/>{{#with App.user}}<br/>Hello, {{fullName}}<br/>{{/with}}<br/>


    CONTEXT WITH “WITH”
    Wednesday, October 3, 12

    View Slide



  23. Hello,

    Ben Hughes



    UNDER THE HOOD
    Wednesday, October 3, 12

    View Slide

  24. App.user = App.User.create();


    <br/>{{#if App.user.lastName}}<br/>Hello, {{App.user.fullName}}<br/>{{else}}<br/>Sorry, not found.<br/>{{/if}}<br/>


    App.user.setProperties({firstName: "Ben", lastName: "Hughes"});
    Wednesday, October 3, 12

    View Slide

  25. App.company = Ember.Object.create({
    people: [
    { name: 'Yehuda' },
    { name: 'Tom' }
    ]
    });
    <br/><ul><br/>{{#each App.company.people}}<br/><li>Hello, {{name}}!</li><br/>{{/each}}<br/></ul><br/>
    Wednesday, October 3, 12

    View Slide

  26. BINDING ATTRIBUTES






    Wednesday, October 3, 12

    View Slide

  27. ASYNCHRONOUS
    LOADING
    Ember’s approach to a difficult problem...
    Wednesday, October 3, 12

    View Slide

  28. TRADITIONAL APPROACH
    jQuery.getJSON('/posts/1', function(post) {
    $("#post").html(
    "" + post.title + "" +
    "" + post.body + ""
    );
    });
    Wednesday, October 3, 12

    View Slide

  29. EMBER’S APPROACH
    “In general, Ember's goal is to eliminate explicit
    forms of asynchronous behavior. As we'll see
    later, this gives Ember the ability to coalesce
    multiple events that have the same result.
    It also provides a higher level of abstraction,
    eliminating the need to manually register and
    unregister event listeners to perform most
    common tasks.”
    Wednesday, October 3, 12

    View Slide

  30. LOADING USER VIA AJAX
    <br/>Hello, {{App.user.fullName}}.<br/>Your username is: {{App.user.username}}.<br/>
    App.user = App.User.find("rubiety");
    Wednesday, October 3, 12

    View Slide

  31. WRONG WAY
    App.User.reopenClass({
    find: function(username) {
    $.ajax({
    url: '/users/' + username,
    dataType: 'json',
    success: function(response) {
    return response.data;
    }
    });
    }
    });
    App.User.find("rubiety");
    Wednesday, October 3, 12

    View Slide

  32. RIGHT WAY
    App.User.reopenClass({
    find: function(username) {
    var user = App.User.create({ username: username });
    $.ajax({
    url: '/users/' + username,
    dataType: 'json',
    success: function(response) {
    user.setProperties(response.data);
    }
    });
    return user;
    }
    });
    App.User.find("rubiety");
    Wednesday, October 3, 12

    View Slide

  33. ONLY DISPLAY IF LOADED
    App.user = App.User.find("rubiety");
    <br/>{{#if App.user.isLoaded}}<br/>Hello, {{App.user.fullName}}.<br/>Your username is: {{App.user.username}}.<br/>{{else}}<br/>Loading user...<br/>{{/if}}<br/>
    Wednesday, October 3, 12

    View Slide

  34. ONLY DISPLAY IF LOADED
    App.User.reopenClass({
    find: function(username) {
    var user = App.User.create({ username: username });
    $.ajax({
    url: '/users/' + username,
    dataType: 'json',
    success: function(response) {
    user.setProperties(response.data);
    user.set("isLoaded", true);
    }
    });
    return user;
    }
    });
    App.User.find("rubiety");
    Wednesday, October 3, 12

    View Slide

  35. EMBER-DATA
    A client-side ORM for Ember. Not covering, but more info here:
    https://github.com/emberjs/data
    Wednesday, October 3, 12

    View Slide

  36. VIEWS &
    CONTROLLERS
    Higher-level constructs for MVC design
    You an do quite a lot just with auto-updating
    templates and Ember.Object, but Ember supports
    a wealth of higher-level components for complex
    UI engineering
    Wednesday, October 3, 12

    View Slide

  37. Wednesday, October 3, 12

    View Slide

  38. MVC COMPONENTS
    • Model: Em.Object (or DS.Model) describes application structure,
    including relationships between models.
    • View: Em.View encapsulates templates and manages events. Usually
    corresponds to a named Handlebars.js template.
    • Controller: Mediate’s views access to model.
    • Em.ArrayController proxies to array data
    • Em.ObjectController proxies to a single object
    • State Manager: (Routers) Act as a map of your application and
    handle transitions as a user moves through it.
    Wednesday, October 3, 12

    View Slide

  39. EM.VIEW
    Wednesday, October 3, 12

    View Slide

  40. NAMED VIEWS


    <br/>Hello, <b>{{name}}</b><br/>


    App.SayHelloView = Ember.View.extend({
    templateName: 'say-hello'
    });
    var view = App.SayHelloView.create({name: "Bob"});
    view.appendTo("#container"); // or view.append(); (appends to body)
    view.remove();
    Wednesday, October 3, 12

    View Slide

  41. VIEWS INSIDE ANOTHER VIEW
    <br/><h1>My Application</h1><br/>{{#view App.SayHelloView name="Bob"}}<br/>
    <br/>Hello, <b>{{name}}</b><br/>
    App.SayHelloView = Ember.View.extend({
    templateName: 'say-hello'
    });
    Wednesday, October 3, 12

    View Slide

  42. VIEWS BOUND TO OTHER DATA
    App.user = App.User.create({firstName: "Ben", lastName: "Hughes"});
    App.SayHelloView = Ember.View.extend({templateName: 'say-hello'});
    var view = App.SayHelloView.create({
    userBinding: "App.user"
    });
    view.append();
    <br/>Hello, <b>{{user.fullName}}</b><br/>
    App.user.set({firstName: "Benjamin"});
    // Hello, Benjamin Hughes
    Wednesday, October 3, 12

    View Slide

  43. VIEW CONTEXT
    App.user = App.User.create({firstName: "Ben", lastName: "Hughes"});
    App.SayHelloView = Ember.View.extend({templateName: 'say-hello'});
    var view = App.SayHelloView.create({
    userBinding: "App.user",
    contextBinding: "user",
    });
    view.append();
    <br/>Hello, <b>{{fullName}}</b><br/>
    Wednesday, October 3, 12

    View Slide

  44. EVENTS WITH {{ACTION}}
    <br/>{{#if isEditing}}<br/>First Name: {{view Ember.TextField valueBinding="user.firstName"}}<br/>Last Name: {{view Ember.TextField valueBinding="user.lastName"}}<br/><a href="#" {{action "show"}}>Show User</a><br/>{{else}}<br/><h1>Showing User {{user.fullName}}.</h1><br/><a href="#" {{action "edit"}}>Edit User</a><br/>{{/if}}<br/>
    App.UserView = Ember.View.extend({
    templateName: "user",
    userBinding: "App.user"
    edit: function(e) { this.set("isEditing", true); },
    show: function(e) { this.set("isEditing", false); }
    });
    Wednesday, October 3, 12

    View Slide

  45. OTHER VIEW FEATURES
    (NOT COVERED)
    • Modifying a View’s HTML (Generated Tag)
    • Custom Handlebars Helpers
    • View Nesting / Hierarchy
    • Event propagation through View Hierarchy
    • {{action}} targeting another view or controller/router
    • View Components (Controls for Select, TextField, etc.)
    • ArrayProxy and Enumerable
    Wednesday, October 3, 12

    View Slide

  46. EM.CONTROLLER
    Controlling access to your model data...
    Wednesday, October 3, 12

    View Slide

  47. App.usersController = Ember.ArrayController.create({
    content: [
    Em.Object.create({ firstName: "Ben", lastName: "Hughes" }),
    Em.Object.create({ firstName: "Oscar", lastName: "Peterson"})
    ]
    });
    App.usersView = Ember.View.create({
    templateName: "users",
    controllerBinding: "App.usersController"
    });
    <br/><ul><br/>{{#each controller}}<br/><li>{{firstName}} {{lastName}}</li><br/>{{/each}}<br/></ul><br/>
    App.usersView.append();
    Wednesday, October 3, 12

    View Slide

  48. <br/><ul><br/>{{#each controller}}<br/><li>{{firstName}} {{lastName}}</li><br/>{{/each}}<br/></ul><br/>
    App.usersView.append();
    App.users = [
    Em.Object.create({ firstName: "Ben", lastName: "Hughes" }),
    Em.Object.create({ firstName: "Oscar", lastName: "Peterson"}),
    Em.Object.create({ firstName: "Kenny", lastName: "Barron"}),
    ];
    App.usersController = Ember.ArrayController.create({
    contentBinding: "App.users"
    });
    App.usersView = Ember.View.create({
    templateName: "users",
    controllerBinding: "App.usersController"
    });
    Wednesday, October 3, 12

    View Slide

  49. App.user = Em.Object.create({
    firstName: "Ben",
    lastName: "Hughes"
    });
    App.userController = Ember.ObjectController.create({
    contentBinding: "App.user"
    });
    App.userView = Ember.View.create({
    templateName: "user",
    controllerBinding: "App.userController",
    contextBinding: "controller",
    });
    <br/>Hi, {{firstName}} {{lastName}}<br/>
    Wednesday, October 3, 12

    View Slide

  50. EM.ROUTER
    Managing State
    Covering only briefly - more information at:
    http://trek.github.com/
    Wednesday, October 3, 12

    View Slide

  51. <br/><h1>My Application</h1><br/>{{outlet}}<br/>
    <br/><h2>Users</h2><br/>...<br/>
    <br/><h2>Projects</h2><br/>...<br/>
    App = Ember.Application.create();
    App.ApplicationController = Ember.Controller.extend();
    App.ApplicationView = Ember.View.extend();
    App.UsersController = Ember.ArrayController.extend();
    App.UsersView = Ember.View.extend();
    App.ProjectsController = Ember.ArrayController.extend();
    App.ProjectsView = Ember.View.extend();
    Wednesday, October 3, 12

    View Slide

  52. App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
    index: Ember.Route.extend({
    route: "/",
    redirectsTo: "users"
    });
    users: Ember.route.extend({
    route: "/users",
    connectOutlets: function(router) {
    router.get("applicationController").connectOutlet("users", App.User.all());
    }
    });
    projects: Ember.route.extend({
    route: "/projects",
    connectOutlets: function(router) {
    router.get("applicationController").connectOutlet("projects", App.Project.all());
    }
    })
    });
    });
    App.initialize();
    // Now Available:
    App.router
    App.router.applicationController, App.router.usersController, App.router.projectsController
    Wednesday, October 3, 12

    View Slide

  53. router.get("applicationController").connectOutlet("users", App.User.all());
    // The above line automatically does the following:
    // 1. New router.usersController with content = App.User.all();
    router.usersController = App.UsersController.create({
    content: App.User.all()
    });
    // 2. New App.UsersView controller = router.usersController, context = controller
    var view = App.UsersView.create({
    controller: router.usersController,
    context: controller
    });
    // The view is rendered with the template (example below)
    // and inserted into {{outlet}} of ApplicationView:
    <br/><ul><br/>{{#each controller}}<br/><li>{{firstName}} {{lastName}}</li><br/>{{/each}}<br/></ul><br/>
    Wednesday, October 3, 12

    View Slide

  54. OTHER ROUTER FEATURES
    (NOT COVERED)
    • Nested Routing
    • Routing with Named Parameters (/users/:user_id)
    • Serializing & Deserializing for State transition on # access
    • Wiring up view actions to router events (and state transitions)
    Wednesday, October 3, 12

    View Slide

  55. CATPRINT
    ORDER BUILDER
    Wednesday, October 3, 12

    View Slide

  56. EMBER STRENGTHS:
    • Scales well with complexity
    • Excellent strong object system throughout the library with
    robust data binding / dependency resolution
    • Robust View Hierarchy
    • Performant Event Delegation
    • Manages creating and destroying views efficiently for optimal
    memory management without leaks and phantom events
    • Excellent tools for complex UI engineering
    • Lean Templates with Handlebars.js
    Wednesday, October 3, 12

    View Slide

  57. EMBER WEAKNESSES:
    • A little too much ceremony for simple apps
    • Poor Documentation, Few non-trivial example apps available
    • Concepts are Difficult
    • A fair amount of “magic” and auto-instantiation with
    Controllers / Routers
    • Template auto-updating only works with Handlebars.js
    • Pre-Version 1.0, so still a bit premature, but getting there
    • Ember ORM (ember-data) “not production ready”
    • Script tag “markers” in rendered markup, and Ember IDs
    Wednesday, October 3, 12

    View Slide

  58. WHEN MIGHT YOU USE EMBER?
    • Complex applications with non-trivial nested UIs - Ember has
    hierarchical views and powerful state managers to make this
    easy
    • Applications with lots of data dependency/recalculation/re-
    rendering - Ember handles this very transparently
    WHEN TO NOT USE EMBER:
    • Applications with fairly simple views and minimal nesting /
    event handling
    Wednesday, October 3, 12

    View Slide

  59. QUESTIONS?
    Ben Hughes
    http://benhugh.es
    @rubiety
    http://emberjs.com/
    http://emberjs.com/guides/
    http://trek.github.com/
    Wednesday, October 3, 12

    View Slide