2

I'm having trouble figuring out how I could pass a parameter to a function that is a part of resolve of ngRoute.

In my case I'm doing stuff with tokens. These tokens are typed, so you cannot use the same token for confirming and email and reseting a password. Here's how my routes are defined:

.when("/confirm/:token", {
    controller: "confirmEmailController",
    templateUrl: "/app/views/confirmEmail.html",
    resolve: {
        tokenStatus: getTokenStatus
    }
})
.when("/reset/:token", {
    controller: "resetPasswordController",
    templateUrl: "/app/views/resetPasswordEmail.html",
    resolve: {
        tokenStatus: getTokenStatus
    }
})

Here's the getTokenStatus function that's being called for both of them:

var getTokenStatus = ["$q", "$route", "tokenService", function($q, $route, tokenService)
{    
    var deferred = $q.defer();

    var tokenType = ???? //<-- how do I pass this?

    tokenService
        .getTokenStatus($route.current.params.token, tokenType)
        .success(function(response)
        {                    
            deferred.resolve(true);
        })
        .error(function()
        {
            deferred.resolve(false);
        });

    return deferred.promise;
}];

The problem is that in order to avoid code duplication I need to somehow pass the value of the token type, as marked in the code. How could I do that?

I've been messing about with this for the last 2 hours, but can't seem to figure it out.

gligoran
  • 3,267
  • 3
  • 32
  • 47
  • 1
    why you don't pass it in route itself? that would be easier – Pankaj Parkar Feb 22 '15 at 10:57
  • where do you get that token type? – Nitsan Baleli Feb 22 '15 at 11:28
  • @pankajparkar: That's the workaround I'm using now, but semantically isn't the best way. – gligoran Feb 22 '15 at 11:30
  • @NitsanBaleli: I'd specify it manually, preferably in routing somehow. It's a known set of values. For example email confirmation is 0, password reset is 1. If ```getTokenStatus``` would be a normal function I'd call it like this: ```getTokenStatus(token, tokenType)```. That's what I'm trying to achieve in essence, but while I get ```token``` from the URL, I'd like to set ```tokenType``` in code. – gligoran Feb 22 '15 at 11:38

2 Answers2

5

1. You can try to include token type into route

.when("/:tokenType/:token", {
    controller: "confirmEmailController",
    templateUrl: "/app/views/confirmEmail.html",
    resolve: {
        tokenStatus: getTokenStatus
    }
})
.when("/:tokenType/:token", {
    controller: "resetPasswordController",
    templateUrl: "/app/views/resetPasswordEmail.html",
    resolve: {
        tokenStatus: getTokenStatus
    }
})

And then just get it from $route.current.params.tokenType. But it's not clean solution - you should check your URL for validity.

2. You can use function wrapping

$routeProvider.when("/confirm/:token", {
    controller: "confirmEmailController",
    templateUrl: "/app/views/confirmEmail.html",
    resolve: {
        tokenStatus: getTokenStatus("confirm")
    }
})
.when("/reset/:token", {
    controller: "resetPasswordController",
    templateUrl: "/app/views/resetPasswordEmail.html",
    resolve: {
        tokenStatus: getTokenStatus("reset")
    }
});

var getTokenStatus = function(tokenType) {
    return ["$q", "$route", "tokenService", function($q, $route, tokenService) {
        var deferred = $q.defer();
        tokenService
            .getTokenStatus($route.current.params.token, tokenType)
            .success(function(response)
            {                    
                deferred.resolve(true);
            })
            .error(function()
            {
                deferred.resolve(false);
            });
        return deferred.promise;
    }];
};

3. You can move get-token-status logic into separate servise

$routeProvider.when("/confirm/:token", {
    controller: "confirmEmailController",
    templateUrl: "/app/views/confirmEmail.html",
    resolve: {
        tokenStatus: ['tokenStatusGetterService', function(tokenStatusGetterService){
            return tokenStatusGetterService("confirm");
        }]
    }
})
.when("/reset/:token", {
    controller: "resetPasswordController",
    templateUrl: "/app/views/resetPasswordEmail.html",
    resolve: {
        tokenStatus: ['tokenStatusGetterService', function(tokenStatusGetterService){
            return tokenStatusGetterService("reset");
        }]
    }
});

//...

.service('tokenStatusGetterService', ["$q", "$route", "tokenService", function($q, $route, tokenService) {
    return function(tokenType) {
        var deferred = $q.defer();
        tokenService
            .getTokenStatus($route.current.params.token, tokenType)
            .success(function(response)
            {                    
                deferred.resolve(true);
            })
            .error(function()
            {
                deferred.resolve(false);
            });
        return deferred.promise;
    };
}]);
Harry Burns
  • 770
  • 5
  • 19
1

one way to do it is to put a function on your getTokenStatus service. this is a simplified example, yet it shows how to pass an argument to your resolve function.

app.factory('getTokenStatus',['$q', '$timeout', '$route', function($q, $timeout, $route){
  this.action = function(tokenType) {
    var defer = $q.defer();

    $timeout(function(){
      var res = {
        path: $route.current.params.token,
        tokenType: tokenType
      }
      defer.resolve(res);
    },1000);

    return defer.promise;
  }

  return this;
}]);

and call it from your resolve object:

app.config(function($routeProvider){
  $routeProvider
  .when("/123/:token", {
    template: "<h1>hello</h1>",
    controller: 'testCtrl',
    resolve: {
      tokenStatus: function(getTokenStatus) {
        return getTokenStatus.action('firstToken').then(function(res){
          console.log(res);

        });
      }
    }
})

here's a plnkr

Nitsan Baleli
  • 5,393
  • 3
  • 30
  • 52