3

I'm trying to create directives on the fly, actually I achived that, but seams pretty hacky.

This was my first approach:

function create(myDir) {
   angular.module("app").directive(myDir.name, function() {
   return {
     template:myDir.template
   };
  });
}

It didn't work because you can't register directives after application started.

based on this post: http://weblogs.thinktecture.com/pawel/2014/07/angularjs-dynamic-directives.html

I found out that I could use compileProvider to do the work, but since compileProvider isn't available outside config block, you need to put it out, so I did:

var provider = {};
angular.module("app",[]);        

angular.module('app')
.config(function ($compileProvider) {
    //It feels hacky to me too.
    angular.copy($compileProvider, provider);
 });
....

function create(myDir) {
    provider.directive.apply(null, [myDir.name, function () { 
        return { template: myDir.template } }]);
    render(myDir); //This render a new instance of my new directive
}

Surprisingly it worked. But I can't feel like being hacking the compileProvider, because I'm using it not in the way it was suppose to be, I would really like to know if is it possible to use the compileProvider properly after the application has started.

Manjar
  • 3,159
  • 32
  • 44
  • Create your own provider and inject $compileProvider into it, then have that new provider publish a service that uses it. – Reactgular Sep 30 '15 at 16:08
  • 1
    You can also check [this project](https://github.com/ex-machine/ng-lazy-module) which does exactly what you want. – Estus Flask Sep 30 '15 at 16:25
  • Both comments are good, but I'm still worry about the fact of taking compileProvider out of its scope – Manjar Oct 01 '15 at 07:31

1 Answers1

3

There is a list of dependencies that can be injected to config blocks (these are built-in $provide, $injector and all service providers) and a list of dependencies that can be injected to everywhere else (service instances and good old $injector). As you can see all that constant does is adding the dependency to both lists.

A common recipe for using providers outside config is

app.config(function ($provide, $compileProvider) {
  $provide.constant('$compileProvider', $compileProvider);
});
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • This solution can really fits, and its pretty elegant, but I'm still worried about the use of a provider out of its scope, as you said , there are "dependencies" which can only be injected in config blocks, if they did that there should be some reason for that, I felt like I'm using it to fit my solution, but not sure if its the good way – Manjar Oct 01 '15 at 07:34
  • 1
    There is a reason. It requires to have a clue what's going on in particular provider. Providers are used as footprints for creating service instances, some of the changes being made to providers won't affect instances and some will. Regarding $compileProvider, new services (and directives are services, too) can be safely registered at any moment. It may require to re-compile these directives in document, if there are any (they weren't initially compiled because they haven't existed). But it is perfectly ok to do with e.g. router views. – Estus Flask Oct 01 '15 at 12:00