49

Consider the following jfiddle http://jsfiddle.net/bchapman26/9uUBU/29/

//angular.js example for factory vs service
var app = angular.module('myApp', ['module1', 'module2']);

var service1module = angular.module('module1', []);

service1module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service1 says \"Hello " + text + "\"";
        },
        sayGoodbye: function(text) {
            return "Service1 says \"Goodbye " + text + "\"";
        }
    };
});

var service2module = angular.module('module2', []);

service2module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service2 says \"Hello " + text + "\"";
        },
        sayGoodbye: function(text) {
            return "Service2 says \"Goodbye " + text + "\"";
        }
    };
});

function HelloCtrl($scope, myService) {
    $scope.fromService1 = myService.sayHello("World");
}

function GoodbyeCtrl($scope, myService) {
    $scope.fromService2 = myService.sayGoodbye("World");
}​

I have 2 modules (module1 and module2). Both module1 and module2 define a service called myService. This appears to create a name clash on myService within Angular when both modules are imported into myApp. It appears AngularJs just uses the second service definition without warning you of the possible issue.

Very large projects (or just reusing modules in general) would have a risk of names clashing, which could be difficult to debug.

Is there a way to prefix names with the module name so that name clashes don't happen?

3
  • An update: I have found a possible workaround by applying a naming convention to the service names passed into the di system. See jsfiddle.net/bchapman26/9uUBU/32 However, my main question still stands: Is there a native way to avoid the name clash shown above? Commented Nov 15, 2012 at 22:02
  • 1
    This seems to be an problem right now, especially when you consider the potential use of 3rd party components. I have an issue raised here. Commented Apr 30, 2013 at 16:19
  • I would think this is not a problem (actually a feature and by design) since it is useful for testing and overriding behavior. Namespacing or using a naming convention is the way to go. Commented May 30, 2013 at 14:44

4 Answers 4

63

As of today, AngularJS modules do not provide any sort of namespacing that would prevent collisions between objects in different modules. The reason is that an AngularJS app has a single injector that holds names for all objects without respect to module names.

The AngularJS Developer Guide says:

To manage the responsibility of dependency creation, each Angular application has an injector. The injector is a service locator that is responsible for construction and lookup of dependencies.

As you've mentioned, nasty bugs can result when injecting modules into your main/app module. When collisions happen they are silent and the winner is determined by whichever was the last module injected.

So no, there's not a built in way of avoiding these collisions. Maybe this will happen in the future. For large apps where this problem becomes more likely, you're right that naming conventions are your best tool. Consider whether objects belonging to a module or function area might use a short prefix.

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

2 Comments

Jim, that sums up my question well. Thanks for the response.
As mentioned in other posts, a "hacky" solution exists in the wild by prefixing the name of the service with the module that originated it, e.g. module2.MyService. The service names are just string keys, after all. The dependent module -- myApp from the example above -- would then define how MyService works in practice. Sub-optimal but usable.
2

You can avoid this situation by using a convention to name your modules so that they always unique.

One approach is to look at how other languages do it. For example in Java the “full name” of the class is based on the name of the file and the folder it’s in. For example if you had a Java file called Bitmap.java in the folder MyArtStuff, the full name of the class would be MyArtStuff.Bitmap

Turns out AngularJS allows you to have dots (.) as part of your module name so you could essentially use the name convention.

For example if a developer create a module called “ModuleA” in the script “MainPage\Module1.js” they should name their module “MainPage.Module1.ModuleA”. Because each path and filename is unique in your app then your module name will be unique.

You would just have to get your developers to follow this convention.

Note as Rockallite points out this will not help with services, controllers, etc having the same name in multiple modules. But you can use a similiar approach to result that and prefix the names of those elements as well.

Ideally AngularJS would have namespaces and in the future it might. Until then the best we can do is do what developers have been doings for over 40 years before namespaces were invented and prefix our elements best we can.

10 Comments

it's not about the module name, but about the service/filter/controller etc. - and in those names I really wouldn't use the dot notation (especially not with ng-annotate)...
It's not about module names conflict. It's about controller/filter/service names conflict in different modules (especially from 3rd parties). Since you reference a controller/filter/service with their name directly and without any namespace, whatever you do with module names doesn't help at all.
@Rockallite Preventing conflict just means the names have to be unique. I'ts not a new problem. It exists in all languages, newer languages use namespaces with dot notation. Java encourages you to use a reverse domain name to make your namespace unique. Libraries like jQuery and Underscore try to use obscure characters. Languages like C which didn't have namespaces used function name prefixes. For example ObjectiveC core library functions use the "NS" prefix to differentiate themselves. The OpenGL library I believe uses the "gl" prefix. You would just have to apply the same principals.
@Rockallite "This is a problem specific to AngularJS"? The "problem" exists in C and ObjectiveC which also have no namespaces. All which I mentioned in my previous response. And the solution is just as "error-prone" and "hard to scale" there. C is still being used today 43 years later. They managed. Namespaces would be ideal, but this problem is decades proven to be manageable.
... manual namespacing is tedious, error prone, and reduces portability. Reference: github.com/angular/angular.js/issues/2767
|
0

Unfortunately, there is no namespacing in AngularJS. One solution is to use a prefix (another solution may be this!). See the following example:

// root app
const rootApp = angular.module('root-app', ['app1', 'app2']);

// app 1
const app1 = angular.module('app1', []);
app1.controller('app1.main', function($scope) {
  $scope.msg = 'App1';
});

// app2
const app2 = angular.module('app2', []);
app1.controller('app2.main', function($scope) {
  $scope.msg = 'App2';
})
<!-- [email protected] -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.min.js"></script>

<!-- root app -->
<div ng-app="root-app">

  <!-- app 1 -->
  <div ng-controller="app1.main">
    {{msg}}
  </div>

  <!-- app 2 -->
  <div ng-controller="app2.main">
    {{msg}}
  </div>

</div>

Comments

-8

Define your controllers on the module you want the service to be from.

service2Module.controller("ServiceTwoCtrl", function(myService, $scope) {});

5 Comments

After using this advice, it appears that this does nothing to resolve the name conflict on the service.
Hmm.. why do you need two modules named the same?
@AndyJoslin - it is the other way round, How do you detect that you have a name collision?
@AndrewJoslin consider an application that you don't control where all modules are developed. Some plugin type architecture where multiple teams build components.
@AndrewJoslin If your app depends on 3rd-party modules, how do you avoid controller/filter/service name conflicts between your own modules and their modules (also between all those 3rd-party modules)?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.