Is is possible to resolve/reject a promise from an action?

I’m creating a dialog service and I want to have a function confirm() that will open a confirmation modal and return a promise. If the user clicks “confirm” I want to promise to resolve. If they click “cancel” I want the promise to reject.

This is what I have so far:

DialogService = Ember.Service.extend(
  {
    open: false
    title: null
    body: null

    confirm: (message) ->
      @set('title', message.title)
      @set('body', message.body)
      @set('open', true)

      return new Ember.RSVP.Promise (resolve, reject) =>
        Ember.run.later(@, (=> @reset(); reject()), 5000)

    reset: ->
     @set('open', false)
     @set('title', null)
     @set('body', null)
  }
)

And, the component that uses it:

DialogComponent = Ember.Component.extend(
  {
    dialog: Ember.inject.service()

    layout: hbs '
      {{#if dialog.open}}
        {{#g-modal dialog=true title=dialog.title}}
          {{dialog.body}}
          <br>
          {{#g-button}}
            Cancel
          {{/g-button}}
          {{#g-button primary=true}}
            Confirm
          {{/g-button}}
        {{/g-modal}}
      {{/if}}
    '

    actions:
      cancel: -> # this should reject the promise
      confirm: -> # this should resolve the promise
      }
    )
  }
)

This opens the dialog for 5 seconds and then closes it and rejects the promise. I’m just stumped as to how to get the cancel action on the component to call reject in the promise.

Any help would be greatly appreciated.

Thanks!

Of course, I figured it out right after writing down the question. The trick was to use Ember.RSVP.defer(). That way, I can set a property on the service to the deferred object and reject/resolve it later on when the user takes action:

DialogService = Ember.Service.extend(
  {
    open: false
    title: null
    body: null
    deferred: null

    #
    # Close and clear the dialog's contents
    #
    reset: ->
      @set('open', false)
      @set('title', null)
      @set('body', null)
    #
    # Returns a promise that will resolve/reject based on the user clicking
    # "Cancel" or "Confirm" in the dialog.
    #
    confirm: (message) ->
      @set('title', message.title)
      @set('body', message.body)
      @set('open', true)

      deferred = Ember.RSVP.defer()
      @set('deferred', deferred)
      return deferred.promise

    resolve: ->
      @reset()
      @get('deferred').resolve('Confirmed')

    reject: ->
      @reset()
      @get('deferred').reject('Canceled')
  }
)

This is pretty much the much talked about cancellable Promise. You’re not really rejecting anything, because it’s not an error. The Promise is simply cancelled.

The official spec is still in it’s very infancy. I’ve heard some rumors of adding it to RSVP though. :wink:

1 Like

Wow. It’s like Penner is reading my diary.