Function
setHelperManager (factory, definition) Object public
Defined in packages/@ember/helper/index.ts:58
import { setHelperManager } from '@ember/helper'; |
- factory
- Function
- A factory function which receives an optional owner, and returns a helper manager
- definition
- Object
- The definition to associate the manager factory with
- returns
- Object
- The definition passed into setHelperManager
Sets the helper manager for an object or function.
1 |
setHelperManager((owner) => new ClassHelperManager(owner), Helper) |
When a value is used as a helper in a template, the helper manager is looked up on the object by walking up its prototype chain and finding the first helper manager. This manager then receives the value and can create and manage an instance of a helper from it. This provides a layer of indirection that allows users to design high-level helper APIs, without Ember needing to worry about the details. High-level APIs can be experimented with and iterated on while the core of Ember helpers remains stable, and new APIs can be introduced gradually over time to existing code bases.
setHelperManager
receives two arguments:
- A factory function, which receives the
owner
and returns an instance of a helper manager. - A helper definition, which is the object or function to associate the factory function with.
The first time the object is looked up, the factory function will be called to create the helper manager. It will be cached, and in subsequent lookups the cached helper manager will be used instead.
Only one helper manager is guaranteed to exist per owner
and per usage of
setHelperManager
, so many helpers will end up using the same instance of the
helper manager. As such, you should only store state that is related to the
manager itself. If you want to store state specific to a particular helper
definition, you should assign a unique helper manager to that helper. In
general, most managers should either be stateless, or only have the owner
they
were created with as state.
Helper managers must fulfill the following interface (This example uses TypeScript interfaces for precision, you do not need to write helper managers using TypeScript):
1 2 3 4 5 6 7 8 9 10 11 |
interface HelperManager<HelperStateBucket> { capabilities: HelperCapabilities; createHelper(definition: HelperDefinition, args: TemplateArgs): HelperStateBucket; getValue?(bucket: HelperStateBucket): unknown; runEffect?(bucket: HelperStateBucket): void; getDestroyable?(bucket: HelperStateBucket): object; } |
The capabilities property must be provided using the capabilities()
function
imported from the same module as setHelperManager
:
1 2 3 4 5 6 7 |
import { capabilities } from '@ember/helper'; class MyHelperManager { capabilities = capabilities('3.21.0', { hasValue: true }); // ...snip... } |
Below is a description of each of the methods on the interface and their functions.
createHelper
createHelper
is a required hook on the HelperManager interface. The hook is
passed the definition of the helper that is currently being created, and is
expected to return a state bucket. This state bucket is what represents the
current state of the helper, and will be passed to the other lifecycle hooks at
appropriate times. It is not necessarily related to the definition of the
helper itself - for instance, you could return an object containing an
instance of the helper:
1 2 3 4 5 6 7 |
class MyManager { createHelper(Definition, args) { return { instance: new Definition(args); }; } } |
This allows the manager to store metadata that it doesn't want to expose to the user.
This hook is not autotracked - changes to tracked values used within this hook will not result in a call to any of the other lifecycle hooks. This is because it is unclear what should happen if it invalidates, and rather than make a decision at this point, the initial API is aiming to allow as much expressivity as possible. This could change in the future with changes to capabilities and their behaviors.
If users do want to autotrack some values used during construction, they can
either create the instance of the helper in runEffect
or getValue
, or they
can use the cache
API to autotrack the createHelper
hook themselves. This
provides maximum flexibility and expressiveness to manager authors.
This hook has the following timing semantics:
Always
- called as discovered during DOM construction
- called in definition order in the template
getValue
getValue
is an optional hook that should return the value of the helper. This
is the value that is returned from the helper and passed into the template.
This hook is called when the value is requested from the helper (e.g. when the template is rendering and the helper value is needed). The hook is autotracked, and will rerun whenever any tracked values used inside of it are updated. Otherwise it does not rerun.
Note: This means that arguments which are not consumed within the hook will not trigger updates.
This hook is only called for helpers with the hasValue
capability enabled.
This hook has the following timing semantics:
Always
- called the first time the helper value is requested
- called after autotracked state has changed
Never
- called if the
hasValue
capability is disabled
runEffect
runEffect
is an optional hook that should run the effect that the helper is
applying, setting it up or updating it.
This hook is scheduled to be called some time after render and prior to paint. There is not a guaranteed, 1-to-1 relationship between a render pass and this hook firing. For instance, multiple render passes could occur, and the hook may only trigger once. It may also never trigger if it was dirtied in one render pass and then destroyed in the next.
The hook is autotracked, and will rerun whenever any tracked values used inside of it are updated. Otherwise it does not rerun.
The hook is also run during a time period where state mutations are disabled
in Ember. Any tracked state mutation will throw an error during this time,
including changes to tracked properties, changes made using Ember.set
, updates
to computed properties, etc. This is meant to prevent infinite rerenders and
other antipatterns.
This hook is only called for helpers with the hasScheduledEffect
capability
enabled. This hook is also not called in SSR currently, though this could be
added as a capability in the future. It has the following timing semantics:
Always
- called after the helper was first created, if the helper has not been destroyed since creation
- called after autotracked state has changed, if the helper has not been destroyed during render
Never
- called if the
hasScheduledEffect
capability is disabled - called in SSR
getDestroyable
getDestroyable
is an optional hook that users can use to register a
destroyable object for the helper. This destroyable will be registered to the
containing block or template parent, and will be destroyed when it is destroyed.
See the Destroyables RFC
for more details.
getDestroyable
is only called if the hasDestroyable
capability is enabled.
This hook has the following timing semantics:
Always
- called immediately after the
createHelper
hook is called
Never
- called if the
hasDestroyable
capability is disabled