4

Working with an AngularJS app (1.4.3), I want a controller to make a call to a method on a service, which should return a boolean value.

Under the hood, the service used to make a call to $window.confirm(), and then just return the result. I am trying to switch the implementation to use Angular Material's $mdDialog.confirm() API, but this returns a promise.

The problem I am running into is that there is no way to return true or false directly from my service without changing the code in my controller to expect a promise. The whole purpose of extracting this method into a service was so that the controller could be separated from the implementation details of the call, and I would consider using a promise (ie, a future boolean) vs. a straight boolean to be an implementation detail.

Here is some code to illustrate: In the controller:

function confirmDeleteDevice() {
    if (notificationService.confirm('Are you sure you want to delete the device?')) {
        deleteDevice();
    }
}

Old function in 'notificationService':

function confirm(message) {
    return $window.confirm(message);
}

New function in notificationService that will not work as expected with the controller code above:

function confirm(message) {
    var confirm = $mdDialog.confirm()
        .title(message)
        .ariaLabel(message)
        .ok('Yes')
        .cancel('No');
    return $mdDialog.show(confirm).then(function() {
        return true;
    }, function() {
        return false;
    });
}

Without changing the controller code to rely on the implementation detail of using a promise, how do I get a boolean value out of my service method? The code above will always execute "deleteDevice()" because the new notificationService.confirm() will return the unresolved promise, which apparently qualifies as a truthy value for the if clause.

I'm definitely no expert on promises, and I understand this isn't exactly how they are expected to be used, but I'd really rather not tie the controller down to using a promise. Is this even possible given the "async" nature of promises?

UPDATE: I definitely looked before I posted and could find nothing, but this just showed up in the "related questions" feed, so I see now my question was a duplicate. The answers there are pretty helpful.

Community
  • 1
  • 1
Sean
  • 498
  • 1
  • 5
  • 13
  • 1
    No, asynchrony is not an implementation detail, as it does change the control flow of the caller a lot. And no, there's no way to get the boolean out of the promise synchronously. Just make your controller expect asynchronous results - and you can make it an implementation detail that its synchronous under the hood. – Bergi Sep 04 '15 at 22:03

1 Answers1

2

You will have to make your condition async as well, chaining through the promise.

i.e

notificationService.confirm('...').then(function(confirmation){
     if(confirmation) {
         deleteDevice();
     }
});

and you really would not need to have catch and return false unless you need to really track the return value since dialog already resolves/rejects the promise based on cancel or Ok, i.e below blocks wont be needed.

   .then(function() {
        return true;
    }, function() {
        return false;
    });

So

function confirm(message) {
    var confirm = $mdDialog.confirm()
        .title(message)
        .ariaLabel(message)
        .ok('Yes')
        .cancel('No');

    return $mdDialog.show(confirm);
}

and just:

notificationService.confirm('...').then(deleteDevice);
PSL
  • 123,204
  • 21
  • 253
  • 243
  • Ok, right, the boolean part of the resolution is pretty much redundant. So am I right in guessing that there is no way to do this without making the code in the controller async? Because execution has already passed out of the original calling function, and the .then() "callback" in the service has no way to reach the original calling function, correct? – Sean Sep 04 '15 at 19:35
  • @Sean Yes you are right, right way is to chain through the promise only. – PSL Sep 04 '15 at 19:40