使用 $provide 重命名第三方角度指令 - 不起作用

Renaming 3rd party Angular Directive using $provide - not working

本文关键字:指令 不起作用 第三方 provide 重命名 使用      更新时间:2023-09-26

我已经在一个大型站点中使用了出色的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.logs,看看它走了多远,我可以看到它甚至没有运行装饰器。起初我认为这可能是 uiPaginationDirective 中的一个简单的拼写错误,但如果我更改一个字符,那么我在控制台中会出现一个很大的注入器错误。所以,它肯定找到了原始指令,但装饰函数没有运行。

我真的在做傻事吗?

编辑:澄清一下,我正在使用ng-annotate来简化依赖注入,因此.config()中没有依赖关系数组

编辑 2:如果页面上未使用该元素,装饰器就不会运行,我没有意识到这一点。因此,如果您使用旧元素,那么装饰器确实会运行,但是如果您使用新别名,则根本不会发生任何事情。我开始认为,我发现的这段代码可能永远不会起作用,除非使用原始指令来启动装饰器。

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

编辑 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:多目录] 多个指令 [s4p寻呼(模块: s4p), uib分页] 要求模板:...

我不明白为什么他们都要求模板。我本来假设 s4p 分页将被 uib-pagination 替换,并且所有属性都复制到 uib-pagination 元素上。显然我不明白为什么这样简单的东西不起作用。

根据我对另一个问题的旧解决方案,您需要在页面上至少使用该指令的一个实例,因为这是角度 DI 的工作方式。它仅在首次使用时懒惰地实例化任何工厂。

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

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

您可以从我的存储库中获取模块

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'
  });
}]);

这是一个笨蛋

试试这个:

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>

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

查看工作堆积器