47
THE ROAD TO EMBER 2.0 FIRST EMBER.JS TREVISO MEETUP presented by / Filippo Zanella @r4m

The road to Ember 2.0

Embed Size (px)

Citation preview

Page 1: The road to Ember 2.0

THE ROAD TO EMBER 2.0FIRST EMBER.JS TREVISO MEETUP

presented by / Filippo Zanella @r4m

Page 2: The road to Ember 2.0

HURRY UP!

On July 24th Ember.js will bump to version 2.0. The core team is moving fast (one release per monthly sprint)

Apr 4th v1.11.1, May 13th v1.12, June 12th v1.13.

Page 3: The road to Ember 2.0

...BUT DON'T BE SCARED.Version 2.0 marks the transformation of Ember from simply an MVC

framework to a complete front-end stack.

Luckily, Ember 2.0 is not a big-bang rewrite. Staying on thecutting-edge can be done without rewriting your app.

Changes have been rolled out incrementally. The 2.0 release willsimply remove features that have been deprecated.

Page 4: The road to Ember 2.0

MOTIVATIONS

Page 5: The road to Ember 2.0

STABILITY WITHOUT STAGNATIONIn the greater JavaScript community, getting the latest and

greatest often means rewriting parts of your apps once a year.

The Ember community works hard to introduce new ideas with aneye towards migration. The Ember core-team call this "stability

without stagnation".

When breaking changes are absolutely necessary, they try to makethose changes ones you can apply without too much thought. They

call these "mechanical" refactors.

To further aid in these transitions, a new tab to the EmberInspector that will list all deprecations in your application.

Page 6: The road to Ember 2.0

BIG BETSThe first bet was on open standards: JavaScript modules, promises

and Web Components.

The second bet was that the community was tired of hand-rollingtheir own build scripts for each project. They've invested heavily inEmber CLI, giving us a single tool that unifies the community and

provides a venue for disseminating great ideas.

In Ember 2.0, Ember CLI and ES6 modules will become first-classparts of the Ember experience.

That is, you should begin moving your app to Ember CLI now.

Page 7: The road to Ember 2.0

LEARNING FROM COMMUNITYEmber core-team have analyzed and discussing React's approach

to data flow and rendering and in particular how they make use of a"virtual DOM" to improve performance.

Ember's view layer is one of the oldest parts of Ember, and was designed for a world where IE7 and IE8 weredominant (gosh!). They've spent the better part of 2014 rethinking the view layer to be more DOM-aware, and the

new codebase (codenamed "HTMLBars") borrows the best ideas from React.

React's "virtual DOM" abstraction also allowed them to simplify theprogramming model of component-based applications.

In Ember 2.0, a "virtual DOM" and data flow model has beenadopted to simplifies communication between components.

Page 8: The road to Ember 2.0

SIMPLIFYING EMBER CONCEPTSEmber 2.0 is about simplification, to reduce file sizes, reduce code

complexity, and generally make apps easier to maintain.

The high-level set of improvements that we have planned are:

More intuitive attribute bindingsNew HTML syntax for componentsBlock parameters for componentsMore consistent template scope1-way data binding by default, with opt-in to 2-way bindingsMore explicit communication between componentsRoutes drive components, instead of controller + templateImproved actions that are invoked inside components

Page 9: The road to Ember 2.0

NEW FEATURES

Page 10: The road to Ember 2.0

INLINE IFIn v1.11 Ember's if helper can be used in the inline form:

{{if isEnabled 'active' 'disabled'}}

Page 11: The road to Ember 2.0

EACH WITH INDEXThe each helper will support an index block param in v1.11:{{#each people as |person index|}} {{!-- The first index value will be 0 --}} <div>{{index}}: {{person.name}}</div>{{/each}}

Page 12: The road to Ember 2.0

BOUND ATTRIBUTE SYNTAXCurrent Ember developers are familiar with the bind-attr

syntax, used to declare an attribute binding on an HTML element.<a {{bind-attr href=url}}>Click here</a>

Ember 1.11 introduces a more intuitive API for attribute binding.For example, here the color variable is bound to the class of a div:<div class="{{color}}"></div>

The inline if helper can also be used in these contexts:<div class="{{color}} {{if isEnabled 'active' 'disabled'}}"></div>

For some attributes, like the disabled boolean, passing a literalvalue is desirable. An example:

<input disabled={{isDisabled}}>

Page 13: The road to Ember 2.0

COMPONENT HELPEREmber components can be bound via the component helper. For

example this logic in a template:{{#if isRed}} {{x-red}}{{else if isBlue}} {{x-blue}}{{else if isGreen}} {{x-green}}{{/if}}

Can be replaced by a property and the component helper.{{component colorComponentName}}

The property colorComponentName should either have a valueof x-red, or x-blue etc. As the value of the computed property

changes, the rendered component will also change.

Page 14: The road to Ember 2.0

STORE.UNLOADALL()Previously, store.unloadAll required a modelName argument

to unload records of a type. Now, you can unload all recordswithout calling store.destroy.

@store.unloadAll() can now unload all models when notpassed a model name.

Page 15: The road to Ember 2.0

GLIMMEREmber 1.13 is the first release that includes the new Glimmer

rendering engine. Glimmer is:

A new faster rendering engine that is especially fast at updates.An implementation of the React-inspired "just re-render it"programming model for components, with one-way data flow bydefault and better enforcement for data-down, actions-up.Supports ergonomic attributes (<my-link href="{{url}}.html">go home</my-link>), angle-bracketcomponents (<my-component />), that hews closely to HTMLsyntax with a few small enhancements.

Page 16: The road to Ember 2.0

THE ATTRS PROPERTYBeginning with Ember 1.13 a component's attributes will be

available in this.attrs rather than on the component itself.

So when a component is invoked this way:{{my-component title=model.name}}

The component will see this.attrs.title as the current valueof model.name. Whenever model.name changes via

observation, or when the parent component is re-rendered, my-component's lifecycle hooks will be triggered, and it will see a new

version of model.name.

Page 17: The road to Ember 2.0

THE MUT HELPERWhat if you want to allow the child component to modify the

property explicitly? The mut helper will produce an object thatcontains both a value property and an update method.

In Ember 1.13, you can write:{{my-counter count=(mut activatedCount)}}

Component.extend click: -> this.attrs.count.update(this.attrs.count.value + 1)

The call to {{mut activatedCount}} packages up an objectcontaining both its current value and a callback that allows the

receiving component to modify it.

Page 18: The road to Ember 2.0

CLOSURE ACTIONIn Ember 1.x, the actions system used bubbling to pass user

behavior to a parent scope. E.g., when clicking a button an actionmight bubble through several controllers.

Action bubbling was difficult to debug, and plagued by an inabilityto have a return value.

Ember 2.x is component-driven, and replaces action bubblingwith a function-passing solution.

Actions:

Can be passed multiple argumentsReturn a value. E.g. result = this.attrs.submit()Can curry

Page 19: The road to Ember 2.0

CLOSURE ACTIONFor example, action submit is passed to my-component where it

is called upon click:app/controllers/index.coffeeimport Ember from 'ember'

Ember.Controller.extend actions: setName: (name) -> model.set('name', name)

{{! app/templates/index.hbs }} {{my-component submit=(action 'setName')}}

app/components/my-component.coffeeimport Ember from 'ember'

Ember.Component.extend click: -> this.attrs.submit(this.get('name'))

Page 20: The road to Ember 2.0

NEW EMBER.JS HELPER APIEmber helpers:

Represent a single valueDo not manage DOM or control flowCan recompute themselvesCan optionally access servicesDo not require a dash

app/helpers/full-name.js` `

Ember.Helper.helper (params, hash) -> return params.join(' ')

import Ember from 'ember'

{{full-name "Daniel" model.lastName}}{{my-component name=(full-name model.firstName "Smith")}}{{! The following usage would set the model.name to the new full name when my-component calls the submit action. }}{{my-component submit=(action (mut model.name) (full-name model.firstName "Smith"

Page 21: The road to Ember 2.0

DEPRECATIONS

Page 22: The road to Ember 2.0

MORE CONSISTENT HANDLEBARS SCOPEIn Ember 1.9, the context-shifting forms of #each and #with have

been deprecated in favor of the named-parameter forms.{{#each post in posts}} {{!-- the context in here is the same as the outside context, and post references the current iteration --}}{{/each}}

{{#each posts}} {{!-- the context in here has shifted to the individual post. the outer context is no longer accessible --}}{{/each}}

{{#with post as otherPost}} {{!-- the context in here is the same as the outside context --}}{{/with}}

{{#with post}} {{!-- the context in here has shifted to the post. the outer context is no longer accessible --}}{{/with}}

Page 23: The road to Ember 2.0

MORE CONSISTENT HANDLEBARS SCOPEIn Ember 1.12, the in and as syntax are further deprecated in favor

of block params syntax.

To transition your code to the new syntax, you can changetemplates that look like this:

{{#each people}} <p>{{firstName}} {{lastName}}</p> <p>{{address}}</p>{{/each}}

with:{{#each people itemController="abc" as |person|}} <p>{{person.firstName}} {{person.lastName}}</p> <p>{{person.address}}</p>{{/each}}

Page 24: The road to Ember 2.0

OBJECTCONTROLLERExperienced Ember users have enjoyed the use of proxying

behavior in the Ember.ObjectController class since 1.0.

However, this behavior will be removed in Ember 2.0 as theframework migrates to routable components.

Page 25: The road to Ember 2.0

OBJECTCONTROLLERTo migrate from an explicitly defined object controller, first convert

the class definition to inherit from Ember.Controller. E.g.:import Ember from "ember";

// Change:export default Ember.ObjectController.extend({// To:export default Ember.Controller.extend({

// ...

Next update any use of {{modelPropertyName}} in templateswith {{model.modelPropertyName}}. You should also review

any computed property dependent keys, observer keys, and getand set statements on the route and controller.

Page 26: The road to Ember 2.0

INSTANCES INITIALIZERSBefore FastBoot, you would only ever run applications one at a

time. In FastBoot, it is important for a single node server to be ableto serve a second request while the first one is fetching its data.

In Ember.js 1.12 application boot is separated into two phases:

Application initializers run, to register dependencies andinjections. These initializers are doing work that is shared acrossall FastBoot requests, and therefore should not create instances.Instance initializers run next. This is the right time to do workthat is specific to each FastBoot request. You can createinstances and modify their state here.

Page 27: The road to Ember 2.0

ACCESS TO INSTANCES IN INITIALIZERSPreviously, initializers had access to an object that allowed them to

both register new classes and get instances of those classes.

If you have an initializer that gets instances of a class, you need tochange it to use an instance initializer.

The store service is now injected as an . As a consequence, if you had initializers depending onthe store, you should move them to an instance initializer as well, and mark it as after: 'ember-data'.

instanceInitializer

Page 28: The road to Ember 2.0

ACCESS TO INSTANCES IN INITIALIZERSChange code that looks like this:

App.initializer name: "clock"

initialize: (container, application) -> application.register("clock:main", Clock) clock = container.lookup("clock:main") clock.setStartTime(Date.now())

To:App.initializer name: "clock"

initialize: (registry, application) -> application.register("clock:main", Clock)

App.instanceInitializer name: "clock"

initialize: (instance) -> clock = instance.container.lookup("clock:main") clock.setStartTime(Date.now())

Page 29: The road to Ember 2.0

SHARED GETTER AND SETTEREmber.js 1.12 introduces an improved syntax for computed

properties with a setter. Previously, computed properties with asetter implemented that setter by inspecting the number ofarguments passed to the computed property's descriptor.

For example, this computed property splits a full name into twoparts when set:

fullName: Ember.computed "firstName", "lastName", (key, newName) -> if (arguments.length > 1) parts = newName.split(" ") this.setProperties({ firstName: parts[0], lastName: parts[1] }) return newName else return this.get("firstName") + " " + this.get("lastName")

Page 30: The road to Ember 2.0

SHARED GETTER AND SETTERThese uses should be converted to use the new discrete getter and

setter syntax introduced in 1.12:fullName: Ember.computed("firstName", "lastName", { get: function() { return this.get("firstName") + " " + this.get("lastName"); }, set: function(key, newName) { var parts = newName.split(" "); this.setProperties({ firstName: parts[0], lastName: parts[1] }); return newName; }});

Page 31: The road to Ember 2.0

EMBER.VIEWEmber 1.x encouraged a Model-View-Controller-Route architecture.Since then, the web has consolidated around a Model-Component-Route pattern for web development that Ember 2.0 also embraces.

Views are removed from the Ember 2.0 API.

YES, VIEWS ARE REMOVED.

However a single release is likely insufficient for large apps toupgrade their entire codebase away from routeable views, and

consequently Ember is providing extended support for views viathe addon.

This addon will remain compatible with Ember until v2.4 of the framework is released.ember-legacy-views

Page 32: The road to Ember 2.0

EMBER.VIEWIn most cases Ember views can be replaced with a component. E.g.:

app/templates/show-menu.hbs{{view.title}}

app/views/show-menu.coffee` `

# Usage: {{view "show-menu"}}Ember.View.extend templateName: 'some-menu' title: 'My Menu'

import Ember from 'ember'

Can be replaced with this component:app/templates/components/show-menu.hbs{{title}}

app/components/show-menu.coffee` `

# Usage: {{show-menu}}Ember.Component.extend title: 'My Menu'

import Ember from 'ember'

Page 33: The road to Ember 2.0

EMBER.VIEWNote that a component has always its own context in a template.

A view's template may have had access to other variables that werepresent where it was called, such as a controller.

A component template will always be isolated, and if data isneeded it should be passed upon invocation. For example:{{show-menu options=controller.menuOptions}}

Page 34: The road to Ember 2.0

EMBER.VIEWROUTABLE VIEWS

Currently, when a template for a given route is rendered, if there isa view with the same name that view will also be used.

For example this view is attached to the rendered route template:app/router.coffee` `

Ember.Router.map -> this.route('about')

import Ember from 'ember'

app/views/about.coffee` `

Ember.View.extend classNameBindings: ['controller.isActive:active']

import Ember from 'ember'

Page 35: The road to Ember 2.0

EMBER.VIEWROUTABLE VIEWS

There are only two reasons a view may be used for a route:

To set attribute bindingsTo attach event handlersTo manage all the jquery stuffs

You should migrate away from routed views.

Page 36: The road to Ember 2.0

EMBER.VIEWROUTABLE VIEWS

For example to attach bindings to an element in the template issufficient:

app/router.coffee` `

Ember.Router.map -> this.route('about')

import Ember from 'ember'

app/templates/about.hbs<div class="{{if isActive 'active'}}"> <!-- something something --></div>

Page 37: The road to Ember 2.0

EMBER.VIEWROUTABLE VIEWS

If attaching events or sharing DOM is necessary, consider acomponent:

app/templates/about.hbs{{#active-layout isActive=isActive}} <!-- something something -->{{/active-layout}}

app/components/active-layout.js` `

Ember.Component.extend classNameBindings: ['isActive:active'] click: -> # Handle click

import Ember from 'ember'

Page 38: The road to Ember 2.0

EMBER.VIEWNOTABLE

In preparation for Ember 2.0, 1.13 introduces many deprecations.Some of these include:

All view APIs in Ember (Ember.CoreView, Ember.View,Ember.CollectionView, Ember.ContainerView)Options to the {{#each helper that trigger a legacy and poorlyperforming legacy layer. Like: itemView, itemViewClass,tagName, emptyView and emptyViewClass.The itemController argument for {{#each.The view and viewClass params for {{outlet}}

Page 39: The road to Ember 2.0

EMBER.LINKVIEWAs a consequence of the deprecation of Ember.View, many

internal views have been ported to component.

Ember.LinkView, the class that backs the {{link-to}}helper, have been ported to Ember.LinkComponent.

Most uses of Ember.LinkView can be directly ported to theEmber.LinkComponent class.

Page 40: The road to Ember 2.0

EMBER.SELECTUsing the Ember.Select global and its view helper form

({{view 'select'}}) is deprecated.

Ember.Select is implemented in a legacy coding style that usespatterns such as observers and two-way data binding that:

can cause pathological performance problemsprovide an experience that is not consistent with idiomaticEmber 2.0 development.

Sadly true. Complex Ember.Select with mixed dynamic content are tricky to be managed.

Legacy support will be provided via the addon.ember-legacy-views

Page 41: The road to Ember 2.0

EMBER.SELECTEmber 2.0 provides several new features that make it much more

straightforward to implement </select> tag functionality via thedata-down, actions-up paradigm in one's codebase.

For example, to create a component that displays a prompt and alist of dropdown options, the following code could be used:app/templates/components/my-select.hbs<select {{action 'change' on='change'}}> {{#each content key="@index" as |item|}} <option value="{{item}}" selected={{is-equal item selectedValue}}> {{item}} </option> {{/each}}</select>

Page 42: The road to Ember 2.0

EMBER.SELECTapp/components/my-select.js` `

Ember.Component.extend content: [] selectedValue: null

actions: change: -> changeAction = this.get('action') selectedElement = this.$('select')[0] selectedIndex = selectedElement.selectedIndex content = this.get('content') selectedValue = content[selectedIndex]

this.set('selectedValue', selectedValue) changeAction(selectedValue)

import Ember from 'ember'

app/helpers/is-equal.js` `

Ember.Helper.helper ([leftSide, rightSide]) -> return leftSide === rightSide

import Ember from 'ember'

Page 43: The road to Ember 2.0

EMBER.SELECTThis component could be used in a template by supplying it an

array of strings as content and an action to call when the usermakes a selection as change:

app/templates/application.hbsThe currently selected item: {{mySelectedItem}}.

{{my-select content=myItems action=(action (mut mySelectedItem))}}

myItems is an array of strings: ['one', 'two', ...]. This uses the action and mut helpers to pass in an action

that will update the (outer scope) mySelectedItem propertywith the user's selection.

Page 44: The road to Ember 2.0

TYPEKEY TO MODELNAMEIn Ember Data, when you ask for a model, Ember Data looks its

class up using Ember's API. When the modelclass is looked up, Ember Data stores the type on the model class.

Dependency Injection

For example, when the following code runs in your application:post = this.store.getById('post', 1)

and Ember Data will store the string "post" on the model class:console.log(post.constructor.typeKey) # 'post'

Ember Data uses this typeKey property internally whencreating/extracting payloads in Serializers, and when locating

models in Adapters.

Page 45: The road to Ember 2.0

TYPEKEY TO MODELNAMEIn Ember Data 1.0.0-beta.18, the typeKey property is now calledmodelName. In addition, the modelName is a dasherized string(previously it was always normalized to be a camelCased string).

For example, if you had a model called TacoShop, it would be stored on the model's constructor's modelNameproperty as taco-shop, whereas previously it would be stored as tacoShop.

Accessing the typeKey property should still work, but will triggerdeprecation warnings.

Page 46: The road to Ember 2.0

IE 8Ember Data v1.0.0-beta.19 is the last release to support InternetExplorer 8. Future versions of Ember Data will not support IE 8.

R.I.P.

Page 47: The road to Ember 2.0

RESOURCESThe road to Ember.js 2.0 RFCThe transition to Ember 2.0 in detailDeprecations added in Ember 1.X