AngularJS指令中的属性更改通知

时间:2015-10-23 12:50:58

标签: angularjs

我有一个包含大量文本框的页面,类似Excel的布局。每列代表一个对象,该列中的单元格包含对象的属性。当单元格中的值发生更改(当单元格失去焦点时触发),我需要知道更改的对象和属性,以便我可以将值复制到其他所选对象中的相同属性。

我有这个工作,但这是一种天真的方法,我认为最好将其封装在一个指令中。问题是我能够编写的指令与我的第一个解决方案一样冗长,似乎并没有改进。

first version只是将对象和属性名称传递给更改处理函数。

<td>
    <input ng-model="person.firstName" 
           ng-change="personChanged(person, 'firstName')" 
           ng-model-options="{updateOn: 'blur'}" />
</td>

$scope.personChanged = function(person, property) {
  alert(person.personId + ' : ' + property);
}

second version使用指令。

<td>
    <input ng-model="person.firstName" 
           name-changed person="person" property="'firstName'" />
</td>

myApp.directive('nameChanged', function() {
  return {
    restrict: 'A',
    scope: {
      person: '=',
      property: '='
    },
    link: function(scope, element, attrs){
      element.bind('change', function(e){
        alert(scope.person.personId + ' : ' + scope.property);
      });
    }
  };
});

在这两个解决方案中,我在属性中声明对象和属性名称,这似乎是多余的,因为我已经通过ngModel提供了两者。这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

当您编写ngModel="person.firstname"时,angular将侦听firstname属性上的任何更改,并且它只会在您的ngModel中保留firstname的值(请查看ngModel和ngModelController上的文档)。这意味着您必须在指令范围内传递其他信息(例如person.id,property)

你应该尽可能避免双向绑定。使用&#39;&amp;&#39;和&#39; @&#39;将属性绑定到指令范围时。

指令的优化版本:

myApp.directive('nameChanged', function() {
  return {
    require: 'ngModel',
    restrict: 'A',
    scope: {
      person: '&',
      property: '@'
    },
    link: function(scope, element, attrs, ngModel){
      element.bind('change', function(e){

        alert(scope.person().personId  + ' : ' + scope.property + ', value is : ' + ngModel.$modelValue)

      // dispatch your change to upper scopes
      scope.$emit('nameChanged', {personId : scope.person().personId, property: scope.property, value : ngModel.$modelValue});

      });
    }
  };
});

然后在你的控制器中处理这个事件:

myApp.controller('peopleController', function($scope) {
  $scope.people = [new Person(1, 'Homer', 'Simpson'), new Person(2, 'Ned', 'Flanders'), new Person(3, 'Otto', 'Mann')];


  $scope.$on('nameChanged', function(event, change){
    // changed detected inside one of ours dirctives
    console.log('changed detected from controller', change)     
    // do what you want with he new value : 'change.value'

  })

});

请注意,事件名称应位于.constant模块中。它的可维护性更好。

Plunker here

您可以通过两种方式(使用ng-change和范围内的fn)或使用isolate scope指令实现您想要的任何方式。就个人而言,我喜欢在指令中做到这一点,以隔离责任,但这取决于你。