Deprecations Added in Ember 1.x
What follows is a list of deprecations introduced to Ember during the 1.x cycle.
For more information on deprecations in Ember, see the main deprecations page.
Deprecations Added in 1.7
§ .then on Ember.Application
As part of the Ember.DeferredMixin
deprecation, using .then
on an
Ember.Application instance itself has been deprecated.
You can use the ready
hook or initializers to defer/advance readiness
instead.
§ Ember.DeferredMixin and Ember.Deferred
Ember.DeferredMixin
and Ember.Deferred
have been deprecated in favor
of using RSVP.Promise
s.
§ Observing container views like arrays
ContainerViews have been observable as arrays, where the items in the array are childViews. This introduces complexity into container views despite the feature being a rarely used one.
Deprecations Added in 1.8
§ Global lookup of views
Previous to Ember 1.8, views would commonly be fetched from the global scope:
Since Ember 1.8, views are more appropriately resolved on the application via strings:
They may also be fetched via a binding:
In general, it is recommended that your Ember application avoid accessing globals from a template.
New usage of Ember.Select
Most of Ember's provided views are already accessed via helpers. For example, the Ember.TextField view is used via the input helper.
The Ember.Select view has not been upgraded to have a helper. Instead, it was suggested that you call it via the global class name:
Since this lookup is now deprecated, the select view has been registered
on an application as select
. The new usage is:
See the updated Ember.Select documentation and the built-in views guide for more details and examples.
Ember.js libraries and plugins
If the code triggering this deprecation is being fired from a library, that library may need to update its suggested usage.
One solution for such a library is to provide mixins instead of classes:
// usage is {{view "list"}}
var App.ListView = Ember.View.extend(ListView);
A more advanced solution is to use an initializer to register the plugin's views on the application:
// usage is {{view "list"}}
Ember.Application.initializer({
name: 'list-view',
initialize: function(container, application) {
container.register('view:list', ListView);
}
});
More details on how to register an Ember.js framework component are available in the initializer API documentation and the dependency injection guide.
§ Hash Location Paths Without Leading Slashes
Prior to this release, if you were using location: 'hash'
(which is the default), you were able to link to a route with a location.hash
that didn't contain the expected leading forward slash. e.g. #foo
instead of the correct #/foo
. Very few, if any, should be impacted by this since the router always produces the correct form.
Doing so is ambiguous because you may also be trying to link to an element on the page whose id matches <div id="foo">
and it also erroneously will create an extra history state if a user clicks on something that transitions to that route again, since it will change location.hash === '#/foo'
.
This ability will be removed quickly to allow us to mimic the browser's behavior of scrolling the page to an element whose id matches, but in our case doing so after the transition ends and everything is rendered. Once this feature is added, you'll be able to link to id's even with doubled up hashes: #/foo#some-id
as well as the expected #some-id
.
Deprecations Added in 1.9
§ More Consistent Handlebars Scope
In Ember 1.9, the each
and with
helpers come in two flavors: a "context-switching" flavor and a "named-parameter" flavor.
This has proven to be one of the more confusing parts of the Ember templating system. It is also not clear to beginners which to use, and when they choose the context-shifting form, they lose access to values in the outer context that may be important.
Because the helper itself offers no clue about the context-shifting behavior, it is easy (even for more experienced Ember developers) to get confused when skimming a template about which object a value refers to.
The context-shifting forms of #each
and #with
have been deprecated in favor of the named-parameter forms. In Ember 1.12, the in
and as
syntax are further deprecated in favor of block params syntax. See the deprecation notes for in and deprecation notes for as.
Transition Plan
To transition your code to the new syntax, you can change templates that look like this:
<p> </p>
<p></p>
with:
<p> </p>
<p></p>
In preparation for further work on HTMLBars, the context switching form of {{each}}
is deprecated. This is mostly a "mechanical" refactor and dramatically
simplifies how to think about the context in your templates. This change should be entirely mechanical.
In prior versions you may have done one of the following:
<ul>
<li></li>
</ul>
<ul>
<li></li>
</ul>
You should now be using:
<ul>
<li></li>
</ul>
<ul>
<li></li>
</ul>
Deprecations Added in 1.11
§ Access to Instances in Initializers
Previously, 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 to change it to use an instance initializer.
Change code that looks like this:
App.initializer({
name: "clock",
initialize: function(container, application) {
application.register("clock:main", Clock);
var clock = container.lookup("clock:main");
clock.setStartTime(Date.now());
}
});
To:
App.initializer({
name: "clock",
initialize: function(registry, application) {
application.register("clock:main", Clock);
}
});
App.instanceInitializer({
name: "clock",
initialize: function(instance) {
var clock = instance.container.lookup("clock:main");
clock.setStartTime(Date.now());
}
});
Added in PR #10256.
For more information, see the instance initializer deprecation guide.
§ Binding Style Attributes
Content in Handlebars templates is automatically HTML-escaped to help
developers prevent inadvertently introducing cross-site scripting (XSS)
vulnerabilities into their applications. If you want to display trusted
content as HTML, you can use a SafeString
, a special string that tells Ember
that the content should be displayed without escaping.
While this works great for HTML, there are some cases where you may bind user
data that the browser interprets as CSS, not HTML. For example, you may bind
the style
attribute of an element:
<div style=></div>
Handlebars only escapes HTML, not CSS, so this may introduce a potential XSS
vulnerability into your application if a malicious user is able to provide data
used in the myStyle
property.
Starting in Ember 1.11, you will receive a warning if you attempt to bind the
style
attribute of an element. Once you have verified that the content being
displayed is trusted and properly escaped, you can disable the warning by
making the content a SafeString
. For example:
myStyle: Ember.computed('color', function() {
/* Note: You must implement #escapeCSS. */
var color = escapeCSS(this.get('color'));
return Ember.String.htmlSafe("color: " + color);
})
Make sure you don't put quotes around the sanitized string, myStyle
, when you
bound it in the template. This would prevent Ember from seeing it as safe.
You can learn more about SafeString
s and writing code that prevents XSS
attacks by reading the Writing
Helpers guide.
§ ObjectController
Experienced 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 the framework migrates to routable components.
New users hit three road bumps when learning about the object controller pattern.
- Given a certain model, which of the three controller options should I be using?
- Which controller is generated by the framework if I do not specify one?
- When using an object controller, why should the
this
context not be passed to actions if it has the properties of my model?
For these reasons, the Road to Ember 2.0 RFC listed object controllers as a concept to be removed from the framework.
To migrate from an explicitly defined object controller, first convert
the class definition to inherit from Ember.Controller
. For example:
import Ember from "ember";
// Change:
export default Ember.ObjectController.extend({
// To:
export default Ember.Controller.extend({
// ...
Next update any use of {{modelPropertyName}}
in templates with {{model.modelPropertyName}}
.
You should also review any computed property dependent keys, observer keys, and get
and set
statements on the route and controller. An example of how to make this migration can
be found in this PR to the Ghost project.
If a controller is not explicitly defined, but instead is being auto-generated by the framework, it will only throw a deprecation message if the proxying behavior is being used.
Added in PR #10062.
Deprecations Added in 1.12
§ as syntax for {{with}}
Renaming a value using {{with}}
has been possible using the as
syntax. Block params,
introduces in Ember 1.10, obsolete the as
syntax.
With helpers should be updated to use block params. For example this helper:
Can be converted as follows:
§ Computed Properties With a Shared Getter And Setter
Ember.js 1.12 introduces an improved syntax for computed properties with a setter. Previously, computed properties with a setter implemented that setter by inspecting the number of arguments passed to the computed property's descriptor.
For example, this computed property splits a full name into two parts when set:
fullName: Ember.computed("firstName", "lastName", function(key, newName) {
if (arguments.length > 1) {
var parts = newName.split(" ");
this.setProperties({ firstName: parts[0], lastName: parts[1] });
return newName;
} else {
return this.get("firstName") + " " + this.get("lastName");
}
});
These 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;
}
});
For further reading, review the RFC describing this feature and the pull request of the initial implementation.
§ in syntax for {{each}}
The in
syntax is used to name an iterated value with {{each}}
. Block
params, introduced Ember 1.10, obsoletes the in
syntax.
Each helpers should be updated to use block params. For example this helper:
Can be converted as follows:
For "itemController" :
Can be converted as follows:
Deprecations Added in 1.13
§ ArrayController
Just like Ember.ObjectController
, Ember.ArrayController
will be removed in
Ember 2.0 for the same reasons mentioned in 1.11's ObjectController
deprecation.
To migrate from an explicitly defined array controller, first convert
the class definition to inherit from Ember.Controller
.
Before:
import Ember from "ember";
export default Ember.ArrayController.extend({
});
After:
import Ember from "ember";
export default Ember.Controller.extend({
});
Next update any use of {{modelPropertyName}}
in templates with {{model.modelPropertyName}}
.
You should also review any computed property dependent keys, observer keys, and get
and set
statements on the route and controller. An example of how to make this migration can
be found in this PR to the Ghost project.
Opposite to 1.11's ObjectController deprecation, if a controller is not explicitly defined, but instead is being auto-generated by the framework, it will not throw a deprecation message even if the proxying behavior is being used.
Added in PR #11476.
§ beforeObserver
Before observers are deprecated due to the negative performance implications they have for Ember internals and applications.
Typically they were used to have access to the old value of a property when it's about to change, but you can get same functionality in an even more efficient way with just a few lines of code:
function fooObserver(obj){
var newFoo = obj.get('foo');
if (obj._oldFoo !== newFoo) {
// do your stuff here
obj._oldFoo = newFoo;
}
}
addObserver(obj, 'foo', fooObserver);
fooObserver(obj); // Optionally call the observer immediately
The related functions Ember.addBeforeObserver
, Ember.removeBeforeObserver
, Ember.beforeObserversFor
, and Function#beforeObserver
are deprecated too.
§ bind-attr
Ember 1.11 introduced new syntax for using dynamic content in attributes.
In 1.10 your only option was to use the bind-attr
helper:
<div ></div>
Ember 1.11 made it possible to intuitively represent dynamic content in attributes as you would expect:
<div title=""></div>
This makes it possible to express a number of concepts directly in the template that previously were awkward to represent and required computer properties, and could even require itemController
.
Dasherized boolean values
Ember 1.11's attribute binding syntax no longer supports dasherizing for boolean values. For example:
export default Ember.Component.extend({
isActiveUser: true
});
Should be replaced with:
Legacy bind-attr
Ember 1.13 deprecated bind-attr
in favor of the new syntax.
To aid in the migration, you can use the legacy-bind-attr plugin to restore this behavior in Ember 2.0 and silence the deprecation warning.
§ Block and multi-argument unbound helper
The unbound helper is mostly a legacy API in Ember, although it is not being removed in 2.0. It was almost exclusively used to manage performance issues which are well addressed in Ember 1.13's new rendering engine.
The first form being deprecated is the block form of unbound. For example:
Show this
Instead, replace this form with a nested helper:
Show this
The second form being deprecated is the non-nested helper lookup. For example:
Replace this form with nested helper call:
Or make all inputs to the helper unbound:
§ Controller.needs
needs
for controllers will be removed in Ember 2.0. You can migrate away from this using Ember.inject.controller
.
Lets say you have a post
controller like this:
import Ember from 'ember';
export default Ember.Controller.extend({
needs: ['comments'],
newComments: Ember.computed.alias('controllers.comments.newest')
});
You can upgrade to Ember.inject.controller
like this:
import Ember from 'ember';
export default Ember.Controller.extend({
comments: Ember.inject.controller(),
newComments: Ember.computed.alias('comments.newest')
});
You can read more about Ember.inject.controller in the Ember API documentation.
§ Copyable.frozenCopy
Just as the Freezable
mixin is deprecated in favor of functionality in
core JavaScript, the frozenCopy
method of the Copyable mixin is also
deprecated in favor of Object.freeze().
Replace the following code:
const Obj = Ember.Object.extend(Freezable, Copyable, {
copy() {
return Obj.create();
}
});
const frozenCopy = Obj.create().frozenCopy();
frozenCopy.isFrozen(); // => true
frozenCopy.set('foo', 'baz'); // => throws TypeError
with:
const a = Ember.Object.create();
Object.isFrozen(a); // => false
Object.freeze(a);
Object.isFrozen(a); // => true
a.set('foo', 'baz'); // => throws TypeError
§ Ember CreateWithMixins
Ember.Object.createWithMixins
method has been deprecated. Instead call Ember.Object.create
or Ember.Object.extend
.
var obj = Ember.Object.createWithMixins({
});
Replace with code above with:
var obj = Ember.Object.extend({
}).create();
§ Ember.CollectionView
Ember.CollectionView
is deprecated as a consequence of the deprecation of Ember.View
.
Legacy support of Ember.CollectionView
will be provided via the ember-legacy-views addon.
Migrating away from Ember.CollectionView
In most cases collection view can be replaced using the {{each}}
helper in combination with the {{component}}
helper.
To be able to programmatically decide which component to use for an item, you can use a Ember.Helper
import Ember from 'ember';
export default Ember.Helper.extend({
compute: function(params, hash) {
var type = params[0];
return type + '-component';
}
});
Then if you have these two components:
Then you can render your different animals like this:
import Ember from 'ember';
export default Ember.Controller.extend({
animals: [
{ type: 'cat', name: 'Buttons' },
{ type: 'dog', name: 'Fido'}
]
});
§ Ember.computed.any
Ember.computed.any
is deprecated in favor of Ember.computed.or
. This change is required because the computed value is the first value ( like || ) rather than a boolean value ( like Array.prototype.any ). For example:
let Hamster = Ember.Object.extend({
hasClothes: Ember.computed.any('hat', 'shirt')
});
The above code will be changed to
let Hamster = Ember.Object.extend({
hasClothes: Ember.computed.or('hat', 'shirt')
});
§ Ember.ContainerView
Ember.ContainerView
is deprecated as a consequence of the deprecation of Ember.View
.
Legacy support of Ember.ContainerView
will be provided via the ember-legacy-views addon.
Migrating away from Ember.ContainerView
In most cases container view can be replaced using the {{each}}
helper in combination with the {{component}}
helper.
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['the-container'],
childComponents: ['a-component', 'b-component']
})
§ Ember.create
Ember.create
is deprecated in favor for Object.create
. For more information
regarding Object.create
, please
read the MDN documentation.
Please change this:
const doug = Ember.create({
firstName: 'Doug'
});
to
const doug = Object.create({
firstName: 'Doug'
});
§ Ember Freezable
The Freezable Mixin has been deprecated because the spec has been added to the javascript core.
Contact = Ember.Object.extend(Ember.Freezable, {
firstName: null,
lastName: null,
// swaps the names
swapNames: function() {
if (this.get('isFrozen')) throw Ember.FROZEN_ERROR;
var tmp = this.get('firstName');
this.set('firstName', this.get('lastName'));
this.set('lastName', tmp);
return this;
}
});
c = Contact.create({ firstName: "John", lastName: "Doe" });
c.swapNames(); // returns c
c.freeze();
c.swapNames(); // EXCEPTION
Replace code above with this:
Contact = Ember.Object.extend({
firstName: null,
lastName: null,
// swaps the names
swapNames: function() {
if (Object.isFrozen(this)) throw Ember.FROZEN_ERROR;
var tmp = this.get('firstName');
this.set('firstName', this.get('lastName'));
this.set('lastName', tmp);
return this;
}
});
c = Contact.create({ firstName: "John", lastName: "Doe" });
c.swapNames(); // returns c
Object.freeze(c);
c.swapNames(); // EXCEPTION
§ Ember.keys
Ember.keys
is deprecated in favor for Object.keys
. For more information
regarding Object.keys
, please
read the MDN documentation.
const food = Ember.keys({
yellow: 'banana',
green: 'pickle'
});
to
const food = Object.keys({
yellow: 'banana',
green: 'pickle'
});
§ Ember.LinkView
As 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 the Ember.LinkComponent
class.
§ Ember.oneWay
Ember.oneWay
is deprecated in favor for Ember.computed.oneWay
. Please
change all instances of Ember.oneWay
from:
let User = Ember.Object.extend({
firstName: null,
nickName: Ember.oneWay('firstName')
});
to
let User = Ember.Object.extend({
firstName: null,
nickName: Ember.computed.oneWay('firstName')
});
§ Ember.ReduceComputedProperty / Ember.ArrayComputedProperty
In addition to Ember.ReduceComputed
and Ember.ArrayComputed
you were able to add a property function call, making use of
the ReduceComputedProperty and ArrayComputedProperty classes.
This usage is also deprecated.
For an example, consider a counter component that displays a total sum of values in an array.
Using Ember.ReduceComputedProperty
would show the following:
totalCount: Ember.reduceComputed({
initialValue = 0;
addedItem(totalValue, newValue) {
return totalValue + newValue;
},
removedItem(totalValue, newValue) {
return totalValue - newValue;
}
}).property('values')
Now that these APIs are deprecated, use the native JavaScript reduce along with the Ember.computed family of functions:
totalCount: Ember.computed('values.[]', function() {
return this.get('values').reduce((previousValue, currentValue) => {
return previousValue + currentValue;
})
})
§ Ember.Select
Using the Ember.Select
global and its view helper form ({{view 'select'}}
)
is deprecated. Ember.Select
in Ember 1.x is implemented in a legacy coding
style that uses patterns such as observers and two-way data binding that
can cause pathological performance problems and provide an experience that
is not consistent with idiomatic Ember 2.0 development.
Legacy support of Ember.Select
will be provided via the ember-legacy-views addon.
Ember 2.0 provides several new features that make it much more straightforward to implement <select> tag functionality via the data-down, actions-up paradigm in one's codebase. For example, to create a component that displays a prompt and a list of dropdown options, the following code could be used:
import Ember from "ember";
export default Ember.Component.extend({
content: null,
selectedValue: null,
didInitAttrs(attrs) {
this._super(...arguments);
var content = this.get('content');
if (!content) {
this.set('content', []);
}
},
actions: {
change() {
const changeAction = this.get('action');
const selectedEl = this.$('select')[0];
const selectedIndex = selectedEl.selectedIndex;
const content = this.get('content');
const selectedValue = content[selectedIndex];
this.set('selectedValue', selectedValue);
changeAction(selectedValue);
}
}
});
// is-equal helper is necessary to determine which option is currently selected.
import Ember from "ember";
export default Ember.Helper.helper(function([leftSide, rightSide]) {
return leftSide === rightSide;
});
This component could be used in a template by supplying it an array of strings
as content
and an action to call when the user makes a selection as change
:
A more complete example of a select
component that mimics many features of the
deprecated Ember.Select
is available in this jsbin.
Here is an example jsbin showing usage of the select tag directly in a template without a component.
There are many Ember-CLI addons that provide select-like functionality.
emberx-select in particular
aims to provide a select component based on the native html select. Alternative
select
component implementations can be iterated upon in addons to identify
best practices and perhaps moved into an official Ember 2.x implementation in
the future.
§ Ember.View
Ember 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. However a single release is likely insufficient for large apps to upgrade their entire codebase away from routable views, and consequently Ember is providing extended support for views via the ember-legacy-views addon. This addon will remain compatible with Ember until v2.4 of the framework is released.
Along with the deprecation of Ember.View
, the Ember.CoreView
class is also
deprecated. If you were using this class, please migrate to Ember.Component
.
Migrating away from the view helper
In most cases Ember views can be replaced with a component. For example this view and usage:
import Ember from "ember";
// Usage: {{view "show-menu"}}
export default Ember.View.extend({
templateName: 'some-menu',
title: 'My Menu'
});
Can be replaced with this component:
import Ember from "ember";
// Usage: {{show-menu}}
export default Ember.Component.extend({
title: 'My Menu'
});
Note that a component is always its own context in a template. A view's template
may have had access to other variables that were present where it was called,
such as a controller
. A component template will always be isolated, and
if data is needed it should be passed upon invocation. For example:
Differences in yielded blocks
Some notable differences exist between yielded view blocks and yielded component blocks. A view could be used this way:
import Ember from "ember";
export default Ember.View.extend({
reversedName: Ember.computed('name', function() {
return this.get('name').split("").reverse().join("");
})
});
Components introduced block params. This concept achieves data passing
without the confusion over what {{view}}
refers to. For example:
import Ember from "ember";
export default Ember.Component.extend({
reversedName: Ember.computed('name', function() {
return this.get('name').split("").reverse().join("");
})
});
Just as passing values to a component allow access to those values in the isolated template of that component, yielding block params allow for values from the component to be passed to the location the component was called at.
Routable Views
When a template for a given route is rendered, if there is a view with the same name that view will also be used. For example this view is attached to the rendered route template:
import Ember from "ember";
export default Ember.Router.map(function() {
this.route('about');
});
import Ember from "ember";
export default Ember.View.extend({
classNameBindings: ['controller.isActive:active']
});
There are only two reasons a view may be used for a route.
- To set attribute bindings
- To attach event handlers
You should migrate away from routed views. For example to attach bindings an element in the template is sufficient:
import Ember from "ember";
export default Ember.Router.map(function() {
this.route('about');
});
If attaching events or sharing DOM is necessary, consider a component:
import Ember from "ember";
export default Ember.Router.map(function() {
this.route('about');
});
import Ember from "ember";
export default Ember.Component.extend({
classNameBindings: ['isActive:active'],
click() {
// Handle click
}
});
view and controller template keywords
View and controller keywords provided a way to access the view or controller backing a template, even across scopes that you might expect to be isolated. In many ways their behavior is emergent, and generally is poorly designed.
Accessing data via {{view.someProp}}
or {{controller.thisThing}}
can
nearly always be replaced by proper use of data passing and block params. See
the guide on differences in yielded blocks
for a complete example of using block params over the {{view}}
keyword.
view
and viewClass
arguments to {{outlet}}
Since the View API is deprecated starting in 1.13, providing the view
or viewClass
argument to the {{outlet}}
helper is likewise deprecated in favor of migrating to component-based approaches, as explained earlier in this
section.
§ Ember.EnumerableUtils
EnumerableUtils
has been deprecated in favor of native implementations. You can consult the
JavaScript Array documentation
to find suitable replacements for EnumerableUtils
functionality.
If the native JavaScript array object does not provide a suitable equivalent for your needs, you might also want to checkout
third party utility libraries like lodash, or underscore.
§ Handlebars / HTMLBars helpers
All the various ways to create helpers on the Handlebars and HTMLBars namespace
have been deprecated in favor of the
Ember.Helper class and it's
Ember.Helper.helper
function. The makeViewHelper
method has been deprecated in favor of just using
an Ember.Component
.
makeViewHelper
If you use viewHelper
you should refactor the view class and template into
a component with the same name as the view helper you registered.
makeBoundHelper
, registerBoundHelper
, helper
, registerHelper
If you have for example:
export default Ember.HTMLBars.makeBoundHelper(function(firstArg, secondArg, options) {
let { hash } = options;
// helper code
});
or
Ember.Handlebars.registerHelper('foo-bar', function(firstArg, secondArg, options) {
let { hash } = options;
// helper code
});
you can replace those with:
export default Ember.Helper.helper(function([firstArg, secondArg], hash) {
// helper code
});
§ Ember.immediateObserver
Ember.immediateObserver
is deprecated in favor of Ember.observer
. Please change all instances of Ember.immediateObserver
from:
Ember.Object.extend({
valueObserver: Ember.immediateObserver('value', function() {
})
});
to
Ember.Object.extend({
valueObserver: Ember.observer('value', function() {
})
});
§ Modifying a Property within didInsertElement
Because of changes in the way Ember renders components in 1.13, setting properties within an overridden didInsertElement
method
will result in a deprecation warning.
In many cases you can move your logic earlier in the component lifecycle by implementing the didReceiveAttrs
hook, one of
the new hooks introduced in 1.13.
didReceiveAttrs() {
this._super(...arguments);
this.set('myValue', value);
}
It may even be possible, if your value is constant, to move the change to init
, where the value can only be set once.
init() {
this._super(...arguments);
this.set('myValue', myValue);
}
Don't see a set
in your didInsertElement
? It may be in didUpdate
or didRender
. Due to a bug, these report the wrong method name.
Still can't find it?
- One of your computed properties may be calling
set
. - An observer is being triggered.
- One of your child components may be setting one of its attributes and it is being propagated upward to this component.
In rare cases, you may be measuring the DOM rendered and want to set an attribute based on that. In this case, it is ok to cause a second render:
didInsertElement() {
this._super(...arguments);
run.schedule('afterRender', this, this.measureAndSet);
},
measureAndSet() {
this.set('height', this.element.children.length * 30);
}
However, doing so is relatively slow and should be done as a last resort.
§
Non-Standard Ways of Calling Ember.set
and Ember.get
Ember is deprecating calls to get
and set
made in non-standard ways. Below are examples
of the calls that are now deprecated:
// referencing properties with globals
Ember.set(null, 'App.foo', bar);
Ember.set('App.foo', bar);
Ember.get(null, 'App.foo');
Ember.get('App.foo');
// referencing properties with 'this'
Ember.set(obj, 'this.foo', bar);
Ember.get(obj, 'this.foo');
// providing a null context
Ember.set(null, 'foo', bar);
Ember.get(null, 'foo');
// providing a non-string property
Ember.set(obj, 42, bar);
Ember.get(obj, 42);
§
Overriding render
When Extending a Component or View
The render
method on components and views should not be overridden and will
go away in Ember 2.x. Modifications to Ember rendering should be made by
overriding Ember's new
component lifecycle hooks
, introduced in version 1.13.
§ RenderBuffer
With the change to the rendering process in Glimmer, the RenderBuffer is no longer used by Ember and will be removed. The class was originally private, and any reference to it should be removed.
§ Reversed Ember.observer Arguments
A little known feature of the observer function allowed for the arguments to be listed in the opposite order, with function first:
Ember.observer(function() {
// React to observer firing here
}, 'property1', 'property2')
This syntax was deprecated in Ember 1.13.5. The above code sample should be replaced with the standard syntax that lists the observed properties, then the function as the last argument:
Ember.observer('property1', 'property2', function() {
// React to observer firing here
})
§ Set positionalParams as a static property on the class
Setting positionalParams
within .extend
is deprecated. It has to be set as a static property on the class itself (.reopenClass
).
Please change this:
import Ember from 'ember';
export default Ember.Component.extend({
positionalParams: [ 'a', 'b' ]
});
to this:
import Ember from 'ember';
var Thing = Ember.Component.extend();
Thing.reopenClass({
positionalParams: [ 'a', 'b' ]
});
§ SortableMixin
Along with Ember.ArrayController
, Ember.SortableMixin
will be removed in Ember 2.0.
You can migrate away from using Ember.SortableMixin
by using Ember.computed.sort
. Using this example:
const SongsController = Ember.ArrayController.extend(Ember.SortableMixin, {
model: null,
sortProperties: ['trackNumber'],
sortAscending: false
});
let songsController = SongsController.create({ songs: songList });
You can transition to using Ember.computed.sort
like this:
const SongsController = Ember.Controller.extend({
model: null,
sortedSongs: Ember.computed.sort('model', 'songSorting'),
songSorting: ['trackNumber:desc']
});
let songsController = SongsController.create({ songs: songList });
You can read more about Ember.computed.sort in the Ember API documentation
Legacy support of Ember.SortableMixin
will be provided via the ember-legacy-controllers addon.
§
Using @each
as a leaf node in a dependent key
Using @each
at the end of a computed key is deprecated and will not work in
Ember 2.0
invalid: Ember.computed('myObject.@each', function () {
//no longer valid for monitoring changes to arrays
});
When defining dependent keys for computed properties, ember 2.0+ will treat
@each
and []
differently.
@each
will monitor specific properties within an array of objects.
eachProp: Ember.computed('myObj.posts.@each.title', function () {
//fired whenever one of the blog post titles is changed.
});
[]
will monitor mutations to the array.
arrProp: Ember.computed('myObj.posts.[]', function () {
//fired whenever a blog post is added or removed
});
§ Using @guid and @item as key in {{each}}
As of 1.13.2 you should not use key='@guid'
or key='@item'
in the {{each}}
helper. It is
documented in 1.13
that you can use these special values to uniquely identify each array entry so that the view code could
more efficiently re-render the display of the list.
This process was simplified as part of a bugfix,
where the key now implicitly defaults to @identity
, which will pick either a guid or an item identifier based on type
of each array entry. Therefore, providing the key attribute is no longer required for re-render optimizations.
Applications should replace instances of:
...
and
...
with
...
§
Using /
for namespace in the {{render}}
helper
When using the render helper, its possible to specify a context within a nested directory structure. Prior to 1.13, it
was acceptable to separate nested directories using slashes /
, but this is now deprecated, as Ember has
settled on using dot notation for namespacing.
For example, a developer might have a controller at app/controllers/blog/posts.js
and is using the render helper to
render that controller context within another template.
Instead of using {{render 'blog/posts'}}
, use {{render 'blog.posts'}}
. That will render the template associated with
app/controllers/blog/posts.js
in your directory structure.
§
Using the {{with}}
Helper with the controller
option
Another option deprecated due to the de-emphasis of controllers is the controller
option used with the {{with}}
helper. In prior versions it was possible to
specify a controller when using {{with}}
, which would use an instance of the
specified controller as the context within the block.
{{#with item.posts controller="myposts"}}
{{!- numPosts fetched from the controller instance "myposts" }}
There are {{numPosts}} posts.
{{with}
Similar to the deprecated {{each}} helper controller options , this approach triggers less performant compatibility code and is deprecated in favor of using local properties or components.
Using local properties
{{#with item.posts as |myPosts|}}
There are {{myPosts.length}} posts.
{{with}}
Using a component
{{! prints the number of posts (if available) }}
{{post-status posts=item.posts}}
§
Using this.get('template')
Prior to 1.13, developers had to check for the existance of the internal template
property to determine the existance of a yielded block.
This is being deprecated in favor of using the new hasBlock
property within your templates.
Determining if a block has been provided from JavaScript
Currently the hasBlock
property is not made available from the JavaScript component object,
so there is no clean alternative for checking whether a block has been passed.
See the JavaScript hasBlock RFC for discussion on making this information
available in the future, as well as possible workarounds.
§
Using TrackedArray
or SubArray
TrackedArray
and SubArray
were internal classes used as implementation
details of ArrayComputed
. ArrayComputed
is deprecated to be removed
in version 2.0.0. As a result, these 2 private classes will be removed as
well.
§
View and Controller options on the {{each}}
helper
The options itemView
, itemViewClass
, tagName
, emptyView
,
emptyViewClass
and itemController
on the {{each}}
helper have been deprecated.
These options were added when controllers were more prominent, and the component story was less fully fleshed out. In Ember 1.13+, using these options triggers a less performant compatibility mode.
The usage of all the above mentioned options should be replaced with components.
An example
Can be replaced with:
<ul>
</ul>
Breaking the example down
The comment
controller and commentView
view have been refactored into the
{{post-comment}}
component.
The noCommentsView
has been refactored in to the {{no-comments}}
component.
Instead of the itemController="comment"
and itemView="commentView"
we use
the newly created {{post-comment}}
component.
Instead of the emptyView="noCommentsView"
we use the {{no-comments}}
component.
We replaced tagName="ul"
part by just surrounding the {{each}}
block with
<ul>
tags.