Class Engine

public

The Engine class contains core functionality for both applications and engines.

Each engine manages a registry that's used for dependency injection and exposed through RegistryProxy.

Engines also manage initializers and instance initializers.

Engines can spawn EngineInstance instances via buildInstance().

Show:

Module: @ember/engine
returns
EngineInstance
the engine instance

Create an EngineInstance for this engine.

Module: @ember/engine
fullName
String
returns
Boolean

Check if a factory is registered.

Module: @ember/engine
initializer
Object

The goal of initializers should be to register dependencies and injections. This phase runs once. Because these initializers may load code, they are allowed to defer application readiness and advance it. If you need to access the container or store you should use an InstanceInitializer that will be run after all initializers and therefore after all code is loaded and the app is ready.

Initializer receives an object which has the following attributes: name, before, after, initialize. The only required attribute is initialize, all others are optional.

  • name allows you to specify under which name the initializer is registered. This must be a unique name, as trying to register two initializers with the same name will result in an error.
initializer.js
1
2
3
4
5
6
7
8
9
10
import { debug } from '@ember/debug';

export function initialize() {
  debug('Running namedInitializer!');
}

export default {
  name: 'named-initializer',
  initialize
};
  • before and after are used to ensure that this initializer is ran prior or after the one identified by the value. This value can be a single string or an array of strings, referencing the name of other initializers.

An example of ordering initializers, we create an initializer named first:

app/initializer/first.js
1
2
3
4
5
6
7
8
9
10
import { debug } from '@ember/debug';

export function initialize() {
  debug('First initializer!');
}

export default {
  name: 'first',
  initialize
};
1
// DEBUG: First initializer!

We add another initializer named second, specifying that it should run after the initializer named first:

app/initializer/second.js
1
2
3
4
5
6
7
8
9
10
11
import { debug } from '@ember/debug';

export function initialize() {
  debug('Second initializer!');
}

export default {
  name: 'second',
  after: 'first',
  initialize
};
1
2
// DEBUG: First initializer!
// DEBUG: Second initializer!

Afterwards we add a further initializer named pre, this time specifying that it should run before the initializer named first:

app/initializer/pre.js
1
2
3
4
5
6
7
8
9
10
11
import { debug } from '@ember/debug';

export function initialize() {
  debug('Pre initializer!');
}

export default {
  name: 'pre',
  before: 'first',
  initialize
};
1
2
3
// DEBUG: Pre initializer!
// DEBUG: First initializer!
// DEBUG: Second initializer!

Finally we add an initializer named post, specifying it should run after both the first and the second initializers:

app/initializer/post.js
1
2
3
4
5
6
7
8
9
10
11
import { debug } from '@ember/debug';

export function initialize() {
  debug('Post initializer!');
}

export default {
  name: 'post',
  after: ['first', 'second'],
  initialize
};
1
2
3
4
// DEBUG: Pre initializer!
// DEBUG: First initializer!
// DEBUG: Second initializer!
// DEBUG: Post initializer!
  • initialize is a callback function that receives one argument, application, on which you can operate.

Example of using application to register an adapter:

adapter.js
1
2
3
4
5
6
7
8
9
10
11
import ApiAdapter from '../utils/api-adapter';

export function initialize(application) {
  application.register('api-adapter:main', ApiAdapter);
}

export default {
  name: 'post',
  after: ['first', 'second'],
  initialize
};
Module: @ember/engine
instanceInitializer

Instance initializers run after all initializers have run. Because instance initializers run after the app is fully set up. We have access to the store, container, and other items. However, these initializers run after code has loaded and are not allowed to defer readiness.

Instance initializer receives an object which has the following attributes: name, before, after, initialize. The only required attribute is initialize, all others are optional.

  • name allows you to specify under which name the instanceInitializer is registered. This must be a unique name, as trying to register two instanceInitializer with the same name will result in an error.
initializer.js
1
2
3
4
5
6
7
8
9
10
import { debug } from '@ember/debug';

export function initialize() {
  debug('Running named-instance-initializer!');
}

export default {
  name: 'named-instance-initializer',
  initialize
};
  • before and after are used to ensure that this initializer is ran prior or after the one identified by the value. This value can be a single string or an array of strings, referencing the name of other initializers.

  • See Application.initializer for discussion on the usage of before and after.

Example instanceInitializer to preload data into the store.

data.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
export function initialize(application) {
    var userConfig, userConfigEncoded, store;
    // We have a HTML escaped JSON representation of the user's basic
    // configuration generated server side and stored in the DOM of the main
    // index.html file. This allows the app to have access to a set of data
    // without making any additional remote calls. Good for basic data that is
    // needed for immediate rendering of the page. Keep in mind, this data,
    // like all local models and data can be manipulated by the user, so it
    // should not be relied upon for security or authorization.

    // Grab the encoded data from the meta tag
    userConfigEncoded = document.querySelector('head meta[name=app-user-config]').attr('content');

    // Unescape the text, then parse the resulting JSON into a real object
    userConfig = JSON.parse(unescape(userConfigEncoded));

    // Lookup the store
    store = application.lookup('service:store');

    // Push the encoded JSON into the store
    store.pushPayload(userConfig);
}

export default {
  name: 'named-instance-initializer',
  initialize
};
Module: @ember/engine
fullName
String
type:name (e.g., 'model:user')
factory
Any
(e.g., App.Person)
options
Object
(optional) disable instantiation or singleton usage

Registers a factory that can be used for dependency injection (with inject) or for service lookup. Each factory is registered with a full name including two parts: type:name.

A simple example:

1
2
3
4
5
6
7
import Application from '@ember/application';
import EmberObject from '@ember/object';

let App = Application.create();

App.Orange = EmberObject.extend();
App.register('fruit:favorite', App.Orange);

Ember will resolve factories from the App namespace automatically. For example App.CarsController will be discovered and returned if an application requests controller:cars.

An example of registering a controller with a non-standard name:

1
2
3
4
5
6
7
8
9
10
11
12
13
import Application from '@ember/application';
import Controller from '@ember/controller';

let App = Application.create();
let Session = Controller.extend();

App.register('controller:session', Session);

// The Session controller can now be treated like a normal controller,
// despite its non-standard name.
App.ApplicationController = Controller.extend({
  needs: ['session']
});

Registered factories are instantiated by having create called on them. Additionally they are singletons, each time they are looked up they return the same instance.

Some examples modifying that default behavior:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Application from '@ember/application';
import EmberObject from '@ember/object';

let App = Application.create();

App.Person = EmberObject.extend();
App.Orange = EmberObject.extend();
App.Email = EmberObject.extend();
App.session = EmberObject.create();

App.register('model:user', App.Person, { singleton: false });
App.register('fruit:favorite', App.Orange);
App.register('communication:main', App.Email, { singleton: false });
App.register('session', App.session, { instantiate: false });
Module: @ember/engine
fullName
String
options
Object

Register options for a particular factory.

Module: @ember/engine
type
String
options
Object

Allow registering options for all factories of a type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Application from '@ember/application';

let App = Application.create();
let appInstance = App.buildInstance();

// if all of type `connection` must not be singletons
appInstance.registerOptionsForType('connection', { singleton: false });

appInstance.register('connection:twitter', TwitterConnection);
appInstance.register('connection:facebook', FacebookConnection);

let twitter = appInstance.lookup('connection:twitter');
let twitter2 = appInstance.lookup('connection:twitter');

twitter === twitter2; // => false

let facebook = appInstance.lookup('connection:facebook');
let facebook2 = appInstance.lookup('connection:facebook');

facebook === facebook2; // => false
Module: @ember/engine
fullName
String
optionName
String
returns
Object
options

Return a specific registered option for a particular factory.

Module: @ember/engine
fullName
String
returns
Object
options

Return registered options for a particular factory.

Module: @ember/engine
type
String
returns
Object
options

Return the registered options for all factories of a type.

Module: @ember/engine
fullName
String
returns
Function
fullName's factory

Given a fullName return the corresponding factory.

Module: @ember/engine
fullName
String

Unregister a factory.

1
2
3
4
5
6
7
8
9
10
11
import Application from '@ember/application';
import EmberObject from '@ember/object';

let App = Application.create();
let User = EmberObject.extend();
App.register('model:user', User);

App.resolveRegistration('model:user').create() instanceof User //=> true

App.unregister('model:user')
App.resolveRegistration('model:user') === undefined //=> true