同一个Angular指令的多个实例会破坏作用域变量。

4

我正在页面上多次使用指令,例如:

<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得到了相同的值。 它获取了最后一次搜索服务调用的值。 我在这里缺少什么? 谢谢。

1个回答

3

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>


隔离作用域是一个问题,同时全局声明的缓存变量也会影响值。感谢您的帮助。 - Abhishek Agrawal
@AbhishekAgrawal - 如果您需要缓存事物的方式,我建议使用内置的$cacheFactory。你可以将它注入到你的指令中,并创建一个自定义命名的缓存。只要您对缓存键进行合理的命名,就不必担心全局声明的问题。 - Josh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接