npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ember-confirmed

v2.5.1

Published

An Ember asynchronous confirmation addon

Downloads

43

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. 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.

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.

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.

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

<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}}
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.

<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}}
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.

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

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

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

{{#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.

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);
    }
  }
});
{{#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.

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);
  });
}