1

I have a service that has an internal list of directive names (lets call it listService). In the spirit of loosely coupled applications I want other modules to be able to add their own directives to that list instead of statically defining it in the service module.

I understand that I can create a provider in order to configure a service like this:

app.provider("listService", ServiceProvider);

app.config(["listServiceProvider", function(listServiceProvider) {
    listServiceProvider.add("myDirective");
}]);

At the same time, I don't want all the modules that define directives to depend on the service. So what I would like to do is "if this service is used in this project: configure it; else: ignore".

Unfortunately, the above code produces a module error if listServiceProvider is not available. I also tried to use a decorator with the same result.

So how can I optionally configure a service in order to have a loosely coupled application?

tobib
  • 2,114
  • 4
  • 21
  • 35
  • 1
    What does it mean for a service to have "an internal list of directives"? Directives are registered on the module and Angular looks for them in the DOM during the compile phase. What would you hope to achieve by "adding them to the list", whatever that means? – New Dev Mar 09 '15 at 19:02
  • "internal list of directives" is a list of directive names. Could really by any list of strings. – tobib Mar 10 '15 at 11:19
  • 1
    If it's loosely coupled why would `listService` need to _know_ about `myDirective`? `myDirective` should be in a separate module. Then you'd add `listService` and the module `myDirective` is in as dependencies to different module, one of a controller for example. Services should be dependencies of controllers and directives (and possibly other services too), not the other way around. A service has nothing to do with _presentation_ (directives, controllers). – Sergiu Paraschiv Mar 10 '15 at 11:27
  • Let me ask another question: how are you planning to use `myDirective` in `listService`? You can't do `var d = new MyDirective()` in your service, you can only bind directives to HTML, so why would you need access to a directive's definition inside a service? – Sergiu Paraschiv Mar 10 '15 at 11:29
  • I have a reason for this, but I did not include it in order to not make the question even longer. It is also not really important *why* I do this. The question is *how* it can be done (or whether it can be done at all). If you need a reason, imagine I need it for sophisticated debugging or something. – tobib Mar 10 '15 at 11:42
  • @tobib, actually, the *why* is important to understand the broader picture and to avoid XY questions. If what you are asking for was possible, what would have happened – New Dev Mar 10 '15 at 13:21

2 Answers2

0

Like I mentioned in the comment, it is important to have a broader context for why you need to register directives (or their names).

In absence of a broader understanding, if, generally speaking, you need to conditionally check for existence of a service (or service provider, in config), you can use the $injector:

.config(function($injector){
   var listServiceProvider;
   if ($injector.has("listServiceProvider")) {
     listServiceProvider = $injector.get("listServiceProvider");
   }

   if (listServiceProvider){
     listServiceProvider.add("myDirective");
   }
});
New Dev
  • 48,427
  • 12
  • 87
  • 129
  • That's exactly what I was looking for. Just one additional question: Will there be issues if the modules are loaded the wrong way around? – tobib Mar 10 '15 at 17:49
  • @tobib, I don't think so. Angular first runs all the `.factory`, `.service`, etc... functions, then starts the `.config` functions – New Dev Mar 10 '15 at 18:46
0

If I understand correctly; you want a service that tracks which of your directives have been added into the Angular app, and for the directives and the service to be decoupled from each other so they can be included on demand.

I don't think the module pattern will do this for you, since the services and directives are injected at load time. Optional dependency injection is not possible.

However, you could fire an event from your directive and pick it up in your service, removing the need for dependency injection altogether.

myDirective

.run(['$rootScope', 'LIST_SERVICE_EVENT', 
          function($rootScope, LIST_SERVICE_EVENT) {
    $rootScope.$emit(LIST_SERVICE_EVENT, 'myDirective');
}]);

listService

.run(['listService', '$rootScope', 'LIST_SERVICE_EVENT', 
        function(listService, $rootScope, LIST_SERVICE_EVENT) {
    $rootScope.$on(LIST_SERVICE_EVENT, function(ev, name) {
        listService.add(name);
    });
}]);

Fiddle: http://jsfiddle.net/bdpxhLg3/4/.

seanhodges
  • 17,426
  • 15
  • 71
  • 93