同一角度指令的多个实例混淆了范围变量

Multiple instance of same angular directive mess up scope variables

本文关键字:实例 变量 范围 一角 指令      更新时间:2023-09-26

我像一样在页面上多次使用该指令

<div data-escape-amp-curation-multi-value-selector
         data-binding-path="model"
         data-search-key="journeys"
         data-current-selection-model="model.journeys">
    </div>
<div data-escape-amp-curation-multi-value-selector
         data-binding-path="model"
         data-search-key="targets"
         data-current-selection-model="model.targets">
    </div>

我的指令看起来像

var directive : ng.IDirective = {
  restrict : 'A',
  template : '<select multiple="multiple" data-options="sources/>',
  compile() {
    return {
      pre(scope : any, element : any, attrs : any) {
        scope.readonly = attrs.readonly === 'true';
      },
      post(scope : any, element : any, attrs : any) {
        var binder = $parse(attrs.currentSelectionModel),
        valueDropDown = element.find('select.value-dropdown'),
        kendoMultiSelect = valueDropDown.data('kendoMultiSelect'),
        defer = $q.defer();
        /**
         * The method to do search.
         * @type {void}
         */
        scope.doSearch = () =  > {
          scope.showSpinner = true;
          scope.$evalAsync(() =  > {
              if (!cache) {
                metadataService.getMetadata(attrs.searchKey).then(
                  result =  > {
                    cache = result;
                    scope.sources = result;
                    defer.resolve();
                  },
                  error =  > {
                    defer.reject(error);
                  });
              } else {
                scope.sources = cache;
                defer.resolve();
              }
              defer.promise.then(() =  > {
                  kendoMultiSelect.setDataSource(scope.sources);
                  scope.showSpinner = false;
                  kendoMultiSelect.value(binder(scope));
                });
            });
        };
        kendoMultiSelect.bind('change', () =  > {
            binder.bind(scope, kendoMultiSelect.value());
          });
        /**
         * Set cache to null on location change
         */
        scope.$on(LOCATION_CHANGE_START, () =  > {
            cache = null;
          });
        scope.$watch(() =  > scope.$eval(attrs.currentSelectionModel), () =  > {
            if (!scope.sources) {
              if (angular.isDefined(cache) && cache !== null) {
                $timeout(() =  > {
                    scope.sources = cache;
                    kendoMultiSelect.setDataSource(scope.sources);
                    kendoMultiSelect.value(binder(scope));
                  });
              } else {
                scope.doSearch();
              }
            } else {
              kendoMultiSelect.setDataSource(scope.sources);
              kendoMultiSelect.value(binder(scope));
            }
          });
      }
    }
  }
}

当此代码呈现时,它会调用后端服务以根据搜索关键字填充源,但bot实例的scope.sources会获得相同的值。它获取上次搜索服务调用的值。我在这里缺少什么?谢谢

scope在Angular中是原型继承的,但只有在您请求时才会创建新的作用域。在这种情况下,您只是在装饰由您的指令所在的父级定义的现有范围。

这意味着添加到作用域的任何内容都将被同一指令覆盖。

只需将scope:true属性添加到指令定义对象中,就可以告诉指令创建一个新的作用域

{
  restrict : 'A',
  scope:true
  //more stuff
}

下面是一个简单的示例,用于显示创建新作用域的指令和不创建的指令之间的区别。

(function() {
  'use strict';
  function NoNewScope() {
    return {
      restrict: 'A',
      template: [
        '<div class="form-group">',
        '  <label>Name - <code>{{name}}</code></label>',
        '  <input class="form-control" type="text" ng-model="name" />',
        '</div>'
      ].join(''),
      link: function(scope) {
        scope.name = "No New Scope";
      }
    };
  }
  function NewScope() {
    return {
      restrict: 'A',
      scope: true,
      template: [
        '<div class="form-group">',
        '  <label>Name - <code>{{name}}</code></label>',
        '  <input class="form-control" type="text" ng-model="name" />',
        '</div>'
      ].join(''),
      link: function(scope) {
        scope.name = "New Scope";
      }
    };
  }
  angular.module('my-app', [])
    .directive('noNewScope', NoNewScope)
    .directive('newScope', NewScope);
}());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="my-app" class="container">
  <div class="row">
    <div class="col-xs-6">
      <h3>NO new scope</h3>
      <div no-new-scope></div>
      <div no-new-scope></div>
    </div>
    <div class="col-xs-6">
      <h3>NEW scope</h3>
      <div new-scope></div>
      <div new-scope></div>
    </div>
  </div>
</div>