This addon provides a statechart abstraction based on xstate
for adding statecharts to your Ember.js application. Statecharts can be used to describe
complex behaviour of your objects and separate ui-concern from behavioral concerns
in your applications. This is especially useful in Ember.Component
-architecture
but can be used across all layers of your application (e.g. when implementing
global application state).
- Ember.js v3.15 or above
- Ember CLI v2.13 or above
- Node.js v10 or above
For classic Ember.js-versions pre Ember Octane please use the 0.8.x
-version
of this addon.
ember install ember-statecharts
Statecharts have been around for a long time and have been used to model stateful, reactive system successfully. You can read about statecharts in the original paper Statecharts - A Visual Formalism for Complex Systems by David Harel.
With statecharts we finally have a good abstraction to model and discuss behaviour with other stakeholders of our applications in addition to a design language that visualizes this behaviour. Here's an example of a button component:
In addition to their modeling capabilities Statecharts are executable and can be used to drive user experience behavior in your Ember.js applications:
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { or } from '@ember/object/computed';
import { task } from 'ember-concurrency';
import { statechart, matchesState } from 'ember-statecharts/computed';
function noop() {}
export default class QuickstartButton extends Component {
get onClick() {
return this.args.onClick || noop;
}
get onSuccess() {
return this.args.onSuccess || noop;
}
get onError() {
return this.args.onError || noop;
}
@matchesState('busy')
isBusy;
@or('isBusy', 'args.disabled')
isDisabled;
@statechart(
{
initial: 'idle',
states: {
idle: {
on: {
CLICK: 'busy',
},
},
busy: {
entry: ['handleClick'],
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
entry: ['handleSuccess'],
on: {
CLICK: 'busy',
},
},
error: {
entry: ['handleError'],
on: {
CLICK: 'busy',
},
},
},
},
{
actions: {
handleClick(context) {
context.handleClickTask.perform();
},
handleSuccess(context) {
context.onSuccess();
},
handleError(context) {
context.onError();
},
},
}
)
statechart;
@task(function* () {
try {
const result = yield this.onClick();
this.statechart.send('SUCCESS', { result });
} catch (e) {
this.statechart.send('ERROR', { error: e });
}
})
handleClickTask;
@action
handleClick() {
this.statechart.send('CLICK');
}
}
Please refer to the documentation page for a detailed guide of how you can use statecharts to improve your Ember.js application architecture.
See the Contributing guide for details.
This project has been developed by https://www.effective-ember.com/ and contributors. It is licensed under the MIT License.