AngularJS指令在prelink中等待promise

时间:2015-03-19 09:28:19

标签: angularjs angularjs-directive angular-promise

我想在我的应用程序中创建一个插件系统。 在我的第一个版本中应该有一个插件文件夹,我将插件放在他们自己的文件夹中。

每个插件都有自己的指令,应该在运行时加载。

文件夹结构如下所示:

-plugins
--plugin1
---directive_plugin1.js
---plugin1.html
--plugin2
---directive_plugin2.js
---plugin2.html

在我的应用程序中,有一些注册的插件如下所示:

$rootScope.registered_plugins = ['plugin1', 'plugin2'];

所以我设置了一个插件指令,如下所示:

module.directive('plugin', ['$compile', 'angularLoad', function($compile, angularLoad) {
        return {
            restrict: 'E',
            scope: { 'plugin': '@' },
            compile: function(element, attrs, transclude) {
                return {
                    pre: function preLink(scope, element, attrs, controller) {
                        console.log('PRE!');

                        var load_script = function() {
                            var url = '/js/plugins/' + scope.plugin + '/directive_' + scope.plugin + '.js';
                            var load = angularLoad.loadScript(url);

                            load.then(function () {
                                console.log('LOADED!');
                            });

                            load.catch(function () {
                                console.log('NOT LOADED!');
                            });
                        };

                        load_script();

                    },
                    post: function postLink(scope, element, attrs, controller) {
                        console.log('POST!');
                        var template = '<' + scope.plugin + ' />';
                        var compiled = $compile(template)(scope);
                        element.append(compiled);
                    }
                }
            }
        }
    }]);

我的插件工厂看起来像这样:

module.factory('pluginfactory', function ($q, $timeout) {
    return function(key) {
        var d = $q.defer();
        $timeout(function() {
            d.resolve(key);
        }, 1);

        return d.promise;
    };
});

我的plugin1指令如下所示:

module.directive('plugin1', function() {
   return {
       restrict: 'E',
       templateUrl: '/js/plugins/plugin1/plugin1.html'
   };
});

我的plugin1 html看起来像这样:

<p>Hello, I am plugin1</p>

我的plugin2指令如下所示:

module.directive('plugin2', function() {
   return {
       restrict: 'E',
       templateUrl: '/js/plugins/plugin2/plugin2.html'
   };
});

我的plugin2 html看起来像这样:

<p>Hello, I am plugin2</p>

我的控制器看起来像这样:

module.controller('PluginController', function($scope, pluginfactory){
        $scope.reset_loading();

        $scope.templates = [
            {template: {url: $scope.folder_plugin + '/plugin_content.html'}}
        ];

        $scope.template_plugin_content = $scope.templates[0].template;
        $scope.validated_plugins = [];

        $scope.validate_plugins = function() {
            for(var i = 0; i < $scope.registered_plugins.length; i++) {
                var key = $scope.registered_plugins[i];
                pluginfactory(key).then(function (plugin) {
                    $scope.validated_plugins.push(plugin);
                });
            }
        };
    });

我的插件html看起来像这样(它正在使用PluginController):

<div class="col2">
    <div class="container-inner"
         ng-init="validate_plugins()">
        <h1>{{ 'PLUGIN_CONTENT' | translate }}</h1>

        <div ng-repeat="p in validated_plugins">
            <plugin plugin='{{ p }}'></plugin>
        </div>
    </div>
</div>

所以主要的问题是,我想在plugin指令的prelink过程中预加载plugin1和plugin2指令。我读到角加载应该对我有用。

当我执行代码时,插件的内容如下所示:

<div ng-repeat="p in validated_plugins" class="ng-scope">
            <plugin plugin="plugin1" class="ng-isolate-scope"><plugin1 class="ng-scope"></plugin1></plugin>
        </div>

<div ng-repeat="p in validated_plugins" class="ng-scope">
            <plugin plugin="plugin2" class="ng-isolate-scope"><plugin2 class="ng-scope"></plugin2></plugin>
        </div>

所以,基本上没有设置p元素。

角度加载在运行时产生的代码如下所示:

<script src="/js/plugins/plugin1/directive_plugin1.js"></script>
<script src="/js/plugins/plugin2/directive_plugin2.js"></script>

当我复制并粘贴代码中的两行并加载应用程序时,它可以正常工作。两个p元素都正确显示。

控制台日志向我显示:

directive_plugin.js:8 PRE!
directive_plugin.js:27 POST!
directive_plugin.js:8 PRE!
directive_plugin.js:27 POST!
2directive_plugin.js:15 LOADED!

所以我看到,问题是角度加载的异步函数。

在执行postLink函数之前,有没有办法在插件指令的preLink-function中等待loadScript-method?

1 个答案:

答案 0 :(得分:0)

我会提出这种黑客行为。

由于范围是在两个函数(pre和post)之间共享的,为什么不在其中放置load promise并等待它解决:

    compile: function(element, attrs, transclude) {
      return {
        pre: function preLink(scope, element, attrs, controller) {
          console.log('PRE!');

          var load_script = function() {
            var url = '/js/plugins/' + scope.plugin + '/directive_' + scope.plugin + '.js';

            // storing the promise in the scope
            scope.isLoadedPromise = angularLoad.loadScript(url);

            scope.isLoadedPromise.then(function() {
              console.log('LOADED!');
            }).catch(function() {
              console.log('NOT LOADED!');
            });
          };

          load_script();

        },
        post: function postLink(scope, element, attrs, controller) {
          console.log('POST!');

          // waiting for the loading to finish
          scope.isLoadedPromise.then(function() {
            console.log('YES IT IS LOADED!');
            var template = '<' + scope.plugin + ' />';
            var compiled = $compile(template)(scope);
            element.append(compiled);
          });
        }
      }
    }