dark_shadow
dark_shadow

Reputation: 3573

Angular ui-router not injecting the resolve into controller

I'm just getting started with Angular and Express and facing tough times with it. I come from a java background and want to learn Angular and Express and therefore trying out to build one small application.

What I'm trying to do: I have given a password reset link to user so as to change his password. The link is something like:

localhost:9000/reset/:token

Now, I have created a simple view which shows an input box to change his password if token is valid otherwise prints an error if token is invalid based on ng-show property of angular.

Problem: Before I can render my above created view, I want ui-router to check if the :token is valid or not. I will be using the information of validity of token in my controller to control ng-show property mentioned above.

After reading this I tried to leverage the $stateProvider.state functionality with a resolve so as to get the response of validation of token as pre-requisite. This will help me when rendering the actual view where I'm using ng-show technique to show error message or input box to change the password based on the ui-router resolve promiseObject.

What is the issue now ?

Well, after breaking my head for too long, I decided to post my question over here. Can anyone please help me here ?

My questions:

1. I'm able to get the data/err from the api call but somehow ui-router is not injecting it in my controller. Can anyone tell me am I doing anything wrong here ?

2. Right now if the token is not valid, I'm returning a 404 in response from my backend api. But the factory method in frontend takes it as err (Is this expected in Node.js ?) and the err is thrown which results in deferred.reject(). Now, if I go with ui-router definition, if the promise is not resolved then the view won't be rendered, right ? Is there any way by which I can pass this err also to my controller ? Reason why I'm asking to pass err is, my view's ng-show logic is based on the response code (4xx/2xx) depending on which I'll show error message or input box.

Code snippets:

Factory Method which calls the rest api:

  isPasswordResetTokenValid: function(token, callback) {
    var cb = callback || angular.noop;
    var deferred = $q.defer();

    return User.getUserByPasswordResetToken(token,
      function(data) {
        deferred.resolve(data);
        return cb(data);
      },
      function(err) {
        deferred.reject(err);
        return cb(err);
      }.bind(this)).$promise;
  } 


'use strict';

angular.module('scrubApp')
  .config(function ($stateProvider) {
    $stateProvider
      .state('passwordreset', {
        url: '/reset/:token',
        templateUrl: 'app/account/passwordreset/passwordreset.html',
        resolve: { 

          promiseObj2: function($stateParams, Auth){
              var token = $stateParams.token;
              console.log(token);
               var response = Auth.isPasswordResetTokenValid({token: token})
              .then( function(response) {
                  console.log(response); // shows response
                  if(response.status == 404) {
                    //$scope.token-expiry = true;
                    return response;
                  }
                  if(response.status == 200) {
                    // $scope.user = response.data;
                  }
              })
              .catch( function(err) {
                console.log(err); // shows error
                return err;
              });
          }
        },
        controller: 'ResetPasswordCtrl'  
      });
  });

ResetPasswordCtrl controller:

'use strict';

angular.module('myApp')
  .controller('ResetPasswordCtrl', function ($scope, User, Auth, Mailer, $stateParams, promiseObj2) {
    $scope.errors = {};
    $scope.user = {};

    console.log(promiseObj2);   // This is coming undefined
    $scope.isTokenExpired = promiseObj2;  // Not able to inject promiseObj2

    $scope.isFormSubmitted = false;


  });

Thanks in advance

Upvotes: 2

Views: 868

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136184

Your resolve promiseObj2 should return a promise from promise service, so that your controller will wait till promise gets resolved.

return Auth.isPasswordResetTokenValid({token: token})

Update

If you want to handle some logic on failure of your token request then you could handle it in your promise itself, that can do couple of thing like

  1. You could redirected to other page using $state.go('login') or $state.go('error') page.

Code

promiseObj2: function($stateParams, Auth, $state){
  var token = $stateParams.token;
  console.log(token);
  return Auth.isPasswordResetTokenValid({token: token}) //added return here
  .then( function(response) {
    console.log(response); // shows response
    if(response.status == 404) {
        $state.go('error')
    }
    if(response.status == 200) {
        return response;
    }
  })
  .catch( function(err) {
    console.log(err); // shows error
    return err;
  });
}
  1. If you want to show html page anyhow if error occurs then You could also return data from the .then of promiseObj2 object that will have information about error message. So that error information is return to the controller

Code

promiseObj2: function($stateParams, Auth, $state){
  var token = $stateParams.token;
  console.log(token);
  return Auth.isPasswordResetTokenValid({token: token}) //added return here
  .then( function(response) {
    console.log(response); // shows response
    if(response.status == 404) {
      return {status: 404, data: "doen't found resource"}
    }
    if(response.status == 200) {
        return response;
    }
  })
  .catch( function(err) {
    console.log(err); // shows error
    return err;
  });
}

Then inside controller we will get resolve the promise of promiseObj2 object and then you will get the value of error in the .then function of it.

angular.module('myApp')
.controller('ResetPasswordCtrl', function ($scope, User, Auth, Mailer, $stateParams, promiseObj2) {
  $scope.errors = {};
  $scope.user = {};
  promiseObj2.then(function(resp){
    console.log(resp)
    $scope.isTokenExpired = resp.isTokenExpired;
  }, function(err){
    console.log(err)
  })
});

Update

If we want to handle a condition where server return 4XX status that means our ajax will call catch function that won't return promise though. We could solve this case by creating custom promise using $q and we will resolve it from the promiseObj2

Code

promiseObj2: function($stateParams, Auth, $state, $q){
  var token = $stateParams.token,
      deffered = $q.defer();
  console.log(token);
  Auth.isPasswordResetTokenValid({token: token}) //added return here
  .then( function(response) {
    console.log(response); // shows response
    if(response.status == 404) {
      //return {status: 404, data: "doen't found resource"}
      deffered.resolve({status: 404, data: "doen't found resource"});
    }
    if(response.status == 200) {
      //return response;
      deffered.resolve(response);
    }
  })
  .catch( function(err) {
    console.log(err); // shows error
    deffered.resolve(err);
  });
  return deffered.promise;
}

Upvotes: 2

Related Questions