Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add directive to module after bootstrap and applying on dynamic content

Tags:

angularjs

I have a web page with a module defined (myModule) where I'm boostraping angularjs using

angular.bootstrap(element,[myModule.name]);

After the click of a button, I add dynamic html and compile using

$compile('<my-element data="data"></my-element>',$scope.$new());

The directive is added using

myModule.directive('myElement',function(){});

The problem is when I add the directive before calling bootstrap, $compile ends up correctly processing my directive. However, if the directive is added after calling bootstrap, $compile does not do anything to my html. It just adds the class ng-scope to it and the directive/tag is not processed.

In my case, not all the directives will be loaded before bootstrap is called. In the case where I load directives after calling bootstrap, how do I get to use it within the page?

Thanks.

Edit: Just to clarify. All directives are loaded dynamically. Those I load before bootstrapping work fine. Those I load after bootstrapping fails. When I swap the directives loaded, I can the same result so it is not the directives but appears to be that after bootstrapping, newly added directives does not seem to take effect.

like image 545
ritcoder Avatar asked Nov 22 '12 00:11

ritcoder


2 Answers

The thing with registering lazy controller or directives is that you have to get hold of $controllerProvider and $compileProvider respectively.

It can be done only during configuration phase so you have to keep the references until you load the controllers/directives.

Lately I was working on lazy loading of the controller, today I've added support for directives, check out my code here:

https://github.com/matys84pl/angularjs-requirejs-lazy-controllers/

particularly this module lazy-directives.js

NOTE: I use RequireJS in my project, however applying my solution to yepnope should be quite easy.

like image 134
matys84pl Avatar answered Nov 01 '22 05:11

matys84pl


This Fiddle show-cases how to dynamically load/register and use:

  • Angular controllers (using $controllerProvider)
  • Angular directives (using $compileProvider)
  • Angular partial templates (using $templateCache)

Code: Setup

// Initialize app.lazyController and app.lazyDirective.
// We will later use them to create controller and directives dynamically.
var app = angular.module('app', []);
app.config(function($controllerProvider, $compileProvider) {
        // see page 12 of:
        //    http://www.slideshare.net/nirkaufman/angularjs-lazy-loading-techniques
        app.lazyController = $controllerProvider.register;

        // see: http://jsfiddle.net/8Bf8m/33/
        app.lazyDirective = $compileProvider.directive;
    });

// set of partials
var partials = [];

// store scope & templateCache, so we can dynamically insert partials
var scope, templateCache;

// define main controller
function MainCtrl($scope, $templateCache) {
    $scope.partials = partials;

    scope = $scope;
    templateCache = $templateCache;
}

Code: Example

var maxPartials = 3;
var i = 0;
var timer = setInterval(function() {
    var i = partials.length;

    app.lazyDirective('clickMe', function () { return {
        link : function (scope, element) {
            element.bind('click', function () {
                alert('Clicked: ' + element.text());
            });
        },
    };});

    // define controller
    var ctrlName = 'partial' + i + 'Ctrl';
    app.lazyController(ctrlName, function($scope) {
        $scope.text = 'hi ' + i;
    });

    // add partial template that I have available in string form
    var newPartial = {
        name: 'template' + i,
        content: '<div ng-controller="' + ctrlName + '" class="a' + i + '">' +
        '<input type="text" ng-model="text"></input>'+
        '{{text}} <br/>' + 
        '<button click-me="">Click Me!</button>' +
        '</div> <br/> <br/>'
    };
    partials[i] = newPartial;

    // add template and notify angular of the content change
    templateCache.put(partials[i].name, partials[i].content);
    scope.$apply();

    // stop timer
    if (partials.length >= maxPartials)  clearInterval(timer);
}, 1000);
like image 21
Domi Avatar answered Nov 01 '22 05:11

Domi