Configuring Ember.js
Disabling Prototype Extensions
By default, Ember.js will extend the prototypes of native JavaScript objects in the following ways:
-
Arrayis extended to implement theEmber.Enumerable,Ember.MutableEnumerable,Ember.MutableArrayandEmber.Arrayinterfaces. This polyfills ECMAScript 5 array methods in browsers that do not implement them, adds convenience methods and properties to built-in arrays, and makes array mutations observable. -
Stringis extended to add convenience methods, such ascamelize()andfmt(). -
Functionis extended with methods to annotate functions as computed properties, via theproperty()method, and as observers, via theobserves()orobservesBefore()methods.
This is the extent to which Ember.js enhances native prototypes. We have carefully weighed the tradeoffs involved with changing these prototypes, and recommend that most Ember.js developers use them. These extensions significantly reduce the amount of boilerplate code that must be typed.
However, we understand that there are cases where your Ember.js application may be embedded in an environment beyond your control. The most common scenarios are when authoring third-party JavaScript that is embedded directly in other pages, or when transitioning an application piecemeal to a more modern Ember.js architecture.
In those cases, where you can’t or don’t want to modify native prototypes, Ember.js allows you to completely disable the extensions described above.
To do so, simply set the EXTEND_PROTOTYPES flag to false:
1 window.ENV = {};
2 ENV.EXTEND_PROTOTYPES = false;
Note that the above code must be evaluated before Ember.js loads. If you set the flag after the Ember.js JavaScript file has been evaluated, the native prototypes will already have been modified.
Life Without Prototype Extension
In order for your application to behave correctly, you will need to manually extend or create the objects that the native objects were creating before.
Arrays
Native arrays will no longer implement the functionality needed to
observe them. If you disable prototype extension and attempt to use
native arrays with things like a template’s {{#each}} helper, Ember.js
will have no way to detect changes to the array and the template will
not update as the underlying array changes.
Additionally, if you try to set the model of an
Ember.ArrayController to a plain native array, it will raise an
exception since it no longer implements the Ember.Array interface.
You can manually coerce a native array into an array that implements the
required interfaces using the convenience method Ember.A:
1 var islands = ['Oahu', 'Kauai'];
2 islands.contains('Oahu');
3 //=> TypeError: Object Oahu,Kauai has no method 'contains'
4
5 // Convert `islands` to an array that implements the
6 // Ember enumerable and array interfaces
7 Ember.A(islands);
8
9 islands.contains('Oahu');
10 //=> true
Strings
Strings will no longer have the convenience methods described in the
Ember.String API reference.. Instead,
you can use the similarly-named methods of the Ember.String object and
pass the string to use as the first parameter:
1 "my_cool_class".camelize();
2 //=> TypeError: Object my_cool_class has no method 'camelize'
3
4 Ember.String.camelize("my_cool_class");
5 //=> "myCoolClass"
Functions
To annotate computed properties, use the Ember.computed() method to
wrap the function:
1 // This won't work:
2 fullName: function() {
3 return this.get('firstName') + ' ' + this.get('lastName');
4 }.property('firstName', 'lastName')
5
6
7 // Instead, do this:
8 fullName: Ember.computed('firstName', 'lastName', function() {
9 return this.get('firstName') + ' ' + this.get('lastName');
10 })
Observers are annotated using Ember.observer():
1 // This won't work:
2 fullNameDidChange: function() {
3 console.log("Full name changed");
4 }.observes('fullName')
5
6
7 // Instead, do this:
8 fullNameDidChange: Ember.observer('fullName', function() {
9 console.log("Full name changed");
10 })
Embedding Applications
In most cases, your application’s entire UI will be created by templates that are managed by the router.
But what if you have an Ember.js app that you need to embed into an existing page, or run alongside other JavaScript frameworks?
Changing the Root Element
By default, your application will render the application
template and attach it to
the document’s body element.
You can tell the application to append the application template to a
different element by specifying its rootElement property:
1 App = Ember.Application.create({
2 rootElement: '#app'
3 });
This property can be specified as either an element or a jQuery-compatible selector string.
Disabling URL Management
You can prevent Ember from making changes to the URL by changing the
router’s location to
none:
1 App.Router = Ember.Router.extend({
2 location: 'none'
3 });
Feature Flags
About Features
When a new feature is added to Ember they will be written in such a way that the feature can be conditionally included in the generated build output and enabled (or completely removed) based on whether a particular flag is present. This allows newly developed features to be selectively released when they are considered ready for production use.
Feature Life-Cycle
When a new feature is flagged it is only available in canary builds (if enabled
at runtime). When it is time for the next beta cycle to be started (generally
6-12 week cycles) each feature will be evaluated and those features that are
ready will be enabled in the next beta (and subsequently automatically enabled
in all future canary builds).
If a given feature is deemed unstable it will be disabled in the next beta point release, and not be included in the next stable release. It may still be included in the next beta cycle if the issues/concerns have been resolved.
Once the beta cycle has completed the final release will include any features that were enabled during that cycle. At this point the feature flags will be removed from the canary and future beta branches, and the feature flag will no longer be used.
Flagging Details
The flag status in the generated build output is controlled by the features.json
file in the root of the project. This file lists all features and their current
status.
A feature can have one of a few different statuses:
-
true- The feature is enabled: the code behind the flag is always enabled in the generated build. -
false- The feature is disabled: the code behind the flag is not present in the generated build at all. -
null- The feature is present in the build output, but must be enabled at runtime (it is still behind feature flags).
The process of removing the feature flags from the resulting build output is
handled by defeatureify.
Feature Listing (FEATURES.md)
When a new feature is added to the canary channel (aka master branch), an
entry is added to FEATURES.md
explaining what the feature does (and linking the originating pull request).
This listing is kept current, and reflects what is available in each branch
(stable,beta, and master).
Enabling At Runtime
The only time a feature can be enabled at runtime is if the
features.json for that build contains null (technically, anything other
than true or false will do, but null is the chosen value).
A global EmberENV object will be used to initialize the Ember.ENV
object, and any feature flags that are enabled/disabled under
EmberENV.FEATURES will be migrated to Ember.FEATURES; those features
will be enabled based on the flag value. Ember only reads the
EmberENV value upon initial load so setting this value after Ember has
been loaded will have no affect.
Example:
1 EmberENV = {FEATURES: {'link-to': true}};
Additionally you can define EmberENV.ENABLE_ALL_FEATURES to force all
features to be enabled.