20

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.

In this way, one direct can use yepnope to load all needed directives before finally compiling the 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.

    ...
    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.loadDirectives loads the directive using yepnope. Part of the code for the 'child' directive is as follows:

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?

4 Answers 4

17

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.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/

Sign up to request clarification or add additional context in comments.

1 Comment

Could you please provide the $routeProvider resolve function explicity? Thanks
13

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()
{
    return {
        restrict: 'A',
        templateUrl: 'templates/some-lazy-directive.html'
    }
})

2 Comments

This worked for me, a helpful post was also here: codeproject.com/Articles/838402/…
how to call this directive to be displayed in the view?
2

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.

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.

Final code looks something like:

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

2 Comments

interesting approach using bootstrap on the child. but this means, multiple bootstraps. would it work? also, could u explain what you did in the ang.loadDirectives?
to fix your yepnope problem you can follow first example of this comment: github.com/SlexAxton/yepnope.js/issues/91#issuecomment-14526165
-1

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

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.