Ember.js is being adopted more and more broadly as time passes, and is an excellent choice for highly complex data-driven UIs. With the recent release of the "2.0" version of the framework, things are faster, smarter, and easier than ever. With a focus on productivity and reducing the number of trivial decisions developers must make while building an app, it's astonishing how quickly one can get up and running, and how well the abstractions hold up as the codebase scales in size and complexity.
I'd like to give a general overview of Ember, and pause to reflect on some important differences that may be important when considering what the best tool is for your project.
7. NOW IMAGINE…
• All the micro-libraries
• All the build tools
• All the pre-processors and post-processors
• All of the permutations with typescript, babel, etc…
14. THE EMBER ECOSYSTEM
ember-cli
Code Generation
Asset Pipeline
Plugins
Extensible CLI
Test Runner
ember.js
SPA routing
Components
Templating
Data Binding
Prioritized Work Queue
ember-data
Request Construction
JSON Serialization
Redux-like Data Flow
Async Relationships
liquid-fire
animations
ember-collection
virtualized list
15. THE EMBER ECOSYSTEM
• Built on strong conventions & opinions
• Focus on developer productivity
• Aligned with web standards
• Abstractions hold up w/ large scale & complexity
• Constantly improving
16. TEMPLATING
• Handlebars
• Declarative markup, an extension of
HTML
• Compiled at build time
• Extensible
Hello,
<strong>
{{firstName}} {{lastName}}
</strong>!
17. TEMPLATING
• Helpers
• Block vs inline form
• Easy to read and reason about
My pet goes
{{#if isDog}}
arf
{{else}}
meow
{{/if}}
My pet goes {{if isDog "arf"
"meow"}}
18. My pet goes {{if isDog "arf" "meow"}}
function ifHelper(condition, ifTrue, ifFalse) {
return condition ? ifTrue : ifFalse
}
{{#if isEnabled}}
<b>Switch is enabled</b>
{{/if}}
function ifHelper(condition, callbackIfTrue) {
return condition ? callbackIfTrue() : '';
}
19. <ul>
{{#each arr as |item|}}
<li>{{item.name}}</li>
{{/each}}
</ul>
function eachHelper(array, cb) {
return array
.map(item => cb(item))
.join('');
}
20. ROUTING
• Router - Finite State Machine
• Routes - Manage transitions between
states
• URLs drive your app this is a core pillar
of Ember
33. <my-widget title='Enter your Info'>
<my-field name='Username'/>
<my-field name='Password'/>
</my-widget>
{{#my-widget title='Enter your Info’}}
{{my-field name=‘Username’}}
{{my-field name=‘Password’}}
{{/my-widget}}
34. init on instantiation
willInsertElement before the component’s element is inserted into the DOM
didInsertElement after the component’s element has been inserted into the DOM
willDestroyElement before the component’s element is removed from the DOM
$(document).ready() for components
Clean up before tear down
EMBER.COMPONENT
35. EMBER-DATA
• Unidirectional data flow, single atom of state
• Can talk to any API
• Moves data massaging out of your business logic
• Built around fetch (important for SS rendering!)
• Saves tons of time if your API uses consistent conventions
36. EMBER-DATA: MODEL
• Representation of any (usually
persistent) data
• Defined by attributes, and
relationships to other models
• “model” is the factory that defines
the structure of “records”
// app/models/book.js
import DS from 'ember-data';
const { attr, hasMany } = DS;
export default DS.Model.extend({
title: attr('string'),
publishedAt: attr('date'),
chapters: hasMany('chapter')
});
37. EMBER-DATA: STORE
• Where you get/create/destroy records
• A single source of truth
• This means that all changes are kept in sync!
• Similar concept in Facebook/flux, angular-data
38. EMBER-DATA: STORE
// (maybe) API request for all records of type "author"
this.store.findAll('author');
// (maybe) API request for record of type "post" with id 37
this.store.findRecord('post', 37);
// API request for all records of type "author"
this.store.fetchAll('author');
// API request for record of type "post" with id 37
this.store.fetchRecord('post', 37);
// look in cache for all records of type "author"
this.store.peekAll('author');
// look in cache for record of type "post" with id 37
this.store.peekRecord('post', 37);