ember-box
v0.1.0
Published
An experimental helper for better 2-way-binding
Downloads
4
Readme
ember-box
An experimental helper for better 2-way-binding:
<Input @value={{box this.value}} />
Implementing Input
:
<input
value={{unwrap @value}}
{{on "input" this.onInput}}
>
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { update } from 'ember-box';
export default class Input extends Component {
@action
onInput({ target: { value } }) {
update(this.args.value, value);
if (this.args.onInput) {
this.args.onInput(value);
}
}
}
Compatibility
- Ember.js v2.18 or above
- Ember CLI v2.13 or above
- Node.js v8 or above
Installation
ember install ember-box
Usage
ember-box
provides the following helpers:
{{box}}
{{wrap}}
{{unwrap}}
{{update}}
And their corresponding functions:
import {
box,
wrap,
unwrap,
update
} from 'ember-box';
The main helper is the box
helper, which receives a path and returns a Box,
which is a reference to that value:
{{box this.myValue}}
This box can be passed around, and the value it references can be accessed or updated wherever it goes:
import Component from '@glimmer/component';
export default class MyComponent extends Component {
this.value = 123;
}
{{#let (box this.value) as |value|}}
<!-- This will output 123 -->
{{unwrap value}}
<!-- This will update the value to 456 when clicked -->
<button {{on "click" (update value 456)}}>
Update
</button>
{{/let}}
You can also unwrap or update a value in JavaScript:
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { unwrap, update } from 'ember-box';
export default class MyOtherComponent extends Component {
get boxValue() {
return unwrap(this.args.box);
}
@action
updateBox(newValue) {
update(this.args.box, newValue);
}
}
Note: The
update
function updates the box immediately, but the{{update}}
helper returns a callback that can be used to update the value later. This is because that is what is normally needed in a template.
unwrap
and update
can also both receive plain JS values. unwrap
will
return the value, and `update will no-op. This allows you to write components
that can optionally receive Boxes:
<!-- this.value will update when the component updates it internally -->
<Input @value={{box this.value}} />
<!-- this.value will not update, but the component can still read its value -->
<Input @value={{this.value}} />
You can also create Boxes in js
by providing a context and path, or by
providing a context and path directly to the helper:
box(this, 'myValue');
{{box this "myValue"}}
Wrapping Boxes
Sometimes, you may want to intercept an update to a Box, either to do some other
action when the value changes (a side-effect) or to process the value. You can
wrap boxes to do this with wrap
and {{wrap}}
:
<Input @value={{wrap (box this.value) this.doSomething}} />
export default class MyComponent extends Component {
@action
doSomething(newValue, _super) {
// do things
_super(newValue);
}
}
The wrapper callback receives the new value, and the super setter, which should
be called if you want to set the value on the box. wrap
can be used to wrap
boxes repeatedly, and unwrap
will recursively unwrap all of them. Also, like
with unwrap
and update
, wrap
can be used with non-Box values to observe
their attempted changes:
<!-- this.value won't update, but `this.doSomething` will fire when it would have -->
<Input @value={{wrap this.value this.doSomething}} />
Contributing
See the Contributing guide for details.
License
This project is licensed under the MIT License.