Summary
This RFC proposes allowing parameters to be passed to the {{mount}}
syntax.
Motivation
This will enable developers to pass contextual data into routeless engines at runtime, allowing individual engines to be used multiple times through a single application under different contexts.
An example could be a dashboard of charts where each chart is a routeless engine. Each chart could be of a different type and would require different data. This RFC would enable the following:
{{!-- app/templates/application.hbs --}}
{{#each charts as |chart|}}
{{mount "chart" type=chart.type data=chart.data}}
{{/each}}
Detailed design
You can see the implementation for this RFC here.
Implementing this functionality turns out to be relatively straight forward. With routeless engines already supporting an application controller, we can use this as a means of providing access to the parameters.
Parameters would be passed to the {{mount}}
syntax in the same way that
they are currently passed to components and helpers.
{{mount "foo" bar="baz"}}
These parameters would then be set as the model
property on the engines
application controller; making them accessible from both a JS and HBS context.
// foo/controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
exampleAction() {
let barParam = this.get("model.bar");
}
}
});
{{!-- foo/templates/application.hbs --}}
The value of the bar param is: {{model.bar}}
How We Teach This
This RFC re-uses concepts that are already heavily used throughout other areas of the framework.
Updates will need to be made to the Ember API docs and ember-engines.com guides in order to explain that
routeless engines can now accept parameters being passed via the {{mount}}
syntax.
In addition, updates would need to include examples of both how to pass parameters
to {{mount}}
as well as how any passed parameters can be accessed from within
the context of an engine.
Drawbacks
Increased risk of runtime dependencies [reference]
This RFC does increase the risk of introducing runtime dependencies.
Example:
import Ember from 'ember';
export default Ember.Component.extend({
geo: Ember.inject.service('geolocation')
})
{{mount "blog" (hash geo=geo)}}
Alternatives
Application route model
hook
This solution suggested that the parameters were provided to the engines
application route via the model
hooks params
argument. While viable,
this solution didn't feel quite right as you were using a route within a routeless
engine.
Introduction of new routelessEngine
primitive
This solution suggested that routeless engines should be given their own primitive
similar to that of a component. The primitive would follow a construct to
components and use the same hooks (e.g., didReceiveAttrs)
for working with
parameters.
This solution was decided against for following main reasons:
- The current public API is that we use
application
controller to back theapplication.hbs
of a route-less engine. Adding a new conceptual primitive here would be a fairly difficult change without breakage. - Introducing a new primitive (e.g. not controller and not a component) is a very heavy handed thing, and should not be taken lightly. We don't think this rises to that level of need.
- This is an ideal case for "just using a component", but that would be roughly akin to "routable components" and we should follow Ember's lead. When routeable components are introduced, we can refactor this in the same way with the same backwards compatibility guarantees.
Unresolved questions
Positional parameters
In addition to supporting named parameters, should the {{mount}}
syntax also
support positional parameters? If so, should this be covered in this RFC, or
in a follow up RFC?