属性指令内的双向数据绑定,需要元素指令

时间:2015-11-06 17:08:50

标签: angularjs

我在同一元素上有一个元素指令(e-dir)和一个属性指令(a-dir):

<e-dir a-dir attr="msg"></e-dir>

我通过msg属性将e-dir传递到attr的隔离范围:

app.directive('eDir', function eDir($timeout) {
  return {
    restrict: 'E',
    scope: {
      attr: '='
    }
  };
}); 

通过这种方式,msg$scope.attrEDirCtrl)或scope.attre-dir的链接功能绑定(双向) )。

有一种简单的方法可以在a-dir的指令中实现相同的双向数据绑定吗?或者你会推荐另一种更简单的方法吗?

我能够提出的最接近的事情是在eDirCtrl.attr = $scope.attr;的控制器(e-dir)内设置EDirCtrl

app.directive('eDir', function eDir($timeout) {
  return {
    restrict: 'E',
    scope: {
      attr: '='
    },
    controller: function EDirCtrl($scope) {
      var eDirCtrl = this;
      eDirCtrl.attr = $scope.attr;
    },
    controllerAs: 'eDirCtrl'
  };
}); 

然后,让a-dir需要e-dir,并通过attr的控制器(e-dir)访问eDirCtrl.attr

app.directive('aDir', function aDir($timeout) {
  return {
    restrict: 'A',
    require: 'eDir',
    link: linkFn
  };

  function linkFn(scope, element, attrs, eDirCtrl) {
    eDirCtrl.attr = 'eDirCtrl.attr';
  }
});

但是,它不是双向的。正如您可以看到此代码段:

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

app.controller('Ctrl', function Ctrl($scope) {
  $scope.msg = 'initial message';
})

app.directive('eDir', function eDir($timeout) {
  return {
    restrict: 'E',
    scope: {
      attr: '='
    },
    template: '<div>$scope.attr: {{attr}}</div>'+
    '<div>eDirCtrl.attr: {{eDirCtrl.attr}}</div>',
    controller: function EDirCtrl($scope) {
      var eDirCtrl = this;
      eDirCtrl.attr = $scope.attr;
      $timeout(function() {
        $scope.attr = 'changing $scope.attr also changes msg';
      }, 2000);
    },
    controllerAs: 'eDirCtrl'
  };
}); 

app.directive('aDir', function aDir($timeout) {
  return {
    restrict: 'A',
    require: 'eDir',
    link: linkFn
  };

  function linkFn(scope, element, attrs, eDirCtrl) {
    $timeout(function() {
      eDirCtrl.attr = 'changing eDirCtrl.attr does not effect $scope.attr or msg';
    }, 4000);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" ng-controller="Ctrl">
  msg: <input type="text" ng-model="msg"><br>
  <e-dir a-dir attr="msg"></e-dir>
</div>

1 个答案:

答案 0 :(得分:2)

双向绑定不起作用的原因是attr被绑定到字符串而不是对象。在JavaScript中,基元(布尔值,数字,字符串)是不可变的,因此当您更改一个时,前一个实例将被丢弃并使用一个新实例。这会破坏Angular的双向绑定,对scope.msg的任何更改都不会通过attr传播到指令中。

您可以通过在对象上设置msg来按预期工作scope.test.msg并将attr绑定到test(对象),而不是msg(字符串)。

我已更新您的代码段以执行此操作:

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

app.controller('Ctrl', function Ctrl($scope) {
  $scope.test = {msg : 'initial message'};
})

app.directive('eDir', function eDir($timeout) {
  return {
    restrict: 'E',
    scope: {
      attr: '='
    },
    template: '<div>$scope.attr: {{attr.msg}}</div>'+
    '<div>eDirCtrl.attr: {{eDirCtrl.attr.msg}}</div>',
    controller: function EDirCtrl($scope) {
      var eDirCtrl = this;
      eDirCtrl.attr = $scope.attr;
      $timeout(function() {
        $scope.attr.msg = 'changing $scope.attr also changes msg';
      }, 2000);
    },
    controllerAs: 'eDirCtrl'
  };
}); 

app.directive('aDir', function aDir($timeout) {
  return {
    restrict: 'A',
    require: 'eDir',
    link: linkFn
  };

  function linkFn(scope, element, attrs, eDirCtrl) {
    $timeout(function() {
      eDirCtrl.attr.msg = 'changing eDirCtrl.attr does not effect $scope.attr or msg';
    }, 4000);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" ng-controller="Ctrl">
  msg: <input type="text" ng-model="test.msg"><br>
  <e-dir a-dir attr="test"></e-dir>
</div>