2

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

1 Answer 1

2

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;
}
Sign up to request clarification or add additional context in comments.

8 Comments

I made the change, it is working now. I'm able to get my promiseObj2 in controller but when backend api responds with a 4xx response code, it startes failing. Can you please answer my second question also ?
That's right but is there any way I can this info to my controller. As I stated earlier, my view rendering logic depends on this information. Any inputs ?
@dark_shadow what you want to do if it doesn't have information? do you want to redirect user to somewhere or wanted to do something else?
My view contains a $scope.someFlag which can be true/false based on whether my token is valid or not? If token is valid, I'll get the promiseObject2 and can see its status code and will be able to toggle it but how will I handle the other case where I need to check if it is invalid and perfome some action on it. For a better explanation, please refer to point 2. Thanks
I tried returning err to the controller like you mentioned but it seems to be failing. Reason: TypeError: Cannot read property 'then' of undefined in the controller. It seems the err is not returned from the resolve instead it gives only a success promiseObj2. That was the reason why I was asking for 4xx being considered as error. I will never be able to check for response == 404 in my .then part as it will always land in the catch condition in the resolve. Any idea why is it so?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.