2

I have a state as following :

.state('core.recover', {
   url: '/recover',
   controller: 'RecoverPasswordCtrl',
   templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
})

I want when I enter to this state to check something before loading the template, in this case I want to call an api that checks for something if the promise is successful it will continue and display the template, otherwise it will redirect the user to another state.

I tried to do this on the top of the controller but I always see the template for a moment then it redirects me, so I tried to use resolve as in this post :

AngularJS | handle routing before they load

As following :

.state('core.recover', {
        url: '/recover',
        controller: 'RecoverPasswordCtrl',
        resolve: function(recoverAccountService, $location, $state, $q) {
          var deferred = $q.defer();
          deferred.resolve();
          recoverAccountService.get({email:$location.search().email, verificationKey:$location.search().verificationKey})
            .$promise.then(function (result) {}).catch(function (err) {
            $state.go("candidature.pre");
          });
          return deferred.promise;
        },
        templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
      })

but it didn't work and I'm getting this error in the browser's console :

Error: 'invocables' must be an object

How can I solve this ?

Community
  • 1
  • 1
Renaud is Not Bill Gates
  • 1,684
  • 34
  • 105
  • 191

1 Answers1

2

You're not using the correct syntax, uiRouter is expecting as entry for resolve an object, which keys it will try to evaluate.

Lets abbreviate your resolving function as aimadResolver, such that

var aimadResolver = function(recoverAccountService, $location, $state, $q) {
    var deferred = $q.defer();
    deferred.resolve();
    recoverAccountService.get({ email: $location.search().email, verificationKey: $location.search().verificationKey })
        .$promise.then(function(result) {}).catch(function(err) {
            $state.go("candidature.pre");
        });
    return deferred.promise;
}

Of course, this is not mandatory, but I'm doing it for the sake of readability. Then, your state definition should be as follows:

state('core.recover', {
    url: '/recover',
    controller: 'RecoverPasswordCtrl',
    resolve: {'yourResolverName': aimaidResolver}
    },
    templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
})

Don't forget to inject yourResolverName in RecoverPasswordCtrl, or else your controller will be instantiated without waiting anyway. Source: look for the resolve examples

On the side I'd like to point out that your use of deferred objects doesn't make sense. You're immediately resolving your deferred object on the second line within your function, which means that recoverAccountservice.get() could still be pending while RecoverPasswordCtrl is already being instantiated. Assuming that recoverAccountservice.get() returns a promise (and if it doesn't, you should change it such that it does), you can more efficiently write:

var aimadResolver = function(recoverAccountService, $location, $state, $q) {
    return recoverAccountService.get({... })
        .then(function(result) {
            // do nothing? Apparently you only want to $state.go on a rejection of the promise
        })
        .catch(function(err) {
            $state.go("candidature.pre");
            return $q.when()
        })
}

More on the use of $q.when() versus deferred can be found here.

Maurits Moeys
  • 1,116
  • 1
  • 12
  • 22