Angular:在Link中,$ watch(ctrl.value)不起作用但是$ watch(function(){return ctrl.value})确实如此。为什么?

时间:2015-07-01 16:45:18

标签: angularjs angularjs-directive

我一直在阅读其他人关于如何在AngularJS(1.4)中正确使用$ watch的答案,但我仍然不明白为什么我的代码不起作用。我不明白如何从指令的链接函数中查看模型值。设置scope.$watch(controller.value)仅在值绑定到控制器之前触发(值仍未定义),稍后在值更改时不会触发。另一方面,scope.$watch(function(){return controller.value})有效。那是为什么?

在我的示例中,我在控制器userCtrl上有一个年龄值。我想基于btn-primary的值将类btn-successcontroller.age添加到按钮:以下是指令:

app.directive('myDirective',function(){
  return {
    restrict: 'A',
    templateUrl:'my-directive.html',
    bindToController: true,
    controller: 'userController',
    controllerAs: 'userCtrl',
    scope: {user:'='}, //example: {name:'John',age:9}
    link: function(scope,element,attrs){
      var vm = scope.userCtrl;
      var el_button = element.find('button');

      //WHY IS $WATCH NOT GETTING CALLED WHEN THE AGE CHANGES?
      //if we change vm.user.age to function(){return vm.user.age} things work
      //but why is that any different?
      scope.$watch(vm.user.age,function(newVal,oldVal){
        console.log('age has changed to ' + newVal);
        if(newVal > 9){
          el_button.removeClass('btn-primary');
          el_button.addClass('btn-success');
        }else{
          el_button.removeClass('btn-success');
          el_button.addClass('btn-primary');
        }
      });
    }
  }
});

app.directive('myDirective',function(){ return { restrict: 'A', templateUrl:'my-directive.html', bindToController: true, controller: 'userController', controllerAs: 'userCtrl', scope: {user:'='}, //example: {name:'John',age:9} link: function(scope,element,attrs){ var vm = scope.userCtrl; var el_button = element.find('button'); //WHY IS $WATCH NOT GETTING CALLED WHEN THE AGE CHANGES? //if we change vm.user.age to function(){return vm.user.age} things work //but why is that any different? scope.$watch(vm.user.age,function(newVal,oldVal){ console.log('age has changed to ' + newVal); if(newVal > 9){ el_button.removeClass('btn-primary'); el_button.addClass('btn-success'); }else{ el_button.removeClass('btn-success'); el_button.addClass('btn-primary'); } }); } } });

关于Plunker的演示:http://plnkr.co/edit/nFjiCzVhVJkUGY5AEM1C?p=preview

1 个答案:

答案 0 :(得分:1)

这是因为vm.user.age在该时间点返回的值被视为要根据范围进行评估的表达式(或此处的属性)。如果在那个时间点说值为12,那么它会在范围内设置属性12上的监视,这显然不是您所期望的。

您应该给出表达式的字符串表示形式(scope.$watch('userCtrl.user.age', function(newVal...),该表达式可以根据返回值的范围或函数进行评估。当您提供userCtrl.user.age被观看时,angular将在$parse service的帮助下将表达式包裹在function(){ return $scope.userCtrl.user.age; } 中,以便说出类似的内容(例如,getter函数将更复杂到解决空检查等问题。):

- (void)viewDidLoad{
[super viewDidLoad];

// add pan recognizer to the view when initialized
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panRecognized:)];
[panRecognizer setDelegate:self];
[yourView addGestureRecognizer:panRecognizer]; // add to the view you want to detect swipe on
}


-(void)panRecognized:(UIPanGestureRecognizer *)sender{

CGPoint distance = [sender translationInView: yourView];


if (sender.state == UIGestureRecognizerStateEnded) {
    [sender cancelsTouchesInView];


    if (distance.x > 70 && distance.y > -50 && distance.y < 50) { // right

        NSLog(@"user swiped right");
        NSLog(@"distance.x - %f", distance.x);

    } else if (distance.x < -70 && distance.y > -50 && distance.y < 50) { //left

        NSLog(@"user swiped left");
        NSLog(@"distance.x - %f", distance.x);

    }

    if (distance.y > 0) { // down
        NSLog(@"user swiped down");
        NSLog(@"distance.y - %f", distance.y);
    } else if (distance.y < 0) { //up
        NSLog(@"user swiped up");
        NSLog(@"distance.y - %f", distance.y);
    }

}
}

将在消化周期中对变化检测进行评估。因此,自己提供一个吸气功能也不会造成任何伤害。