0

I have a function which returns a promise which is resolved if the user is currently logged in, or waits to resolve once the user has logged in. SO you can do this...

myService.waitForLogin().then(function(){
    // Subscribe to pusher.com events
});

I then use a similar call to unsubscribe from events when the user logs out.

The trouble is that I want to run my .then() code every time the user logs in, so the process is....

  • If the user is logged in, run the code.

  • If not, wait till they log in, then run the code.

  • If they log out then back in again, run the code again.

I was originally using $rootscope.$on to listen to login/out events which worked well for the repeated occurrences, but I needed it to be promise based in case the user was already logged in.

Here is my code:

var defer = $q.defer();

if(isLoggedIn()){
    defer.resolve();
}

else{

    var offLoggedInTrue = $rootScope.$on('loggedin-true', function(){
        defer.resolve();
        offLoggedInTrue();
    });

}

return defer.promise;
jonhobbs
  • 26,684
  • 35
  • 115
  • 170
  • 1
    Promises can only get resolved one time... by definition. Maybe you should try using other async systems like `Rx.Observable` (although that's a whole different API) – olivarra1 Nov 21 '16 at 15:57
  • Or you could manually trigger the 'loggedin-true' event if the user is already logged in. – Swimburger Nov 21 '16 at 15:58
  • I am not sure if this is possible with rxjs. Basically, yes, it is possible, but we all know, that `window.setTimeout` has a maximal limit. And also remember the mobile browser issues, which does not have `window.setTimeout` implemented due to security and GUI freezing reasons. But you could propably emit events in an interval, which checks whether the user is logged in or not. Or even more better: Change your concept. There are many other ways to do this common task. Maybe you could use REST request to your backend to retrieve the user state periodically. – alpham8 Nov 21 '16 at 16:04

2 Answers2

1

You can use the promise to controll the login status by storing a deferred on your service, and then return the promise through your method waitForLogin(). However, instead of resolving the promise, you could just notify it, once you resolve the login promise it won't be resolved again, so you can notify and reuse it many times as you can.

Note: this is a solution using promises, however you may find better use events instead, it's easier to maintain in my opinion.

For example:

angular.module('myApp', [])
  .service('LoginStatusService', function($q) {

    // store a deferred to represent the login resolution state
    var loginDeferred = $q.defer();

    // the getter method to yout login promise
    this.waitForLogin = function() {
      return loginDeferred.promise;
    };

    // an example login method from where you could notify the login promise
    this.login = function(login, password) {
      /// do async login things and then
      loginDeferred.notify();
    };

    // when the deferred may need to got reseted
    this.logoff = function(login, password) {
      /// do logoff things and then
      // loginPromise = $q.defer();
    };
  })

Then on your controller or whatever provider you want you can inject the service and use it like so:

  .controller('MyController', function(LoginStatusService) {

    LoginStatusService.waitForLogin().then(null, null, function () {
      // do your subscribe stuff here
    });
  });
lenilsondc
  • 9,590
  • 2
  • 25
  • 40
  • Thanks, but if I'm not mistaken this will still only fire once, no? – jonhobbs Nov 21 '16 at 16:23
  • @jonhobbs Yes you're right, I've updated my answer, instead of using `resolve` you can use `notify`. That may be help you with this issue. – lenilsondc Nov 21 '16 at 16:25
  • Thanks, I think this is the answer I should accept, but I feel a little uncomfortable about using notify indefinitely and never resolving or rejecting the promise. Can you see any side-effects of doing this? Should it be forced to resolve/reject at some point? – jonhobbs Nov 21 '16 at 16:48
  • No, I don't. But I think the best aproach is to use the observer pattern, but it's different from promises. – lenilsondc Nov 21 '16 at 16:52
  • @jonhobbs check this out tell me if it serves for your purposes https://github.com/lenilsondc/ng-observer – lenilsondc Nov 22 '16 at 16:50
  • Thanks Lenilson, I'll take a look. I have solved my problem for now by writing a bit more code than I'd like to, but this may help me in the future. – jonhobbs Nov 22 '16 at 19:51
1

You can keep using the "loggedin-true", and after you subscribe to the event, you can trigger the event manually IF the user is already logged in. Here is a small sample.

angular.module('app', [])
  .controller("mainController", function($scope, $rootScope) {
    $scope.output = "";
    $rootScope.$on('loggedin-true', function() {
      $scope.output += "loggedin event \n";
    });
    if (isLoggedIn()) {
      $rootScope.$emit("loggedin-true");
    }
    logOut($scope);
    logIn($scope, $rootScope);
  });

function isLoggedIn() {
  return true;
}

function logOut($scope) {
  $scope.output += "loggedout \n";
}

function logIn($scope, $rootScope) {
  $scope.output += "login \n";
  //login successfull
  $rootScope.$emit("loggedin-true");
}
<div ng-app="app" ng-controller="mainController">
  <pre>{{output}}<pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Swimburger
  • 6,681
  • 6
  • 36
  • 63
  • Thanks Sniels, I guess I already knew that I could do it the long way but I wanted this function to be easy to use and I wanted to keep it DRY because other developers are going to be calling my waitForLogin() function and I don't want them to have to write lots of logic each time. Thanks for the answer though. – jonhobbs Nov 21 '16 at 16:22
  • If you want to make it DRY'er, I'd suggest putting it in a service and injecting it into your controllers. I'm not a fan of using scopes in services, but I wouldn't pull a library for EventEmitter logic since it's already in Angular. Here's [a blogpost](http://www.codelord.net/2015/05/04/angularjs-notifying-about-changes-from-services-to-controllers/) how you could wrap it into a service. – Swimburger Nov 21 '16 at 18:54