Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can directives be lazy loaded in angularjs?

Tags:

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?

like image 582
ritcoder Avatar asked Sep 21 '12 21:09

ritcoder


People also ask

How is lazy loading implemented in AngularJS?

To enable lazy loading, we need to update the routing config to indicate that some modules will be loaded on route execution: import { ModuleWithProviders } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from '../home/home.

Which directive is used to implement lazy loading?

Use an ng-if directive in the HTML. By setting the defined variable to true after the directive is lazy loaded, the ng-if directive will use the $compile service to compile the lazy loaded directive.

How is lazy loading achieved in Angular?

Lazy loading is a technique in Angular that allows you to load JavaScript components asynchronously when a specific route is activated. It improves the speed of the application load time by splitting the application into several bundles. When the user navigates through the app, the bundles are loaded as required.

Does AngularJS support lazy loading?

AngularJS doesn't officially support lazy loading of components, services, etc. However, third party libraries such as ocLazyLoad provide this functionality. Lazy loading components is very simple with UI-Router and ocLazyLoad. The component is loaded and registered with ocLazyLoad, then the state is activated.


2 Answers

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/

like image 136
ify.io Avatar answered Sep 21 '22 23:09

ify.io


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'
    }
})
like image 40
Kel Avatar answered Sep 23 '22 23:09

Kel