如何使用服务更改范围变量?

时间:2014-04-21 16:51:45

标签: javascript angularjs http

我有一个应用程序,在应用程序内部是注册和登录表单。

使用注册表单,当用户创建帐户时,他们会自动登录。

使用登录表单,用户也可以登录(显然)。

我有两个控制器:一个用于注册表单,另一个用于登录表单。我希望他们能够共享服务'logIn',因为这两种形式的用户最终都会登录。

到目前为止一直在努力。我唯一的问题是登录表单异步检查用户对数据库的登录凭据,如果处理此请求的PHP脚本返回说没有匹配,则angular更新错误消息的模型,如下所示给用户。当'logIn'服务不用作服务时,这种方法完全正常,但只是复制到两个控制器中。以下是'SignupCtrl'的外观:

.controller('SignupCtrl',['$scope','$http',function($scope,$http) {
    $scope.error = false;

    $scope.logIn = function() {
        var data = // user's login credentials

        $http({
            // send credentials to server, ask if there's a match
        })
        .success(function(data) {
            if(data.match === false) {
                $scope.error = true;
            } else {
                // start session, redirect to new page, etc.
            }
        })
    }
}]);

然后,在模板内:

<div ng-show="error">Oops! That email/password doesn't exist.</div>

这很好用;但正如我所说,不是'logIn'函数用作服务时。这是因为我无法弄清楚如何在服务中更新$scope.error

我尝试过使用$rootScope(这不起作用):

.service('logIn',[/* injections */, '$rootScope', function(/* injections */, $rootScope) {
    return function(email, password) {
        // all the same code as before

        if(data.match === false) {
            $rootScope.error = true; // this does nothing
        }
    }
}]);

// in the controller (the service is injected in as 'logIn')

$scope.logIn = logIn;

然后,在模板中:

<button ng-click="logIn(user.email, user.password)">Login</button>

用户可以使用该服务正常登录。问题只是用服务更新$scope.error变量。

也许如果我能以某种方式做到这一点,它会起作用:

<button ng-click="logIn(user.email, user.password, $scope)">Login</button>

然后在服务中:

return function(email, password, scope) {
   // etc.
   if(data.match === false) {
       scope.error = true;
   }
}

有什么想法?谢谢。

小编辑

只是为了澄清,根据我对services的理解,它们似乎取代了人们通常如何声明一个全局函数,或者仅仅是模块内部的整体函数,以避免重复自己。例如:

(function() {
    function globalFunction() {
        //etc.
    }

    $('.thing').click(globalFunction);

    $('.otherThing').click(globalFunction);
}());

可能有一个更好的例子,但我认为这个想法是明确的。

这个概念是否与在角度内使用服务的方式类似?如果没有,是否有更好的方式让我去做我正在尝试做的事情而不使用服务?

1 个答案:

答案 0 :(得分:2)

您可以将$rootScope传递给服务,但污染您的$rootScope通常不是一个好主意,但是在这个特殊情况下您的问题是没有强制摘要因此你的控制器$scope没有意识到这种变化。在您发布的代码中,如果将$rootScope.error包裹在$rootScope.$apply()内,则可以正常工作。但回调更清晰。

我建议你将回调传递给service方法,并在回调中设置你的范围变量:

login:function(email,password,callback){
    $http({
            // send credentials to server, ask if there's a match
        })
        .success(function(data) {
         callback(data.match);
        })
}

并在您的控制器中:

$scope.logIn = function() {
    loginServcie.login($scope.email,$scope.password,function(dataIsMatched){
   //you now have the result of call, and dataIsMatched is true or false
    $scope.error = !dataIsMatched;
})
}