/**
@module @ember/component
*/
import { DirtyableTag } from '@glimmer/reference';
import { FrameworkObject } from 'ember-runtime';
import { symbol } from 'ember-utils';
export const RECOMPUTE_TAG = symbol('RECOMPUTE_TAG');
export function isHelperFactory(helper) {
return (typeof helper === 'object' && helper !== null && helper.class && helper.class.isHelperFactory);
}
export function isSimpleHelper(helper) {
return helper.destroy === undefined;
}
/**
Ember Helpers are functions that can compute values, and are used in templates.
For example, this code calls a helper named `format-currency`:
```handlebars
{{format-currency cents currency="$"}}
```
Additionally a helper can be called as a nested helper (sometimes called a
subexpression). In this example, the computed value of a helper is passed
to a component named `show-money`:
```handlebars
{{show-money amount=(format-currency cents currency="$")}}
```
Helpers defined using a class must provide a `compute` function. For example:
```app/helpers/format-currency.js
import Helper from '@ember/component/helper';
export default Helper.extend({
compute([cents], { currency }) {
return `${currency}${cents * 0.01}`;
}
});
```
Each time the input to a helper changes, the `compute` function will be
called again.
As instances, these helpers also have access to the container and will accept
injected dependencies.
Additionally, class helpers can call `recompute` to force a new computation.
@class Helper
@public
@since 1.13.0
*/
let Helper = FrameworkObject.extend({
init() {
this._super(...arguments);
this[RECOMPUTE_TAG] = DirtyableTag.create();
},
/**
On a class-based helper, it may be useful to force a recomputation of that
helpers value. This is akin to `rerender` on a component.
For example, this component will rerender when the `currentUser` on a
session service changes:
```app/helpers/current-user-email.js
import Helper from '@ember/component/helper'
import { inject as service } from '@ember/service'
import { observer } from '@ember/object'
export default Helper.extend({
session: service(),
onNewUser: observer('session.currentUser', function() {
this.recompute();
}),
compute() {
return this.get('session.currentUser.email');
}
});
```
@method recompute
@public
@since 1.13.0
*/
recompute() {
this[RECOMPUTE_TAG].inner.dirty();
},
});
Helper.isHelperFactory = true;
class Wrapper {
constructor(compute) {
this.compute = compute;
this.isHelperFactory = true;
}
create() {
// needs new instance or will leak containers
return {
compute: this.compute,
};
}
}
/**
In many cases, the ceremony of a full `Helper` class is not required.
The `helper` method create pure-function helpers without instances. For
example:
```app/helpers/format-currency.js
import { helper } from '@ember/component/helper';
export default helper(function(params, hash) {
let cents = params[0];
let currency = hash.currency;
return `${currency}${cents * 0.01}`;
});
```
@static
@param {Function} helper The helper function
@method helper
@for @ember/component/helper
@public
@since 1.13.0
*/
export function helper(helperFn) {
return new Wrapper(helperFn);
}
export default Helper;