Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sukima/ember-confirmed
An Ember asynchronous confirmation addon
https://github.com/sukima/ember-confirmed
ember ember-addon javascript
Last synced: about 2 months ago
JSON representation
An Ember asynchronous confirmation addon
- Host: GitHub
- URL: https://github.com/sukima/ember-confirmed
- Owner: sukima
- License: other
- Created: 2017-09-08T20:40:13.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-02-13T19:11:20.000Z (almost 6 years ago)
- Last Synced: 2024-10-21T21:02:48.011Z (2 months ago)
- Topics: ember, ember-addon, javascript
- Language: JavaScript
- Homepage:
- Size: 124 KB
- Stars: 12
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# ember-confirmed
An Ember asynchronous confirmation addon
A very simple *promise-like* API for easily showing a confirmation and
resolving to the result of the user input. Its main goal is to replace or
enhance the typical `window.confirm` and many adhoc event based solutions (see
example below).Special thanks to [FunnelCloud Inc.](http://funnelcloud.io/) for graciously
providing inspiration, R+D, and support.License: MIT
## Installation
```
ember install ember-confirmed
```## Usage
```
import Confirmer from 'confirmer';
```Much like the `Promise` API the constructor for the `Confirmer` takes
a function. That function is passed a resolver object which has four functions
on it that you can use to *fulfill* the `Confirmer`.```js
new Confirmer(function (resolver) {
// Affirm confirmation
resolver.confirm();
// Reject confirmation
resolver.reject();
// Cancel confirmation
resolver.cancel();
// Reject with an Error
resolver.error(new Error());
})
```Each state can take an optional value. The `Confirmer` is a wrapper around
a `Promise` and can be treated as a promise. For example to capture any errors
or exceptions you may trigger you would use the `catch()` function.```js
new Confirmer(function (resolver) { … })
.catch(function (reason) { console.error(reason); });
```The `then()` function will be passed the underlying data object:
```
new Confirmer(function (resolver) { … })
.then(function (result) {
console.log(result.reason);
console.log(result.value);
});
```The `reason` being one of `rejected`, `confirmed`, or `cancelled`. And the
`value` is the value passed to one of the resolver functions.The following methods are chainable:
#### `onCanceled`
Is called when `resolver.cancel()` is triggered. Used to denote that the
confirmation was cancelled and perhaps should do nothing.#### `onConfirmed`
Is called when `resolver.confirm()` is triggered. Used to denote that the user
has confirmed in some way. ("OK" button, correct login credentials, etc.)#### `onRejected`
Is called when `resolver.rejected()` is triggered. Used to denote that the user
has performed an action that denied the confirmation. ("No" button, bad
password, etc.)#### `onDone`
Is called when **any** of the resolver functions are triggered. This is used for
clean up like closing the dialog and removing stale event handlers. This is also
called if the `resolver.error` is triggered or something throws an exception in
the initialization function (which can be captued by the `catch()` function just
like a promise).## Examples
The following are example situations that I've run into and how this module can
help reason about them.### Basic `window.confirm`
In this example we will wrap the `window.confirm`. Although this is **not**
asynchronous it does illustrate the API.```js
new Confirmer(function (resolver) {
if (confirm('Whould you like to do this?')) {
resolver.confirm();
} else {
resolver.cancel();
}
})
.onConfirmed(function () { console.log('Ok! let\'s crack on!'); })
.onCancelled(function () { console.log('Maybe next time then?'); })
.onDone(function () { console.log('Confirm completed') });
```### Example component
```hbs
Result was confirmed: {{if confirmed 'YES' 'NO'}}
{{#if resolver}}
Confirmation?
Cancel
Ok
{{else}}
Show Dialog
{{/if}}
``````js
import Component from '@ember/component';
import Confirmer from 'confirmer';export default Component.extend({
actions: {
showDialog() {
new Confirmer(resolver => this.set('resolver', resolver))
.onConfirmed(() => this.set('confirmed', true))
.onCancelled(() => this.set('confirmed', false))
.onDone(() => this.set('resolver', null));
}
}
});
```### Password prompt
Maybe the resolution of the confirmation needs more logic. For example asking
for a password.```hbs
Result was confirmed: {{if confirmed 'YES' 'NO'}}
{{#if resolver}}
Password: {{input type="password" value=password}}
Cancel
Ok
{{else}}
Show Dialog
{{/if}}
``````js
import Component from '@ember/component';
import Confirmer from 'confirmer';const REAL_PASSWORD = 'password';
export default Component.extend({
actions: {
showDialog() {
new Confirmer(resolver => this.set('resolver', resolver))
.onConfirmed(password => {
this.set('confirmed', password === REAL_PASSWORD);
})
.onCancelled(() => this.set('confirmed', false))
.onDone(() => this.set('resolver', null));
}
}
});
```### Auto closing message box
Here is an example of a message box that auto closes after 5 seconds.
Notice that you can call the resolver functions multiple times and only the
first one wins.```js
import Component from '@ember/component';
import { later } from '@ember/runloop';
import Confirmer from 'confirmer';const DIALOG_AUTO_CLOSE_DELAY = 5000;
export default Component.extend({
actions: {
showDialog() {
new Confirmer(resolver => {
later(resolver.cancel, DIALOG_AUTO_CLOSE_DELAY);
this.set('resolver', resolver);
})
.onConfirmed(() => this.set('confirmed', true))
.onCancelled(() => this.set('confirmed', false))
.onDone(() => this.set('resolver', null));
}
}
});
```### Unsaved changes confirmation on route transition
Here is an example if trapping a route transition and showing a confirmation
dialog if the data is not saved (dirty).It shows how you can pass a Confirmer object around between each other.
#### `app/routes/index.js`
```js
import Route from '@ember/routing/route';export default Route.extend({
actions: {
willTransition(transition) {
let confirmer = this.controller.showDirtyConfirmation();
if (confirmer) {
transition.abort();
confirmer.onConfirmed(() => transition.retry());
}
}
}
});
```#### `app/controllers/index.js`
```js
import Controller from '@ember/controller';
import Confirmer from 'confirmer';export default Controller.extend({
showDirtyConfirmation() {
if (!this.get('model.hasDirtyAttributes')) { return; }
return new Confirmer(resolver => {
this.set('modalAction', resolver);
this.set('showConfirmationModal', true);
})
.onConfirmed(() => this.get('model').rollbackAttributes())
.onDone(() => this.set('showConfirmationModal', false));
}
});
```#### `app/templates/index.hbs`
```hbs
{{#if showConfirmationModal}}
You have unsaved changes. Are you sure wish to abandon them?
No
Yes
{{/if}}
```### Example using ember-remodal
We have an `{{#ember-remodal-redux}}` component to handle the complexity of
using remodal as a component instead of a global/service. If this does not fit
your needs then you can still use remodal manually.This is an example using the [ember-remodal addon](http://sethbrasile.github.io/ember-remodal/) on your own.
```js
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import Confirmer from 'confirmer';export default Controller.extend({
remodal: service(),showConfirmationModal() {
const remodal = this.get('remodal');
let modalName = 'confirmation'; // Change as needed
return new Confirmer(resolver => {
this.set('modalResolver', resolver);
let promise = remodal.open(modalName);
resolver.dispose(() => {
// https://github.com/sethbrasile/ember-remodal/issues/3
return promise
.then(() => {
let modalState = tryInvoke(this.get('modal'), 'getState');
// https://github.com/vodkabears/Remodal/issues/291
if (modalState !== 'opened') { return; }
return remodal.close(modalName);
})
.then(() => this.set('modalResolver', null));
});
});
},actions: {
resolveModal(method, value) {
this.get('modalResolver')[method](value);
}
}
});
``````hbs
{{#ember-remodal
forService=true
name="confirmation"
onConfirm=(action "resolveModal" "confirm")
onCancel=(action "resolveModal" "reject")
onClose=(action "resolveModal" "cancel")
as |modal|}}
{{#modal.cancel}}Close{{/modal.cancel}}
Pick yes or no:
{{#modal.cancel}}No{{/modal.cancel}}
{{#modal.confirm}}Yes{{/modal.confirm}}
{{/ember-remodal}}
```### Example using ember-sweetalert
This is an example of wrapping the [ember-sweetalert addon](https://github.com/Tonkpils/ember-sweetalert) in a Confirmer object.
```js
import Confirmer from 'confirmer';
import sweetAlert from 'ember-sweetalert';export default function sweetAlertConfirmer(sweetAlertOptions) {
return new Confirmer(resolver => {
sweetAlert(sweetAlertOptions)
.then(result => {
if (result.dismiss) {
resolver.cancel(result.dismiss);
} else {
resolver.confirm(result.value);
}
})
.catch(resolver.error);
});
}
```