Ember.js 1.10.0 and 1.11 Beta Released
We are pleased to announce the release of both Ember.js 1.10.0 and the first beta in the 1.11 series. This comes as the tenth cycle of our release process that began after 1.0 was released.
The 1.10 release represents the effort of at least 50 contributors across over 553 commits.
The HTMLBars Templating Engine
Throughout 2014 the Ember.js community has poured its shared effort into a new templating solution. This new library, dubbed HTMLBars, makes available features and performance improvements impossible to support with Handlebars (the previous library). We are delighted to announce the inclusion of the HTMLBars templating engine in Ember.js 1.10.
HTMLBars will enable the implementation of several APIs described in The Road to Ember 2.0, and contributes to our continued improvement of rendering performance. Additionally, it will allow us to continue supporting all Ember 1.x template syntax.
This long-term effort would not have succeeded without the continued contributions of the Ember community and core team. In no particular order and with apologies to anyone we've missed we would like to thank @krisselden, @wycats, @_mmun, @nerd20, @mixonic, @ebryn, @salzhrani, @rwjblue, @tomdale, oneeman, @kpdecker and the many alpha and beta testers who provided feedback and bug reports. You are the stuff "stability without stagnation" is made of.
New Features in Ember.js 1.10
HTMLBars 0.8.5
Ember.js 1.10 is dependent on HTMLBars 0.8.5. To ease this and later template library version changes, Ember's template compiler will be packaged as a part of the release files. For example, a JSBin in Ember 1.9 would need to be updated from:
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v2.0.0.js"></script>
<script src="http://builds.emberjs.com/tags/v1.9.1/ember.js"></script>
to
<script src="http://builds.emberjs.com/tags/v1.10.0/ember-template-compiler.js"></script>
<script src="http://builds.emberjs.com/tags/v1.10.0/ember.debug.js"></script>
The ember-template-compiler.js
is only required for template compilation. The
runtime dependencies for HTMLBars are built into the framework file.
To smoothly upgrade to 1.10 and HTMLBars, Ember-CLI users should update to a version at or after 0.1.12, remove their application's Handlebars dependency, and modify the Brocfile to not load Handlebars. This diff shows the changes needed to upgrade an Ember-CLI app to 1.10.
Ember App-Kit users should upgrade to Ember-CLI.
Ember-Rails users should upgrade to version 0.16.1, then remove their Handlebars dependency.
Developers of applications that follow a non-standard build pipeline should review the instructions published by Robert Jackson this week and join the conversation at discuss.emberjs.com or on IRC.
Performance Improvements
Ember.js 1.8 introduced a performance regression that we expected to re-coup in the 1.10 release. In December the team at Discourse created the ember-performance repo. This project aids Ember developers in profiling and measuring performance in the framework.
Using these benchmarks, we're pleased to report a twelve percent improvement in common rendering scenarios between 1.7 and 1.10, and as much as a fifty percent improvement between 1.9 and 1.10.
Better rendering and general framework performance continue to be a priority for the core team and community. Specific goals include reactive rendering for HTMLBars, more optimized metal views, limiting observation, and refinements to the Ember object model.
Chained Else Blocks
HTMLBars is built using the Handlebars parser, and will continue to gain
features related to template syntax. Ember 1.10 features support for chained
else helpers, the most common use being else if
. An example:
Ship that code!
You can finish War and Peace eventually...
Chained else helpers work with any else
, including those of with
and each
helpers.
You can read more about the implemetation in the Handlebars repo. Thanks to @kpdecker for this improvement.
Block Params
Ember 1.10 introduces block parameters. Block params provide consistent scope to templates, and allow components to pass internal values to a downstream scope.
For example:
Preserving template context results in easier to read templates, and passing variables into child scopes allows for new patterns of component composition.
Block params are passed from a template via the yield
helper. For example, this
component yields the fullName
and age
values:
// app/components/x-customer.js
export default Ember.Component.extend({
fullName: function(){
var customer = this.get('customer');
return [customer.get('firstName'), customer.get('lastName')].join(' ');
}.property('customer.firstName', 'customer.lastName'),
age: function(){
return (new Date() - this.get('birthday')) / (86400000 * 365);
}.property('birthday')
});
<div class="customer">
</div>
<div class="layout">
Hello, . You are years old.
</div>
Many thanks to @_mmun for the implementation of this new feature.
Injected Properties
Ember 1.x has exposed two APIs for managing dependency injection. The first is
the application initializer API, using register
and inject
methods on an
application instance. The second allows configuration of an injection on
controllers via needs
. You can read more about these patterns in
the dependency injection guide.
The new injected properties offer a more declarative API for dependency injection.
Use Ember.inject.service()
to inject a service with the same name as the property
it is injected as. In this example, the storage
service is injected onto the
storage
property:
export default Ember.Component.extend({
storage: Ember.inject.service()
});
Passing a name to the service()
method allows a different service to be injected.
For example:
export default Ember.Component.extend({
storage: Ember.inject.service('local-storage')
});
In addition to injecting services, controllers can be injected with Ember.inject.controller
.
Importantly, these injections are lazy. When used within a unit test, a stubbed service can
be passed during create
. For example:
test("a value is saved on storage", function(){
expect(1);
var component = this.subject({
storage: {
write: function(){
ok(true, 'value was written');
}
}
});
var element = this.append();
element.click();
});
Refer to the API documentation to read about this new feature in detail.
Thanks to slindberg for his implementation of this feature.
Notable Deprecations
As Ember.js moves forward, various APIs are deprecated to allow for their removal in a later major release (such as 2.0). The deprecations page summarizes deprecations and demonstrates how to update to a new API.
- The explicit
{{bind}}
helper has been deprecated. This helper has long been marked private, and was a legacy Sproutcore feature. This helper will be removed in Ember 1.11. - Quote-less outlet names are deprecated in 1.10. An example of this is
{{outlet modal}}
, which should be re-written as{{outlet "modal"}}
. This ensures the outlet helper is consistent with others, where unquoted words are values and not string literals. - The
beforeObserver
feature is deprecated in Ember 1.10. Before observers are rarely used, but introduce significant overhead to the observer system in general. For observer use that requires the previous value of a property be known, implementing a cache is easier and more efficient. Read more about how to do this on the deprecations page. - Observing the
childViews
array of aContainerView
is deprecated. - Setting the
childViews
property on a view definition is deprecated in 1.10. For example:
var ChildB = Ember.View.extend();
export default Ember.ContainerView.extend({
childViews: [ 'childA', ChildB ],
childA: Ember.View.extend()
});
This use of childViews
is inconsistent with other uses throughout Ember, and
as a result is difficult to implement with good performance. Explicitly creating
views upon initialization is preferred:
var ChildB = Ember.View.extend();
export default Ember.ContainerView.extend({
init: function(){
this._super();
this.pushObject(this.createChildView(this.childA));
this.pushObject(this.createChildView(ChildB));
},
childA: Ember.View.extend()
});
New Features in Ember.js 1.11 beta
Ember.js 1.11 beta continues a series of releases iterating the framework toward our 2.0 goals. In six weeks, these and a few other features will be declared stable.
Inline if
In 1.11 Ember's if
helper can be used in the inline form:
Thanks to @marciojunior_me for implementing this feature.
Each with Index
The each
helper will support an index
block param in Ember 1.11:
<div> : </div>
Thanks to @_mmun for implementing this feature.
Bound Attribute Syntax
Current Ember developers are familiar with the bind-attr
syntax, used
to declare an attribute binding on an HTML element. An original
motivation for HTMLBars was to improve on this syntax.
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=""></div>
The inline if helper can also be used in these contexts:
<div class=" "></div>
For some attributes, like the disabled
boolean, passing a literal value
is desirable. An example:
<input disabled=>
To allow the data-binding of non-string values to boolean properties and custom element properties, bound attributes are implemented with a property-first setter.
When binding to an attribute, Ember first checks to see if that attribute is a property of the element's DOM node (with normalization of capitalization). If it is, the value is set with a property. For example:
<input disabled=>
// disabled is a property of input elements, so...
input.disabled = true;
If the attribute is not present as a property, then its value is set as an attribute:
<div class=>
// class is not a property of div elements, do...
div.setAttribute('class', 'red');
For SVG attributes and the style attribute, we've made a exceptions to this pattern. Despite these exceptions, the property-first rule is a good way to describe what is happening behind the scenes. In practice, the binding syntax feels natural.
Many thanks to @mixonic, @_mmun, and @wycats for their effort on the design and implementation of this feature.
Named Substates
Two routing substates exist for Ember routes. The loading
substate will be entered
if the async hooks of a route are still processing, and the error
substate will be
entered when an async hook promise is rejected.
Substates are sibling routes. When the new
route of cars.new
is loading, the cars.loading
substate is entered. The application
route has no parent namespace to nest its siblings.
This makes using the loading
and error
substates impossible for an application route.
Named substates add a new lookup method for substates. The name of the route is pre-pended
onto the substate. So a valid loading substate for application
can be defined as
application_loading
.
Thanks to @machty for landing this feature.
Component Helper
Ember components can be bound via the component
helper. For example this logic
in a template:
Can now be replaced by a computed property and the component
helper.
The property colorComponentName
should have a value of x-red
, x-blue
etc. As
the value of the property changes, the rendered component will also change.
A big thank you to @lukemelia for shipping this new feature.
Notable Deprecations in 1.11
The following deprecations are scheduled for release with Ember.js 1.11:
- The
ObjectController
will be removed in Ember 2.0. In Ember 1.11, both explicitly using anObjectController
and using the proxying behavior of a generatedObjectController
will raise deprecation warnings.
As the features included in Ember 1.12 are developed, additional deprecations may be added to the 1.11 release.
Changelogs
Using Ember? Please take ten minutes to share your feedback by participating in the 2015 Ember Community Survey. Open until February 20th.