Ember.js – Enterprise Application Framework



Ember.js – Enterprise Application Framework

0 1


qconsf-ember


On Github hbrysiewicz / qconsf-ember

Ember.js

Enterprise Application Framework

Heather Brysiewicz / @caligoanimus

I'm here to talk to you about Ember.js, a client side framework
I have been programming for most of my life. I have interests all over the technology space, but my career has always focussed around the web and its ever changing technologies.
I have been working with Ember for over 2 years. My first application could easily be described as frustrating. The resources were limited and the community was quite small. I was patient and the more I learned the easier it got. I have my own web consulting firm, we specialize in ember applications.
Organizer for sandiego.js I see a lot of members choosing ember and they are able to grasp the core concepts and fully recognize the benefits much easier because the resources and community that has grown so much ember.
This is thanks to the individuals and companies that have adopted and contributed to the success of the framework.

Who is using Ember.js?

emberjs.com/ember-users

Who is using Ember.js?

builtwithember.io

built with ember is another resource that highlights websites that are public facing and built with ember.

You'll see up here some fortune 500 and some other recognizable company names that are using Ember. Qualcomm just recently relaunched their entire public facing website along with the help of digital agency Digitaria.

So Why do these companies chose Ember.js?

App grows, complexity doesn't Sam Mueller, Yahoo Ad-Manager Plus

Ember has the ability to manage the complexity of large applications and websites with grace Jackie Hade, from Digitaria on Qualcomm

The fact that Ember is so opinionated... any Ember developer can look at any other Ember application and immediately have a huge benefit Lance Harper, NBCNews

When tasked with building a robust, powerful, and ambitious web applicaiton, Ember is the tool for that job. These are some quotes from some of the companies I showed before on why they chose ember. You'll see some common themes when reading these quotes or information online about why individuals or companies choose Ember

It Grows!

One of those is that it grows really well. Ember boasts being developed for ambitious apps. It stays easy to manage and navigate a project as it grows in size.

Opinionated = Performance + Productivity

Another is that ember is opinionated. Convention over configuration This means that it is able to take care of common tasks the correct and performant way, enabling the developer to be more productive. It also means that picking up a new ember app takes minutes of knowledge transfer, not days!

Evolution: Rise from the Ashes

Where did we come from?

Ember didn't come out of nowhere boasting some serious muscle. There has been a long line of front-end web technologies that have led up to the modern day client-side solutions, like Ember. It has improved on the solutions built before it, and exceeded them.

Ajax

DOM Selection and Traversing

Events, Effects, and Animations

Extensible

I was working a web dev position when jQuery came up on my radar. The ease of making ajax calls was enough for me to incorperate it immediately. The dom selection engine made manipulating the dom much easier and more shorthand, with chaining and traversing. Never been a fan of jquery plugins as they far too often incur performance problems, but jquery also bosted being 'highly extensible' Soon the entire application had nearly been rewritten with much more of the logic being moved to the client from the server. Just as fast, this code became difficult to manage, or even find scattered throughout the proejct, as was the case with many a jquery project.

Lean MVC

Small Footprint

Easy to Learn

Provides Basic Tools

The next big leap was Backbone and it improved the quality of life for many front-end developers. jquery or other selector engine dependency It offered a lean approach to MVC with a minimal learning curve, only a few core concepts to master. A lot of boilerplate that had to be handled by the developer. No structure. Memory management is a serious consideration for backbone developers, view lifecycle must be well managed or memory leaks are all too easy. Provides basic toolset for building an application or custom framework. Is not a framework.

Two-Way Binding

Manages View Life-Cycle

Automatic Creation

Router

Ember-Data

Performance

Two-Way binding in today's generation of client-side tech has really simplified templates and leaned down a lot of logic that had to be done prior to update views. Setup and teardown of views Automatically create Routes, Controllers and Views even if you haven't defined them yourself. Ember-Data is an optional model layer that provides a way to interact with data on your server, cache them for performance and can be used without much configuration for most projects Because Ember is so particular, it makes good app management decisions so you don't have to. Optimizes updates to the DOM when data change, Caching of computed properties, only recalculates when necessary.

It's a Framework

Models*
Router
Controllers
Views & Components
Templates
Ember is very much a framework models: optional layer. represent your data returned from server, ember-data provides ways for managing and loading the data router: url, handles error/loading states, retrievs data & pushes to controller, hierarchical controller: decorating the data, business logic and event handling views/comps: responsible for dom interaction, responding to user events. comps are isolated views templates: handlebars, much like html but provide helpers for displaying or iterating over data, responding to user actions.

Ember-CLI

I'm going to walk through an example application that will cover these core pieces. It is important to note that this will be done from the context of Ember-CLI. Command line tool that provides the boiler plate, blue prints, and build tools needed to get an ember app up-and-running in minutes. Ember-CLI allows you to write the application code in es6 module syntax Getting started with ember-cli is as easy as this one line of code you see here.

After hitting enter you'll see ember-cli build out some required files and the enforced project structure with be stubbed out for you under the app/ directory. It will even build out the project with the testing structure and dependencies The last steps will be to install bower and npm dependencies, and finally to initialize a new git repository.

Imgur Example

Using the commonly known web application, Imgur, as an example to demonstrate the core concepts of Ember. I'm going to work in from the visual concepts to the more internal concepts for the different pieces.
  • URL
    /
  • Template Path
    app/templates/application.hbs
  • View Path
    app/views/application.js
  • Controller Path
    app/controllers/application.js
  • Route Path
    app/routes/application.js
Lets take a look at the appication from a visual perspective first to get an idea of the different pieces that will be created. This is the landing page, so we are at the root of the application. Ember is going to look for these files to be defined for any custom logic or UI needed for the application view. For this example, I have a header that I want to persist no matter where I am in the application, so this will be put in the template for application.
  • URL
    /
  • Template Path
    app/templates/application.hbs
  • View Path
    app/views/application.js
  • Controller Path
    app/controllers/application.js
  • Route Path
    app/routes/application.js
The default ember behavior for the view and controller is enough for our example, so we won't need to write any code for that. Ember will build out a working application view and controller with default behavior for us. We only need to write the application template, and that is only because we have a header that persists throughout the entire application.

Application Template

app/templates/application.hbs

<header>
  {{#link-to 'index'}}
    <i class="fa fa-circle fa-emgur-logo"></i>
    Emgur
  {{/link-to}}
</header>

<div class="main-container">
  {{outlet}}
</div>
Here is what our application template file looks like. Any time the route changes, the template will be rendered inside the outlet tag.
  • URL
    /
  • Template Path
    app/templates/index.hbs
  • View Path
    app/views/index.js
  • Controller Path
    app/controllers/index.js
  • Route Path
    app/routes/index.js
By default, index is the route that is run when the url is at the root.
  • URL
    /
  • Template Path
    app/templates/index.hbs
  • View Path
    app/views/index.js
  • Controller Path
    app/controllers/index.js
  • Route Path
    app/routes/index.js
For the index, we will need a custom template where we loop through each gallery item. Add some styling in there as well. We are also going to need to grab the content for the index route, in this case, the array of gallery items to display.

Index Route

app/routes/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return this.store.find('gallery');
  }
});
this.store gives access to the data store. model is a special hook on the route that provides the main content to the controller. this.store.find returns a promise and Ember will wait for that promise to resolve before rendering the template.

app/templates/index.hbs

<div class="container">
  {{#each}}
    {{image-thumb content=this}}
  {{/each}}
  <div class="clear"></div>
</div>
each default behavior is to loop over the content provided in the route. image-thumb is a component that will display the thumbnail, manage the hover state, and show the comments count.
  • Template Path
    app/templates/components/image-thumb.hbs
  • Component Path
    app/components/image-thumb.js
components are a special kind of view that is completely isolated. any data you want it to have access to must be passed into it, this also works with bound elements.

:isHovering

commentCount

here is a demo of how the interaction is going to work. basically we want the gradient and comment count to show up when we hover, along with the border. The border we do with css, simple :hover selector. The content for the count we'll use a flag on the component. Also, the comments for a given gallery item will have to be totalled. This isn't on the data model so this will have to be an attribute on the component.

Image Thumbnail Component

app/components/image-thumb.js

import Ember from 'ember';

export default Ember.Component.extend({
  isHovering: false,

  commentsCount: function() {
    return this.get('content.comments.length');
  }.property('content.comments'),

  mouseEnter: function() {
    this.set('isHovering', true);
  },

  mouseLeave: function() {
    this.set('isHovering', false);
  }
});
pretty simple component but it gives you an idea of a component. `content` is passed in and we get the comment count by grabbing the length of the comments array. the isHovering toggles when the mouseOver and mouseLeave events fire. components, like views, are evented and implement touch, drag/drop, mouse, key and form events. Custom events can also be registered.

Image Thumbnail Template

app/templates/components/image-thumb.hbs

{{#link-to 'gallery' content}}
  <div class="image-item">
    <div class="image-thumb">
      <img {{bind-attr src=content.image.url}}>
    </div>
    {{#if isHovering}}
      <div class="image-details">
        <div class="image-comment">
          <div class="comment-count">{{commentsCount}} comments</div>
        </div>
      </div>
    {{/if}}
  </div>
{{/link-to}}
here we can see the isHovering flag at work in the handlebars template. we can also see the `bind-attr` handlebars helper. this comes in handy with images, or other attributes you may want to bind like height, width, or even data-attrbutes you may be using for interactions with other libraries.

Adding Routes

I wrapped the entire image thumb component in a link-to so that when it was clicked, the individual gallery view would display that item's specific content.

Define Routes

app/router.js

import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('gallery', { path: '/gallery/:gallery_id' });
});

export default Router;
We don't need to define the main index or app route, ember will do that for us as we saw before. If we name the parameters with the model name and follow it with the `_id` we won't need to write these routes. The default behavior for the route will be to look up the model, in this case `gallery` and do a find with the passed in id number.
  • URL
    /gallery/:gallery_id
  • Template Path
    app/templates/gallery.hbs
  • View Path
    app/views/gallery.js
  • Controller Path
    app/controllers/gallery.js
  • Route Path
    app/routes/gallery.js
This route content will replace the index content inside of that {{outlet}} tag.
  • URL
    /gallery/:gallery_id
  • Template Path
    app/templates/gallery.hbs
  • View Path
    app/views/gallery.js
  • Controller Path
    app/controllers/gallery.js
  • Route Path
    app/routes/gallery.js
The route default behavior as we mentioned will be enough for us, since we are taking advantage of the expected naming convention for our id parameter. The only other thing we will need is the template file that will handle the display of the title and image, as well as the comments. Most of what is in the template should be easy to figure out, but the new stuff would be actions. We want to be able to add a new comment.

Gallery Item Template

app/templates/gallery.hbs

<div class="gallery-container">
  <div class="gallery-full">
    <div class="gallery-title">{{title}}</div>
    <div class="gallery-posted">{{postedFormated}}</div>
    <div class="gallery-image">
      <img {{bind-attr src=image.url}}>
    </div>
  </div>

  <div class="gallery-comments">
    <div class="comment-new">
      {{#if isEditing}}
        {{focus-textarea value=newComment rows=3 focus-out='offEdit' action='submitComment'}}
        <div class="comment-button-container">
          <div class='save-button' {{action 'submitComment'}}>save</div>
          <div class="comment-length">{{newCommentCharacters}}</div>
        </div>
        <div class="clear"></div>
      {{else}}
        {{input placeholder='Submit a comment' focus-in='onEdit'}}
      {{/if}}
    </div>
    <ul class="gallery-comments-ul">
      {{#each comments}}
        <li class="gallery-comment">
          <div class="comment-posted">{{postedFormatted}}</div>
          <div class="comment-content">{{content}}</div>
        </li>
      {{/each}}
  </ul></div>
</div>

<!-- TODO -->
<div class="gallery-navigation"></div>
This template has a bit more going on since there is more interaction available between the user and the application. I'm going to step through the unfamiliar pieces.

Gallery Item Template

app/templates/gallery.hbs

bind-attr is a handlebars helper that allows for ember objects to be bound to a dom element attribute. in this example, the src for an image.

Gallery Item Template

app/templates/gallery.hbs

focus-textarea is another component that extends the default ember textarea. this component has quite a few more attributes than the one prior and even has some actions being defined.

Gallery Item Template

app/templates/gallery.hbs

action is another handlebars helper that triggers an event. these actions bubble up until the action is found.

Gallery Item Template

app/templates/gallery.hbs

loop over each comment

Gallery Item Controller

app/controllers/gallery.js

import Ember from 'ember';

export default Ember.ObjectController.extend({
  maxChars: 140,
  isEditing: false,
  newComment: null, // bound to value of textarea

  postedFormated: function() {
    return moment(this.get('posted')).fromNow();
  }.property('posted'),

  newCommentCharacters: function() {
    return this.maxChars - this.get('newComment.length');
  }.property('newComment'),

  actions: {
    onEdit: function() {
      this.set('isEditing', true);
    },

    offEdit: function() {
      if (this.get('newCommentCharacters') === this.maxChars) {
        this.set('isEditing', false);
      }
    },

    submitComment: function() {
      var _this = this;

      var comment = this.store.createRecord('comment', {
        content: this.get('newComment')
      });

      comment.save().then(function(comment) {
        var gallery = _this.get('content');
        gallery.get('comments').pushObject(comment);

        gallery.save().then(function(gallery) {
          _this.setProperties({
            newComment: null,
            isEditing: false
          });
        });
      });
    }
  }
});

That's all you need to get started with

Get Involved!

Community

#emberjs

Thanks!

hbrysiewicz.github.io

@caligoanimus