如何在控制器中修改指令隔离范围变量,同时仍然保持隔离?

How to modify directives isolated scope variable in controller, while still keeping it isolated?

我有一个独立作用域的指令。我正在修改指令控制器中从父控制器传递的变量之一。我 运行 遇到的问题是,当我在同一视图上使用此指令的多个实例(具有不同的 optionsmodel)时,options 对象不会对指令的每个实例保持唯一。相反,它成为一个共享变量,指令的所有实例都使用相同的 options 对象。

所以如果我像下面这样在我的视图中使用它们,optionsA.isFlagOn = trueoptionsB.isFlagOn = false

<my-directive model="modelA" options="optionsA">
<my-directive model="modelB" options="optionsB">

带有 modelB 的指令加载 optionsA

如何在为每个特定实例修改它时保持 options 唯一性?

angular.module('myModule', [])
.directive('myDirective', function($compile) {
  template = '<h3><span ng-bind="model.title"><h3><p><span ng-bind="options"></span></p>';
  return {
    restrict: 'AE',
    scope: {
       model: "=",
       options: "=?" //A JSON object
    },
    controller: function($scope) {
      $scope.options = $scope.options || {};
      //A function that sets default values if no options object passed
      ensureDefaultOptions($scope);

      //now based on some of the options passed in, I modify a property in the options object
      if ($scope.options.isFlagOn)
        $scope.options.thisProp = true;
    },
    link: function(scope, element, attr) {
      let content = $compile(template)(scope);
      element.append(content);
    }
  };
}

编辑: 我解决了我的问题。我的解决方案发布在下面的答案中。

你能把它改成你的单向绑定吗:

scope: {
       model: "=",
       options: "<?" //A JSON object
    }

你的指令应该复制传入的选项和默认值,这样每个指令实例都有自己的选项对象。

您可以使用 extend

轻松实现
var defaultOptions = { a:1, b:2, c:3 };
var options = angular.extend(defaultOption, $scope.options);
// then use options everywhere

请注意,这只会在初始化期间执行一次,因此如果您的选项异步来自控制器,则需要额外处理。

我使用 1.4x 或更高版本中可用的 Angular 指令的 bindToController 属性 解决了这个问题。

angular.module('myModule', [])
  .directive('myDirective', function($compile) {
    template = '<h3><span ng-bind="vm.model.title"><h3><p><span ng-bind="myOptions"></span></p>';
    return {
      restrict: 'AE',
      bindToController: {
        model: "=",
        options: "=?" //A JSON object
      },
      scope: {},
      controller: function() {
        var vm = this;

        //a function that handles modifying options
        vm.setOptions = function(options){
          let newOptions = {};
          angular.copy(options, newOptions);

          // modify newOptions here

          return newOptions;
        }

      },
      controllerAs: 'vm',
      link: function(scope, element, attr) {

         ensureDefaultOptions(scope.vm);

         scope.myOptions = scope.vm.setOptions(scope.vm.options);

         let content = $compile(template)(scope);
         element.append(content);
      }
    };
  });