Alex Alex - 6 months ago 18
AngularJS Question

AngularJS: Can't use .then on promise from factory

With my current project i try to learn AngularJS + asp.net. I follow this tutorial.

My current code is:

LoginFactory.js

var LoginFactory = function($http, $q) {
return function(emailAddress, password, rememberMe) {
return $http.post(
"/Account/Login", {
Email: emailAddress,
Password: password,
RememberMe: rememberMe
}
);
}
}
LoginFactory.$inject = ["$http", "$q"];


LoginController.js

$scope.login = function () {
LoginFactory($scope.loginForm.emailAddress, $scope.loginForm.password, $scope.loginForm.rememberMe)
.then(function (result) {
if (result.success) {
if ($scope.loginForm.returnUrl !== undefined) {
$location.path("/");
} else {
$location.path($scope.loginForm.returnUrl);
}
} else {
$scope.loginForm.loginFailure = true;
}
});
}
//CODE OMITTED
LoginController.$inject = ["$scope", "$routeParams", "$location", "LoginFactory"];


If i run this example i get an error in my browser console "the object does not support the property or method 'then'". As far as i understood the documentation of
$http
correct
$http.post
always returns a promise ? Why can't i use
.then
for it ?

If i rewrite my example like this (No use of LoginFactory):

$scope.login = function () {
$http.post(
"/Account/Login", {
Email: $scope.loginForm.emailAddress,
Password: $scope.loginForm.password,
RememberMe: $scope.loginForm.rememberMe
}
)
.then(function (result) {
console.log(result);
if (result.success) {
if ($scope.loginForm.returnUrl !== undefined) {
$location.path("/");
} else {
$location.path($scope.loginForm.returnUrl);
}
} else {
$scope.loginForm.loginFailure = true;
}
});
}


everything works fine and i get the results that i've expected. Why is the inline call successful but the factory call fails ?

Thanks for you help :)




EDIT (In response to @NutBoltu):
I've changed my main.js according to your suggestions

main.js

myApp.controller("LoginController",[ "LoginFactory", LoginFactory]);
myApp.factory("LoginFactory", ["$http", LoginFactory]);


Forthermore i changed my LoginFactory.js to:

LoginFactory.js

var LoginFactory = function($http) {
return {
http: function(emailAddress, password, rememberMe) {
return $http.post(
"/Account/Login", {
Email: emailAddress,
Password: password,
RememberMe: rememberMe
});
}
}
}
LoginFactory.$inject = ["$http"];


But i still get the "The object does not support the property or method 'http'" error.




EDIT2: If i log the LoginFactory like this
console.log(LoginFactory);
in my Controller i get the folloing output (exactly the definition of LoginFactory):

function($http) {
return {
http: function(emailAddress, password, rememberMe) {
return $http.post(
"/Account/Login", {
Email: emailAddress,
Password: password,
RememberMe: rememberMe
});
}
}
}


Solution
Thanks @NutBoltu for his help with this. The solution was to play the LoginFactory and the LoginController inline into the main.js. The solution is looking like this:

main.js

myApp.controller("LoginController", ["$scope", "$routeParams", "LoginFactory", function ($scope, $routeParams, loginFactory) {
$scope.loginForm = {
emailAddress: "",
password: "",
rememberMe: false,
returnUrl: $routeParams.returnUrl
};

$scope.login = function () {
console.log("controller ok");
console.log(loginFactory);
loginFactory($scope.loginForm.emailAddress, $scope.loginForm.password, $scope.loginForm.rememberMe)
.then(function (result) {
console.log(result);
if (result.success) {
if ($scope.loginForm.returnUrl !== undefined) {
$location.path("/");
} else {
$location.path($scope.loginForm.returnUrl);
}
} else {
$scope.loginForm.loginFailure = true;
}
});
}
}]);

boundlessCommunity.factory("LoginFactory", [
"$http", function($http) {
return function(emailAddress, password, rememberMe) {
console.log("factory ok");
return $http.post(
"/Account/Login", {
Email: emailAddress,
Password: password,
RememberMe: rememberMe
});
}
}
]);

Answer

Angular factory is a service provider which will be called to return the service instance. In your case, you are trying to return $http.post promise. You need to wrap the promise inside an object and return that object. Also you need to declare factory as below.

myModule.factory('LoginFactory',[ "$http", function($http) {
  return {
    http: function(emailAddress, password, rememberMe) {
        return $http.post(
            "/Account/Login", {
                Email: emailAddress,
                Password: password,
                RememberMe: rememberMe
            });
    }
  } 
]);

In your controller you need to inject LoginFactory.

myModule.controller('LoginController',[ "LoginFactory", function(LoginFactory) { 

    $scope.login = function () {
       LoginFactory.http($scope.loginForm.emailAddress, $scope.loginForm.password, 
                  $scope.loginForm.rememberMe).then(function(response{
                       //....
       }) 
    }
}]);