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. 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
.
{ // Affirm confirmation resolver; // Reject confirmation resolver; // Cancel confirmation resolver; // Reject with an Error resolver;}
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.
{ … } ;
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.
window.confirm
Basic In this example we will wrap the window.confirm
. Although this is not
asynchronous it does illustrate the API.
{ if resolver; else resolver; } ;
Example component
<p>Result was confirmed: {{if confirmed 'YES' 'NO'}}</p> {{#if resolver}} <p>Confirmation?</p> <button onclick={{action resolver.cancel}}>Cancel</button> <button onclick={{action resolver.confirm}}>Ok</button>{{else}} <button onclick={{action "showDialog"}}>Show Dialog</button>{{/if}}
;; ;
Password prompt
Maybe the resolution of the confirmation needs more logic. For example asking for a password.
<p>Result was confirmed: {{if confirmed 'YES' 'NO'}}</p> {{#if resolver}} <label> Password: {{input type="password" value=password}} </label> <button onclick={{action resolver.cancel}}>Cancel</button> <button onclick={{action resolver.confirm password}}>Ok</button>{{else}} <button onclick={{action "showDialog"}}>Show Dialog</button>{{/if}}
;; const REAL_PASSWORD = 'password'; ;
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.
;;; const DIALOG_AUTO_CLOSE_DELAY = 5000; ;
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
; ;
app/controllers/index.js
;; ;
app/templates/index.hbs
{{#if showConfirmationModal}} <div class="modal"> <p>You have unsaved changes. Are you sure wish to abandon them?<p> <button {{action (action modalActions.cancel)}}>No</button> <button {{action (action modalActions.confirm)}}>Yes</button> </div>{{/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 on your own.
;;; ;
{{#ember-remodal forService=true name="confirmation" onConfirm=(action "resolveModal" "confirm") onCancel=(action "resolveModal" "reject") onClose=(action "resolveModal" "cancel") as |modal|}} {{#modal.cancel}}<button class="pull-right">Close</button>{{/modal.cancel}} <p>Pick yes or no:</p> {{#modal.cancel}}<button>No</button>{{/modal.cancel}} {{#modal.confirm}}<button>Yes</button>{{/modal.confirm}}{{/ember-remodal}}
Example using ember-sweetalert
This is an example of wrapping the ember-sweetalert addon in a Confirmer object.
;; { return { ; };}