javascript 如何在 angularjs 中延迟加载指令?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12538665/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 16:28:27  来源:igfitidea点击:

How can directives be lazy loaded in angularjs?

javascriptangularjs

提问by ritcoder

I'm working with angularjs and I want to be able to load directives as and when they are needed instead of having all of them loaded at the start of the page. I'm trying to create directives for my most frequently used plugins.

我正在使用 angularjs,我希望能够在需要时加载指令,而不是在页面开头加载所有指令。我正在尝试为我最常用的插件创建指令。

In this way, one direct can use yepnopeto load all needed directives before finally compiling the html.

这样,yepnope在最终编译 html 之前,可以使用一个直接加载所有需要的指令。

If the directive is loaded at start of page with the others, everything works just fine. However if the 'child' directive is loaded later (within the 'parent'), it does not take effect. Below is the code for the pre field in the compile field of the 'parent' directive.

如果该指令在页面开始时与其他指令一起加载,则一切正常。但是,如果稍后加载“子”指令(在“父”中),则它不会生效。下面是 'parent' 指令的 compile 字段中 pre 字段的代码。

    ...
    var pre = function (scope, element, attrs) {
        element.html('Please wait. Loading...');
        ang.loadDirectives('caiDatePicker', function () {
            console.log('loaded');
            scope.data.raw = scope.rawData;
            var html = createObjUi(scope, scope.data, scope.defn);
            element.html(html); //data
            $compile(element.contents())(scope.$new());
            scope.$apply();
        });
    };
    return { restrict:'A', compile: {pre:pre,post:function(){...}};

ang.loadDirectivesloads the directive using yepnope. Part of the code for the 'child' directive is as follows:

ang.loadDirectives使用 yepnope 加载指令。'child' 指令的部分代码如下:

angular.module('mycomponents') //PS: I'm assuming this will fetch the already created module in the 'parent' directive
.directive('caiDatePicker', function ($parse) {
    return {
        scope: {},
        restrict: 'A',
        link: function (scope, element, attrs) {
            scope.$watch('this.$parent.editing', function (v) {
                scope.editing = v;
            });
            yepnope({
                test: $().datePicker,
                nope: [
                    '/content/plugins/datepicker/datepicker.js', //todo: use the loader
                    '/content/plugins/datepicker/datepicker.css'
                ],
                complete: function () {
                    if (scope.model && scope.model.value) {
                        var date = scope.model.value;
                        element.val(date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear());
                    }
                    element.datepicker({ weekStart: 1, format: 'dd/mm/yyyy' })
                        .on('changeDate', function (ev) {
                            scope.model.value = ev.date;
                            scope.$apply();
                        });
                }
            });
            attrs.$observe('path', function (v) {
                var fn = $parse(v);
                var model = fn(scope.$parent);
                scope.model = model;
            });
        }
    }
});

Is what I'm doing even possible in the first place?

我正在做的事情一开始就有可能吗?

If so, what am I doing wrong?

如果是这样,我做错了什么?

采纳答案by ritcoder

After searching for so long and not getting any answers, I ended up with the following

在搜索了这么长时间并没有得到任何答案之后,我最终得到了以下结果

  1. Create an angular app. This is also an angular module.
  2. You can add any directive to the module at any time using app.directive(name,function). These can be directives loaded asynchronously.
  3. You can bootstrap any element. When bootstrapping, specify the app in the list of modules to angular.
  1. 创建一个有角度的应用程序。这也是一个角度模块。
  2. 您可以随时使用 app.directive(name,function) 向模块添加任何指令。这些可以是异步加载的指令。
  3. 您可以引导任何元素。引导时,将模块列表中的应用程序指定为 angular。

The problem was that yepnope was not firing the complete function as I needed them to be. In the end, I build a small wrapper on top of yepnope that appears to guarantee that the complete function is fired.

问题是 yepnope 没有像我需要的那样触发完整的功能。最后,我在 yepnope 之上构建了一个小包装器,它似乎可以保证完整的函数被触发。

Final code looks something like:

最终代码如下所示:

var app3 = new Cai.AngApp('app3');
app3.loadControllers('app1.controller3', function () {
        app3.loadDirectives('jsonEditor', 'datePicker', function () {
            app3.bootstrap($('#d3'));
    });
});

回答by ify.io

If you want to register directives, after the application has been bootstrapped, you will have to use the $compileProvider instead of the module API. For example...

如果你想注册指令,在应用程序被引导后,你将不得不使用 $compileProvider 而不是模块 API。例如...

$compileProvider.directive('SomeLazyDirective', function()
{
    return {
        restrict: 'A',
        templateUrl: 'templates/some-lazy-directive.html'
    }
})

Then you can use the 'resolve' function when defining a route with the $routeProvider to load the lazy directive using your script loader. To do this, let the function return a promise that is resolved once your directive and other lazy dependencies have been loaded. AngularJS will wait for the promise to be resolved before rendering the route, thus ensuring that your directives will be ready before the view needs it. I have written a blog post detailing how to achieve lazy loading in AngularJS. It describes in more detail what I have stated here and it can be found at http://ify.io/lazy-loading-in-angularjs/

然后,您可以在使用 $routeProvider 定义路由时使用 'resolve' 函数来使用脚本加载器加载惰性指令。要做到这一点,让函数返回一个承诺,一旦你的指令和其他惰性依赖被加载,这个承诺就会得到解决。AngularJS 将在渲染路由之前等待 promise 得到解决,从而确保您的指令在视图需要之前准备就绪。我写了一篇博文详细介绍了如何在 AngularJS 中实现延迟加载。它更详细地描述了我在这里所说的内容,可以在http://ify.io/lazy-loading-in-angularjs/找到

回答by Kel

Here's what I did, using compile provider attached to the application, making it accessible from anywhere you have the actual module reference.

这就是我所做的,使用附加到应用程序的编译提供程序,使其可以从您拥有实际模块引用的任何地方访问。

var app = angular.module('app');
app.config(function ($compileProvider) {
    app.compileProvider = $compileProvider;
});

Then later on, after bootstrap you can lazily load a directive which gets compiled and linked:

然后,在引导程序之后,您可以延迟加载一个被编译和链接的指令:

app.compileProvider.directive('SomeLazyDirective', function()
{
    返回 {
        限制:'A',
        templateUrl: 'templates/some-lazy-directive.html'
    }
})

回答by Tejas

I am not sure how using a angularJS directive will be an appropriate answer

我不确定如何使用 angularJS 指令是一个合适的答案

I have done the following and it works flawlessly

我已经完成了以下操作并且它完美无缺

  • Use mustache list to decide list item template.(https://github.com/janl/mustache.js/)
  • On load of your application apis should load only 10 -50 records, depending on your content.
  • On scroll of list as soon as you are about to reach to end, fire next apis call form next 20 items and so on.
  • If your data is not changing, you can store it locally and repopulate.

  • keep fetching latest records and ad it locally.

  • 使用 mustache 列表来决定列表项模板。(https://github.com/janl/mustache.js/
  • 加载您的应用程序 api 时,应仅加载 10 -50 条记录,具体取决于您的内容。
  • 在您即将到达结束时立即滚动列表,触发下一个 apis 调用表单接下来的 20 个项目,依此类推。
  • 如果您的数据没有变化,您可以将其存储在本地并重新填充。

  • 不断获取最新记录并在本地进行广告。