如何防止指令绑定到Angular中控制器范围内的元素



我有一个Angular应用程序MyApp,它依赖于外部模块(两种不同的地图解决方案),我需要它们,但在不同的控制器中(甚至在MyApp中的不同模块)。

问题是这两个模块都有绑定到同一个参数的指令(在本例中为"center"),这导致它们都操作单个元素。我想要的是一个指令在一个控制器内是活动的,而另一个指令则在另一个控制器中是活动的——所以不要让它们同时影响我的元素。

我不想更改外部模块的代码来实现这一点。

我发现这是一个非常有趣的问题。下面的答案是不完整的,坦率地说,有点粗糙,但它展示了一种在不修改模块本身源代码的情况下重命名另一个模块中的指令的方法。要使其接近生产,还有很多工作要做,而且绝对可以改进。

解决方案的注意事项是,一旦指令被重命名,"旧"名称将不再有效。它还取决于一些角度约定,这些约定可能会随着未来的版本等而改变,所以它不能经得起未来的考验。对于复杂的指令,它也可能失败,而且我还没有真正对它进行任何测试

然而,它证明了这是可以做到的,并且这个概念可能会导致功能角度的需求(为外部模块命名名称以防止冲突的能力,例如您正在经历的冲突)。

我认为,如果你的用例相当简单,这将解决你的问题,但我不建议在一般情况下使用它。

(function () {
          var util = angular.module('util', [], function ($compileProvider) {
            util.$compileProvider = $compileProvider
          })
          .factory('$directiveRename', function () {
              var noop = function () { return function () { }; };
              return function (module, directive, newDirective) {
                  var injector = angular.injector(['ng', module]);
                  var directive = injector.get(directive + 'Directive');
                  if(directive)
                  {
                      //there can be multiple directives with the same name but different priority, etc.  This is an area where this could definitely be improved.  Will only work with simple directives.
                      var renamedDirective = angular.copy(directive[0]);
                      delete renamedDirective['name'];
                      util.$compileProvider.directive(newDirective, function () {
                          return renamedDirective;
                      });
                   }
                  //noop the old directive
                  //http: //stackoverflow.com/questions/16734506/remove-a-directive-from-module-in-angular
                  angular.module(module).factory(directive + 'Directive', noop);
              };
          });
      })();

示例用法:

angular.module('app', ['module1', 'module2', 'util'])
  .run(function ($directiveRename) {
      $directiveRename('module1', 'test', 'testa');
      $directiveRename('module2', 'test', 'testb');
  });

另一个稍微不那么粗鲁的答案。

在包含angular的脚本标签后立即添加以下内容(在加载任何其他模块之前)

<script type="text/javascript">
        var angularModule = angular.bind(angular, angular.module);
        angular.module = function (moduleName, requires, configFn) {
            var instance = angularModule(moduleName, requires, configFn);
            var directive = instance.directive;
            instance.directive = function (directiveName, directiveFactory) {
                //You can rename your directive here based on the module and directive name.  I don't know the module and directive names for your particular problem.  This obviously could be generalized.
                if (instance.name == 'module1' && directiveName == 'test') {
                    directiveName = 'testa';
                }
                if (instance.name == 'module2' && directiveName == 'test') {
                    directiveName = 'testb';
                }
                return directive(directiveName, directiveFactory);
            }
            return instance;
        };
</script>

这是通过拦截对module.directive的调用来实现的,并允许您在创建指令之前重命名该指令。

最新更新