我应该在角度控制器中使用$ watch还是大功能?

时间:2015-01-09 22:52:36

标签: angularjs controllers watch

我有一个提交给第三方服务的表单,以便接收"令牌"。我可以指定一个回调函数来处理来自第三方服务的响应。理想情况下,此响应将是令牌,但它也可能是错误消息。回调函数在我的控制器中。在该函数中,我设置了一些其他$ scope变量,这些变量是在应用程序流程中向前推进的。

由于我没有更新的$ scope变量值而无法向前移动并且它们正在我的回调函数中设置,我认为我在使用$ watch来更新$ scope变量时触发更多事件或者我可以将其余功能放在回调函数中。

选项1(简化示例):
使用$ watch on $ scope变量在其值更新时向前移动

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {

     $scope.token = false;

     $scope.$watch('token', function () {  
         doThis();
         for(var i=0; i<len; i++) {
             myFnction("Do Some", MORE_STUFF);
         }

         someObj.fetchGoodStuff($scope.token);             
     });

     $scope.myCallback = function(status, response) {
         if(!response.error) {
             $scope.token = response.token;
         }
    })
}]);



选项2(简化示例):
从回调函数

中向前移动
var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {

     $scope.token = false;

     $scope.$watch('token', function () {  
         doThis();
         for(var i=0; i<len; i++) {
             myFnction("Do Some", MORE_STUFF);
         }

         someObj.fetchGoodStuff($scope.token);             
     });

     $scope.myCallback = function(status, response) {
         if(!response.error) {
             $scope.token = response.token;

             doThis();
             for(var i=0; i<len; i++) {
                 myFnction("Do Some", MORE_STUFF);
             }

             someObj.fetchGoodStuff($scope.token); 
         }
    })
}]);



对我而言,似乎更多&#34;正确&#34;隔离基本功能,在这种情况下是从第三方服务接收响应函数的响应,并将进行中的功能放在其他地方。

但是我能看到的另一个地方就是在$ watch调用的函数中...因为$ scope变量的值每页访问只更改一次,$手表似乎不合适。

有人对收到回复后采取行动的最佳方式有任何见解吗?

2 个答案:

答案 0 :(得分:1)

您需要多少次拨打第三方服务?你需要每次都打电话还是需要打电话一次?常见的方法是使用返回promise的服务包装第三方代码。

myApp.factory('My3rdParty', ['$q', '$rootScope', function ($q, $rootScope) {
    return {
        getToken: function () {
            var deferred = $q.defer();
            doSome3rdPartyStuff(function success(token) {
                // we need to trigger a digest because 3rd party lib runs out of
                // angular's digest cycle
                $rootScope.$apply(function (){
                    deferred.resolve(token);
                });
            }, function error(err){
                $rootScope.$apply(function (){
                    deferred.reject(err);
                });
            });
            return deferred.promise;
        }
    }
}]);

在您的控制器中,注入服务并拨打电话并使用承诺继续

myApp.controller('SomeController', ['$scope', 'My3rdParty', function ($scope, My3rdParty) {
    $scope.doSomeAction = function () {
         My3rdParty.getToken().then(function (token) {
             alert("I got the token!");
         }, function (err) {
             alert("I got an error");
         });
    }; 
}]);

如果您需要向用户显示令牌,可以将其放在$ scope下, 如果您希望在控制器之外更改令牌(用户更改它,其他一些服务更改它),您可能需要$ watch,否则上面的代码就足够了。

答案 1 :(得分:0)

不要使用手表。它会在以后产生大量的开销和麻烦。仅在绝对必要时使用。您应该尝试使用承诺,并尽可能让您的服务返回承诺。如果必须向您的外发服务提供回调(无法返回承诺),请执行以下操作:

myApp.controller('GreetingController', ['$scope', '$timeout', function($scope, $timeout) {

 $scope.token = false;

// Use this promise to simulate various events related to token fetching
var tokenFetched = $q.defer();

$scope.callbackYouMustHave = function(status, response) {
    if (!response.error) {
        tokenFetched.resolve(response.token); // or any other data you need
    } else {
        tokenFetched.reject(status, response); // Error handling
    }
}

tokenFetched.then(function(token) {
    // Triggering a digest with $timeout, a little awkward but better than watch trust me
    $timeout(function() {
        $scope.token = token; // This triggers a digest and changes your view / whatever
    });
    doThis();
    for(var i=0; i<len; i++) {
        myFnction("Do Some", MORE_STUFF);
    }

    someObj.fetchGoodStuff($scope.token);
});

tokenFetched.catch(function(status, response) {
    // error handling
    console.log('error fetching token:', response);
});

有。完全干净,完全可读。除非你绝对必须

,否则不要使用手表

作为对此的补充,我意识到如果你使用promises,你可能需要手动触发摘要。我做了另一个编辑