If you have fast machine and recent Google Chrome or Safari installed, please check a bit more "moving" version of that presentation

Otherwise, scroll down to see the slides

A framework for creating ambitious web applications

Based on the Ember.js Guides and other resources

Why Emberjs -- Javascript MV* Framework?

Organizing the concerns in an application into models, views, controllers and routers, templates, presenters or ViewModels.


Ember.js structure the application into logical abstraction layers

Model: is an object that stores persistent state

Template: describes the user interface of the application. View: for sophisticated handling of user events or to create a re-usable component

Router: translates a URL into a series of nested templates, each backed by a model. Controllers: is an object that stores application state

Ember.js have several built-in mechanisms as:

Bindings: changes to one variable will propagate its value into other variables

Computed Properties: That will automatically update along with the properties they are reliant upon

Automatically Updated Templates: to keep up-to-date the WUI whenever changes happen to the underlying data

Ember.js use convention over configuration

When the application boots, Ember will look for these objects:

App.ApplicationRoute          # Route Ember will invoke the router's 
                              # hooks first before rendering the template
App.ApplicationController     # Controller Ember will set an instance of this
                              # as the controller for the template
application                   # Template (main) its properties <- controller
App.ApplicationRoute = Ember.Route.extend(setupController: (controller) ->
  controller.set "title", "Hello world!"
App.ApplicationController = Ember.Controller.extend(appName: "My First Example")

When the application access a resource as /posts, Ember will look for these objects:

App.PostsRoute          # Route Ember will invoke the router's hooks first before rendering 
                        # the template
App.PostsController     # Controller Ember will set an instance of this as the controller for
                        # the posts template
posts                   # Template that will be render in the {{outlet}} in the application template
App.PostsRoute = Ember.Route.extend(model: ->
  # the model is an Array of all of the posts

Because the model is an Array, Ember.js will automatically supply an instance of Ember.ArrayController, which will present the backing Array as its model

{{#each controller}}

If a route uses a dynamic segment, the route's model will be based on the value of that segment provided by the user:

App.Router.map ->
  @resource "posts",
    path: "/posts/:post_id"
App.PostRoute          # Route handler's model hook converts the dynamic :post_id
                       # parameter into a model
App.PostController     # Controller Ember will set an instance of this as the controller for
                       # the post template
post                   # Template that will be render in the {{outlet}} in the posts template

Because the model is an Object, Ember.js will automatically supply an instance of Ember.ObjectController, which will present the backing Object as its model

App.PostRoute = Ember.Route.extend(
  model: (params) ->
    App.Post.find params.post_id
  serialize: (post) ->
    post_id: post.get("id")


Creating an Application

window.App = Ember.Application.create()

This give you:

ModelEmber.js Models

Defining an store (using Ember Data)

App.Store = DS.Store.extend
  revision: 13
  adapter: DS.RESTAdapter.create
    namespace: 'api/v1'

Defining a model with attributes

App.Person = DS.Model.extend(
  firstName: DS.attr("string")
  lastName: DS.attr("string")
  birthday: DS.attr("date")
  fullName: ->
    @get("firstName") + " " + @get("lastName")
  .property("firstName", "lastName")
  posts: DS.hasMany('App.Post')
App.Post = DS.Model.extend(
  title: DS.attr("string")
  intro: DS.attr("string")
  content: DS.attr("string")
  author: DS.belongsTo("App.Person")
Expected JSON for a Person ( GET /api/v1/people/2)
{"person": {
  "id": "2",
  "first_name": "Jeff",
  "last_name": "Atwood",
  "birthday": "1993-06-05T22:24:03Z",
  "post_ids": [4, 9, 13]}
Expected JSON for a collection of Persons (GET /api/v1/people)
{"people": [{"id": "1",
    "first_name": "Ron",
    "last_name": "Jeffries",
    "birthday": "1978-08-15T12:14:53Z",
    "post_ids": [1, 2, 5, 7]
  },{"id": "2",
    "firstName": "Jeff",
    "lastName": "Atwood",
    "birthday": "1993-06-05T22:24:03Z",
    "post_ids": [4, 9, 13]}]

Finding models

post = App.Post.find(1)  # Finding an specific model record
If a record with that ID has already been created, it will be returned immediately. This feature is sometimes called an identity map
post = App.Post.find()  # Finding all the model records
This returns an instance of DS.RecordArray. The record array will start in a loading state with a length of 0, but can immediately be use it in templates. When the server responds with results, the templates will watch for changes in the length and update themselves automatically.
Note: DS.RecordArray is not a JavaScript array,implements Ember.Enumerable. For retrieve records by index the [] notation will not work, use the objectAt(index) method.
people = App.Person.find(firstName: "Peter")  # Finding all the model records  
                                            # that satisfy the query criteria 

ControllerEmber.js Controllers

Representing a Single Model

App.PostController = Ember.ObjectController.extend(isExpanded: false)
App.PostRoute = Ember.Route.extend(setupController: (controller, post) ->
  controller.set "model", post
<h2>by {{author}}</h2>

<div class='intro'>

{{#if isExpanded}}
<button {{action toggleProperty 'isExpanded'}}>Hide Content</button>
<div class='content'>
<button {{action toggleProperty 'isExpanded'}}>Show Content</button>

Representing Multiple Models

App.PostsController = Ember.ArrayController.extend(tooManyWordsPost: ->
  tooManyWordsPost = @filter((post) ->
    post.get("words") > 3000
  tooManyWordsPost.get "words"
App.PostsRoute = Ember.Route.extend(setupController: (controller, person) ->
  controller.set "model", person.get("posts")
<h1>Author: {{fullName}}</h1>

{{#each controller}}

{{tooManyWordsPost}} posts over 3000 words.

RouterEmber.js Routers

Defining a Resource

App.Router.map ->
  @resource "posts", ->
    @route "new"

This router creates three routes:

URL Route Name Controller Route Template
/ index IndexController IndexRoute index
N/A posts PostsController PostsRoute posts
/posts posts.index PostsController
/posts/new posts.new PostsController

A way to see the routes defined in an Emberjs App is in the javascript console use: App.Router.router.recognizer.names

NOTE: You should use this.resource for URLs that represent a noun, and this.route for URLs that represent adjectives or verbs modifying those nouns.

Defining Nested Resource

App.Router.map ->
  @resource "people",
    path: "/people/:person_id"
  , ->
    @route "edit"
    @resource "posts", ->
      @route "new"

This nested router creates the following routes:

URL Route Name Controller Route Template
/ index App.IndexController App.IndexRoute index
N/A person App.PersonController App.PersonRoute person
/people/:person_id person.index App.PersonIndexController App.PersonIndexRoute person/index
/people/:person_id/edit person.edit App.PersonEditController App.PersonEditRoute person/edit
N/A posts App.PostsController App.PostsRoute posts
/people/:person_id/posts posts.index App.PostsIndexController App.PostsIndexRoute posts/index
/people/:person_id/posts/new posts.new App.PostsNewController App.PostsNewRoute posts/new

TemplateEmber.js Templates

The Templates and Handlebars

Handlebars: Partials

Handlebars: Views

Handlebars: Renders

Handlebars: Controls


Ember-Data: The FixtureAdapter

Allows to begin developing Ember.js apps now, and switch to another adapter when the API is ready to be consumed without any changes to the application code

App = Ember.Application.create()
App.Store = DS.Store.extend(
  revision: 13
  adapter: DS.FixtureAdapter.create()
App.Person = DS.Model.extend(
  firstName: DS.attr("string")
  lastName: DS.attr("string")
App.Documenter.FIXTURES = [
  { id: 1, firstName: 'Yehuda', lastName: 'Katz' },
  { id: 2, firstName: 'Tom' , lastName: 'Dale'   }

QUnit Logo Integration and Unit Testing

App.rootElement = "#arbitrary-element-to-contain-ember-application" 
  setup: ->

visit url 
find selector, context
click selector
keyDown selector, type, keyCode

test "creating a post displays the new post", ->
  .fillIn(".post-title", "A new post")
  .fillIn(".post-author", "John Doe")
  .click("button.create").then ->
    ok find("h1:contains('A new post')").length, "The post's title should display"
    ok find("a[rel=author]:contains('John Doe')").length, "A link to the author should display"

Questions ?


Thank you !

Manuel Vidaurre


Use a spacebar or arrow keys to navigate