15

如果我有一个没有模板的 AngularJS 指令,并且我希望它在当前范围内设置一个属性,那么最好的方法是什么?

例如,计算按钮点击次数的指令:

<button twoway="counter">Click Me</button>
<p>Click Count: {{ counter }}</p>

使用将点击计数分配给双向属性表达式的指令:

.directive('twoway', [
'$parse',
  function($parse) {
    return {
      scope: false,
      link: function(scope, elem, attrs) {
        elem.on('click', function() {
          var current = scope.$eval(attrs.twoway) || 0;
          $parse(attrs.twoway).assign(scope, ++current);
          scope.$apply();
        });
      }
    };
  }
])

有一个更好的方法吗?从我读过的内容来看,一个孤立的范围会过大,但我需要一个子范围吗?除了使用$parse. 我只是觉得我让这件事变得太难了。

完整的 Plunker在这里

4

5 回答 5

33

为什么隔离范围过大?它对这种事情非常有用:

  scope: {
     "twoway": "=" // two way binding
  },

这是这个问题的一个非常惯用的角度解决方案,所以这就是我坚持的。

于 2013-09-18T21:18:32.503 回答
25

我很惊讶没有人提到ng-model,做两个数据绑定的默认指令。也许它不是那么为人所知,但链接函数有第四个参数:

angular.module('directive-binding', [])
  .directive('twoway', 
      function() {
        return {
          require: '?ngModel',
          link: function(scope, elem, attrs, ngModel) {
            elem.on('click', function() {
              var counter = ngModel.$viewValue ? ngModel.$viewValue : 0
              ngModel.$setViewValue(++counter);
              scope.$apply();
            });
          }
        };
      }
    );

在你看来

<button twoway ng-model="counter">Click Me</button>
<p>Click Count: {{ counter }}</p>

第四个参数是ngModelController的 API ,它在处理(例如解析和格式化)和在指令和范围之间共享数据有很多用途。

这是更新的Plunker

于 2013-09-18T21:35:56.650 回答
2

您绝对可以在不使用的情况下将其简化一点$parse

angular.module('directive-binding', []).directive('twoway', [function () {
    return {
        scope: false,
        link: function (scope, elem, attrs) {
            elem.on('click', function () {
                scope[attrs.twoway] = scope[attrs.twoway] == null ? 1 : scope[attrs.twoway] + 1;
                scope.$apply();
            });
        }
    };
}]);
于 2013-09-18T21:18:39.767 回答
2

应用双向绑定的一个好方法是使用指令组件。这是我的解决方案。它允许使用 ng-repeat 和可扩展的数据绑定。

查看 Plunker

HTML

<body ng-controller='MainCtrl'>  
    Data: {{data}}
    <hr>
    <mydirective name='data[0]'></mydirective>
    <hr>
    <mydirective name='data[1]'></mydirective>
</body>

控制器

app.controller('MainCtrl', function($scope) {
  $scope.data = [];
  $scope.data[0] = 'Marco';
  $scope.data[1] = 'Billy';
});

指示

app.directive("mydirective", function(){
    return {
        restrict: "EA",
        scope: {name: '='},
        template: "<div>Your name is : {{name}}</div>"+
        "Change your name : <input type='text' ng-model='name' />"
    };
});

在计数器的情况下,可以使用相同的方法完成。

于 2016-05-27T16:10:04.007 回答
0

将模板更改为:

<button twoway bind="counter">Click Me</button>
<p>Click Count: {{ counter.val }}</p>

并指示:

.directive('twoway',
    function() {
        return {
            scope: {
                localValue: '=?bind'
            },
            link: function(scope, elem, attrs) {
                scope.localValue = {
                    val: 0
                };
                elem.on('click', function() {
                    scope.localValue.val = scope.localValue.val + 1;
                    scope.$apply();
                });
            }
        };
    }
);
于 2017-01-16T20:31:29.270 回答