使用$ provide重命名第三方Angular Directive - not working

时间:2016-03-17 00:22:35

标签: javascript angularjs angularjs-directive angularjs-compile

我在大型网站中使用了优秀的Angular UI引导程序以及我自己的许多指令。为了整洁起见,我寻找了一种方法来重命名几个uib指令而不触及他们的代码,并遇到了几个SO问题,看起来是一个很好的解决方案。麻烦的是,它不适合我。这是我的代码。

angular.module('s4p').config(function($provide, $compileProvider){

    console.log("I am logged in the console");

    $provide.decorator('uibPaginationDirective', function($delegate){

        console.log("I am not logged");

        $compileProvider.directive('s4pPaging', function(){
           return $delegate[0];
        });

        return function() { return angular.noop };

    });
});

我已经在那里放了几个console.log来看看它到底有多远,我可以看到它甚至没有运行装饰器。起初我认为这可能是uiPaginationDirective中的一个简单的拼写错误,但如果我改变了一个字符,那么我在控制台中会出现一个很大的注入错误。所以,它肯定找到了原始指令,但装饰功能没有运行。

我做的事真的很蠢吗?

编辑:为了澄清,我使用ng-annotate来简化依赖注入,因此.config()中没有依赖项数组

编辑2 :如果页面上没有使用该元素,装饰器就不会运行,我没有意识到。因此,如果您使用旧元素,则装饰器会运行,但如果您使用新别名,则根本不会发生任何事情。我开始认为我发现的这些代码可能永远不会有效,除非使用原始指令将装饰器置于装备之中。

编辑3 :我已经为此添加了赏金,因为找到解决方案会很好。即使没有人能修复示例代码,也必须有其他方法来重命名第三方指令而不更改它?我找到了一个名为"别名的插件"这样做但我不想使用更多第三方代码,我想了解解决方案。

编辑4 :我一直在玩我借用的代码,你可以在下面的plunkr中看到 - http://plnkr.co/edit/3aDEed?p=preview我认为它只有用,因为演示使用了HTML中的原始指令,后跟重命名的指令。如果从HTML中删除原始文件,则它们都会消失。我假设是因为指令装饰器仅在第一次使用该指令时运行。所以,我现在的任务是找到一种方法让装饰器在不使用原始指令的情况下运行,或者寻找更好的方法来重命名第三方指令......

编辑5 :我尝试了其他似乎是别名插件似乎在幕后做的事情。

angular.module('s4p').directive('s4pPaging', function(){

    return {
        restrict: 'EA',
        replace: true,
        template: '<uib-pagination class="s4pPaging"></uib-pagination>'
    }

});

...但不幸的是我收到了以下错误。

  

错误:[$ compile:multidir]多个指令[s4pPaging(模块:   s4p),uibPagination]要求模板:...

我不知道为什么他们都要求模板。我原以为s4p-paging会被uib-pagination和被复制到uib-pagination元素的所有属性所取代。很明显,我不明白为什么像这样简单的东西不起作用。

2 个答案:

答案 0 :(得分:3)

基于我的old solution for another question,您需要在页面上使用至少一个指令实例,因为这是角度DI工作的方式。只有当它第一次使用时,它才会懒惰地实例化任何工厂。

正如我在前面的评论中提到的,您可以通过获取指令工厂获得任何指令配置(指令名称后缀为&#34;指令&#34;)$injector.get('directiveNameDirective')

这是一个解决问题的抽象(请记住,这将解决命名冲突问题以及原始线程,这也是更模块化,更容易设置,只需在您的应用程序中进行一次配置调用)。

你可以get the module from my repository

angular.module('renameDirectiveUtil', [])
.provider('renameDirective', ['$provide' , '$compileProvider' , function($provide, $compileProvider){
    var directiveSet;

    this.setConfig = function setConfig(config){
      directiveSet = config;

       angular.forEach(directiveSet, function iterator(targetDir, sourceDir){
          sourceDir +=  'Directive';
          //Set up decorators
          $provide.decorator(sourceDir, function decorate($delegate){

             //Used to register a directive. $delegate is the original directive definition.
             $compileProvider.directive(targetDir, function(){
                return $delegate[0];
             });

              //This will remove the original directive definition, if not just return the delegate as is.
              return function() { return angular.noop };
          });
      });
    };

    this.$get  = ['$injector', function renameDirectiveService($injector){
      return { 
        rename : function rename(){
          angular.forEach(directiveSet, function(_,dir){
             var sourceDir = dir + 'Directive';
            //Just return the original directive definition which will trigger the decorator and redefine itself while renaming the new one.
            $injector.get(sourceDir);
          });
        }
      }
    }];
}]).run(['renameDirective',function(renameDirective){
  renameDirective.rename();
}]);

现在您需要做的就是将其作为依赖项包含在您的模块中。

 angular.module('plunker', ['renameDirectiveUtil']);

并通过提供格式为{sourceDirectiveName : targetDirectiveName }

的配置对象来配置它
app.config(['renameDirectiveProvider',function(renameDirectiveProvider){
  renameDirectiveProvider.setConfig({
    'property' : 'cmProperty'
  });
}]);

这是 plunker

答案 1 :(得分:2)

试试这个:

var app = angular.module('plunker', ['ui.bootstrap', 'myDirectives']);

angular.module('myDirectives', [])
.directive('myPagination', function($injector) {
  return angular.copy($injector.get('uibPaginationDirective'))[0];
});

app.controller('PaginationDemoController', function($scope) {});

<body ng-app="plunker">
  <div ng-controller="PaginationDemoController">
    <my-pagination total-items="20" ng-model="currentPage"></my-pagination>
  </div>
</body>

无需首先在页面上使用原始指令即可。

请参阅working plunker