使用 $provide 重命名第 3 方 Angular 指令 - 不起作用 [英] Renaming 3rd party Angular Directive using $provide - not working

查看:19
本文介绍了使用 $provide 重命名第 3 方 Angular 指令 - 不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个大型站点中使用了出色的 Angular UI 引导程序以及我自己的许多指令.为了简洁起见,我寻找了一种在不触及代码的情况下重命名几个 uib 指令的方法,并遇到了几个 SO 问题,看起来是一个很好的解决方案.问题是它对我不起作用.这是我的代码.

I've using the excellent Angular UI bootstrap in a large site alongside lots of my own directives. For the sake of neatness I looked for a way of renaming a couple of the uib directives without touching their code and came across a couple of SO questions and what looked like a great solution. The trouble is that it's not working for me. Here's my code.

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 中的一个简单的拼写错误,但是如果我更改了一个字符,那么我会在控制台中出现一个很大的注入器错误.所以,它肯定会找到原始指令,但装饰函数没有运行.

I've put a couple of console.logs in there to see how far it's getting and I can see that it's not even running the decorator. At first I thought this might have been a simple spelling mistake in uiPaginationDirective but if I change even a single character then I get a big injector error in the console. So, it's definitely finding the original directive but the decorate function is not running.

我真的在做一些愚蠢的事情吗?

Am I doing something really stupid?

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

Edit: Just to clarify, I'm using ng-annotate to simplify dependency injection, hence no array of dependencies in the .config()

编辑 2:如果该元素未在页面上使用,则装饰器不会运行,这是我没有意识到的.因此,如果您使用旧元素,则装饰器确实会运行,但如果您使用新别名,则什么也不会发生.我开始认为,除非使用原始指令来启动装饰器,否则我发现的这段代码可能永远不会工作.

Edit 2: The decorator doesn't run if the element isn't used on the page, which I didn't realise. So, if you use the old element then the decorator does run, but if you use the new alias then nothing happens at all. I'm beginning to think that this code I found may never have worked unless the original directive is used to kick the decorator into gear.

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

Edit 3: I've added a bounty to this because it would be nice to find a solution. Even if nobody can fix the example code there must be other ways of renaming a third party directive without changing it? I have found a plugin called "alias" which does this but I don't really want to use more 3rd party code and I want to understand the solution.

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

Edit 4: I have been playing with the code which I borrowed to make this which you can see in the following plunkr - http://plnkr.co/edit/3aDEed?p=preview I think it only works because the demo uses the original directive in the HTML followed by the renamed directive. If you remove the original one from the HTML then they both disappear. This I assume is because the directive decorator is only run the first time the directive is used. So, my quest is now to find a way to get the decorator to run without using the original directive, or to look for a better way to rename a 3rd party directive...

编辑 5:我尝试了其他一些东西,这似乎是别名插件在幕后所做的事情.

Edit 5: I tried something else which seems to be what the alias plugin seems to be doing under the hood.

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

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

});

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

...but unfortunately I get the following error.

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

Error: [$compile:multidir] Multiple directives [s4pPaging (module: s4p), uibPagination] asking for template on:...

我不明白为什么他们都要求模板.我会假设 s4p-paging 将被 uib-pagination 替换,并且所有属性都复制到 uib-pagination 元素上.显然,我不明白为什么这样简单的事情不起作用.

I don't get why they are both asking for template. I would have assumed that the s4p-paging would get replaced with the uib-pagination and all of the attributes copied on to the uib-pagination element. Clearly I don't understand why something simple like that doesn't work.

推荐答案

基于我的另一个问题的旧解决方案,您需要在页面上使用至少一个指令实例,因为这是 angular DI 的工作方式.它仅在第一次使用时懒惰地实例化任何工厂.

Based on my old solution for another question, you would need to use at least one instance of the directive on the page since that is the way angular DI works. It lazily instantiates any factory only when it is used for the first time.

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

As i mention in my comment earlier you can get any directive configuration by getting the directive factory (directive name suffixed by the the word "Directive")$injector.get('directiveNameDirective').

这是解决问题的抽象(请记住,这也将解决原始线程中的命名冲突问题,而且这更加模块化,并且只需在您的应用程序中调用一个配置即可轻松设置).

Here is an abstraction for resolving the problem (remember this will resolve the naming conflict problem as well from the original thread also this is more modular and easy set up with just one config call in your app).

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

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

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

All you would need to do now is to include this as dependency in your module.

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

并通过提供格式为 {sourceDirectiveName : targetDirectiveName } 的配置对象来配置它.

and configure it by providing a config object which is of the format {sourceDirectiveName : targetDirectiveName }.

app.config(['renameDirectiveProvider',function(renameDirectiveProvider){
  renameDirectiveProvider.setConfig({
    'property' : 'cmProperty'
  });
}]);

这是一个plunker

Here is a plunker

这篇关于使用 $provide 重命名第 3 方 Angular 指令 - 不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆