Angular' $ watch

时间:2016-04-29 13:14:37

标签: angularjs

今天我在使用$ watch的AngularJS中遇到了一些非常奇怪的行为。我将代码简化为以下示例:

https://jsfiddle.net/yLeLuard/

此示例包含一个跟踪state变量的服务。指令用于将click事件绑定到DOM,通过服务更改state变量。

此示例中存在两个问题:

  1. 第一个关闭按钮(上面带有ng-click属性)仅更改第二次单击时的状态
  2. 没有ng-click的两个按钮不会改变状态
  3. main.html中

    <div ng-controller="main">
      State: {{ api.isOpen | json }}
      <div ng-click="" open>
        <button>Open - Working fine</button>
      </div>
      <div ng-click="" close>
        <button>Close - Works, but only on second click</button>
      </div>
      <div open>
        <button>Open - Not Working</button>
      </div>
      <div close>
        <button>Close - Not Working</button>
      </div>
    </div>
    

    main.js

    var myApp = angular.module('myApp', []);
    
    myApp.controller('main', ['$scope', 'state', function($scope, state) {
      $scope.api = state;
    
      $scope.api.isOpen = false;
    
      $scope.$watch('api.isOpen', function() {
        console.log('state has changed');
      });
    }]);
    
    myApp.directive('open', ['state', function(state) {
      return {
        restrict: 'A',
        scope: {},
        replace: true,
        template: '<button>Open</button>',
        link: function(scope, element) {
          element.on('click', function() {
            state.isOpen = true;
          });
        }
      };
    }]);
    
    
    myApp.directive('close', ['state', function(state) {
      return {
        restrict: 'A',
        scope: {},
        replace: true,
        template: '<button>Close</button>',
        link: function(scope, element) {
          element.on('click', function() {
            state.isOpen = false;
          });
        }
      };
    }]);
    
    myApp.service('state', function() {
      return {
        isOpen: null
      };
    });
    

2 个答案:

答案 0 :(得分:4)

那是因为您在click上使用了本机事件监听器。此事件是异步的,不属于Angular摘要周期,因此您需要手动消化范围。

myApp.directive('open', ['state', function(state) {
  return {
    restrict: 'A',
    scope: {},
    link: function(scope, element) {
      element.on('click', function() {
        scope.$apply(function() {
          state.isOpen = true;
        });
      });
    }
  };
}]);

修正小提琴:https://jsfiddle.net/7h95ct1y/

我建议直接在ng-click中更改状态:ng-click="api.isOpen = true"

答案 1 :(得分:0)

您应该将链接功能作为预链接功能,这解决了第二次点击的问题。

https://jsfiddle.net/2c9pv4xm/

myApp.directive('close', ['state', function(state) {
  return {
    restrict: 'A',
    scope: {},
    link:{
     pre: function(scope, element) {
      element.on('click', function() {
        state.isOpen = false;
        console.log('click', state);
      });
    }
    }
  };
}]);

对于不工作的部分,你将你的指令放在div上,所以当你单击div时它可以工作但不能按下按钮。你的开放指令应该在按钮上。

编辑:其他评论者建议您直接在ng-click中更改状态。我不推荐它,它可能适用于这种情况,但是如果你必须有更多的分配来做它不可行。