Setting Modules in AngularJS app - javascript

I'm building an AngulrJS module that I intend to share, for free, with other developers via GitHub/bower. While my approach currently works, I'm concerned about name collisions. The way that I am currently setting up my module is like this:
var myModuleName = angular.module('myModuleName', []);
myModuleName.factory('$myFirstServiceName', function() {
...
});
myModuleName.factory('$mySecondServiceName', ['$q', function($q) {
...
}]);
myModuleName.factory('$myThirdServiceName', ['$q', function($q) {
...
}]);
My concern is that global 'myModuleName'. While this approach works, the name of my module isn't that "special". For that reason, I'm concerned it will collide with a developers existing stuff or cause other problems down the road.
Is there any way to more elegantly create a module where I don't have to worry about naming collisions?
Thank you!

You can use prefix in module name, which present project/library/author.
Like pasvaz.bindonce, ui.router etc...

Related

Share data, events across multiple angular modules

I'm developing some project where I use multiple modules
I have a kernel module and other modules that depend on kernel
angular.module('kernel', []);
...
angular.('process-manager', [ 'kernel', 'ui.router' ])
...
etc
I need to share some data across all modules and also broadcast some events across all modules.
For now in child modules I'm using $rootScope of kernel module that defined as a global in the $window object
.factory('$appScope', appScope)
...
appScope.$inject = ['$window', '$rootScope'];
function appScope($window, $rootScope: ng.IRootScopeService) {
if (angular.isDefined($window.superScope) === false) {
$window.superScope = $rootScope;
}
return $window.superScope;
}
Is there any better solution to do things like this?
EDIT
kernel module bootstraped through ng-app and other modules bootstraped through angular.bootstrap();
I see you're using .factory()... in your code, and even though I'm not sure exactly how you use it, you might be on the right path.
Use services. Services are singletons that are meant to hold data that can be shared through injection across your app and even across modules. As for broadcasting events, you can call $broadcast on your $rootScope, or you can $watch changes on your services' data in all modules.
There's a better answer to a similar question here.
Here's an example:
angular.module('firstModule', []).service('MyService', function () {
return {
some: 'data'
};
}).controller('someController', function ($scope, MyService) {
$scope.$watch(function () {
return MyService.some;
}, function (some) {
// This runs whenever the service's data changes
console.log(some.data, 'logged in first module');
}, true);
});
angular.module('secondModule', ['firstModule']) // <-- this makes the first module's service available for injection in the second module
.controller('someController', function ($scope, MyService) {
$scope.$watch(function () {
return MyService.some;
}, function (some) {
// This runs whenever the service's data changes
console.log(some.data, 'logged in second module');
}, true);
})
Cum grano salis
The service may be instantiated anew for every module, which may impede your ability to communicate across modules. Please fact-check me on this. In the meantime, local storage as suggested in Dennis Nerush's answer may be the better way to go. I have found https://github.com/gsklee/ngStorage to be a good complement for usage with Angular.
I suggest to use local storage to pass data between modules and keep the data consistent . Here is a great example
http://www.codediesel.com/javascript/sharing-messages-and-data-across-windows-using-localstorage/
Register an event listner in the required modules as '$scope.$on('changedVariable', function (event, args){//do your thing in listning module});'
And in the module from where you need to braodast:
$scope.$broadcast('changedVariable', { change: someValue});
And you are done, precisely! ;)

Define a constant that can be used in module/controller/etc. definition in angular

I would like to put module name, controller name etc. to string constants, so that I can easily change them if the need be (compared to fixing it in each and every file).
So I have this code:
angular
.module("app.admin.home")
.controller("HomeController", HomeController);
And I would like it have this (or similar):
angular
.module(moduleConstants.admin)
.controller(controllerConstants.adminHome, HomeController);
Is there a proper way to define this type of constants in Angular (ordinary injection does not work in this case). I guess I can create just global javascript constants, but maybe there is a better way of achieving this, some common way to define constants in angular. I have a strong C# background and it sounds stupid to me that constants need to be injected, they are not abstract code that can have different implementation, so it sounds wrong to inject it rather than just reference.
To avoid polluting the global name space, you could use a closure:
(function (moduleConstants, controllerConstants) {
angular
.module(moduleConstants.admin)
.controller(controllerConstants.adminHome, HomeController);
})({admin: "app.admin.home"},
{adminHome: "HomeController"});
According with the documentation, the right way of defining constants using angular js is using: Constants
This can be a simple implementation:
angular.module('config', [])
.constant('CONSTANT_YOU_NEED', {
name: 'test',
valueOfConst: '3.14'
});
But i guess you can't use this for modules or Controllers, but just passing to them

Prevent Third Party Factory Interfering with My App's Factory with the Same Name

I am using angular-bootstrap-colorpicker in my app and am having a weird issue. The colorpicker module has a factory named Slider. That's causing the colorpicker not to work because my app also has a factory called Slider. Refactoring every occurrence of this in the app isn't possible, and it seems like a sloppy workaround anyway. The error being thrown is
Uncaught TypeError: Slider.setSaturation is not a function
which I've concluded is because my app's factory has no method setSaturation and Angular is "confused". I don't really know enough about factories and how Angular organizes them, but it seems very odd that they would be available across modules like that. eg
angular.module('thomasApp', [])
...
.factory('Slider', ...
is affected by
angular.module('colorpicker.module', [])
...
.factory('Slider', ...
or vice versa.
Is there someway I can compartmentalize this colorpicker so that it does not interfere with my Slider factory?
Edit:
I agree with the linked answer that using a prefix as a namespace is a smart idea. However that would require an unrealistic amount of refactoring. I appreciate the answer below but it isn't fleshed out enough for me to be able to put into action.
1) Is this really the best possible solution (apart from prefixing from the project's beginning)? - If I make a change like this, will it be erased the next time I do a bower update, or someone pulls down my project and does a bower install?
2) Is there a better way? - If not, can the current answer be expanded and have explanations of what's happening added?
The problem that you have is general already known issue in Angular. #fracz was right, it's connected with Modules and namespace / name collision in AngularJS. The issue is that Angular has only one $injector instance per module instantiatation and all defined injectable objects go into it. By injectable objects I mean constants, values, services, controllers, directives.. This is bad in cases as this one because even if we modularize our application by defining multiple modules and dependencies between them at the end all the defined injectable objects end up in a same context/namespace/injector.
Angular makes this even worse by not using fail-fast technique in such cases and because the application continues working you may end up noticing the issue late which often can lead to expensive refactorings. And there is still a question how we can improve this, IMO failing-fast at least will help in avoiding this issue at it's beginning.
However in your case you are lucky that the library is really small and what you need is only the color picker directive. I have made a workaround example here by defining the color picker directive in your module while taking it's definition from the instantiated library module $injector. Like this you are free to change even it's name :).
Code example:
// NOTE: redefine the directive
app.directive('colorpicker', function () {
var injector = angular.injector(['ng', 'colorpicker.module']);
return injector.get('colorpickerDirective')[0];
});
For clarification purposes there is also an example that shows how Angular behaves when you define two service with the same name. The application successfully continues working with the last service definition.
I hope that this answer makes the things clear and successfully solves your problem. If you have more questions feel free to ask. Cheers!
Maybe something like this - create a fake module and wrap the existing provider under a new name. This will isolate the dependency.
var colorpicker = angular.module('my-colorpicker', ['colorpicker.module']);
colorpicker.factory('ColorPickerSlider', function() {
var injector = angular.injector(['colorpicker.module']);
var Slider = injector.get('Slider');
return Slider;
});
I know that this doesn't solve the fundamental problem of namespaces but it gives a way of hiding existing dependencies in a sandbox.
Yes, you can handle multiple factories with same name.
Here is the example,
var app = angular.module('firstApp', []);
app.factory('SameFact', [function () {
return { Name: "First" };
}]);
var app2 = angular.module('secondApp', ['firstApp']);
app2.factory('SameFact', [function () {
return { Name: "Second" };
}]);
app2.controller("testController", ["SameFact", "$scope", "$injector", function (SameFact, $scope, $injector) {
$scope.myName = {};
$scope.myName.Name1 = SameFact.Name; // This will be "Second", Last factory
var inj = angular.injector(['firstApp']);
$scope.my_inject = inj.get('SameFact').Name; // This will be "First", the first factory
}]);
Note
When you pass a factory as a dependency to a controller, it will register the last registered factory.
That is, in this example, I have registered two factory with same name SameFact but in different module.
When I refer the factory SameFact from my controller it will always point to the factory which is registered last, ie, factory in secondApp.
But, you can manually refer the factory which is in the module firstApp.
You can use angular.injector(['module_name']) to select injector of your required module and then use get() function inside it to get your factory or service.
Conclusion
So, you need declare a scope variable which point to your Slide factory of colorpicker module. And use this scope variable to get all required operations within colorpicker module. Find where the place where you are calling functions of colorpicker and replace it with this new variable.
Hope this will help you to survive your current situation.
Feel free to ask any doubts regarding this !!!
Place colorpicker.module preceeding your module that's containing Slider factory, at your module initialization :
angular.module('thomasApp', ['colorpicker.module','anotherModule'])
Here is an example on js fiddle

Angularjs simple meaning of module and Dependency

Hello I am New to angularjs
var app = angular.module('app', [])
app.controller('ProductController', ['$scope,$htttp', productController]);
Please correct me if i am wrong
This above two line is saying we have created the module name app
and we have controller called productController and have $scope, $http as a dependency.
App is starting point of our angularjs application.
Controller is basically for business logic.
what is the servieces ,Factory ?
what is Dependency Injection in simple words ?
I want to understand it more clearly as i study on angualar.js also. but unable to understand it clearly.
Please help to provide me some simple understanding on this
angular.module create module for application, and an application can one or more than one module. It's for modularity. so if you want to initialize core module. then you have to
var app=angular.module("core.module", [
/* Shared Modules */
"services",
"widgets",
"layout"])
So what it does it will initialize every module for application.so by using app object you can directly create common directive for all the modules and much more.
core.module is behaves like constructor and what you want to initialize will pass in "[]" during the call of constructor. it's up-to you.
You can call it as dependency.
In every module you can have different controllers but one thing always keep in mind whenever you add script file reference in html then do add child modules first then core otherwise it will give error. Module not defined.
Service and Factory pretty much they both are equivalent. Most important is to realize that both are singletons.
Factories are functions that return the object, while services are constructor functions of the object which are instantiated with the new keyword.
Services:
angular.module('app').service('abcservice', function() {
this.getdata= function() {};
});
Factory:
angular.module('app').factory('TestFactory', function() {
return {
someFunction: function() {}
};
});
when you want to use services and factory in our application then you have to pass it as argument/dependency in controller declaration.
app.controller(controllerId, ['$scope','abcservice','TestFactory']);
For much please refer Angular Tutorial

Angular JS, Add Global Array or Object to Module. Recommended or not?

When creating an Angular Module one could essentially add global arrays or objects to the module. Like so..
var myApp = angular.module('myApp', ['myModule']);
myApp.run(function()
{
});
angular.module('myModule', [])
.run(function()
{
// global to module
var thisModule = angular.module('myModule');
thisModule.globalArray = [];
thisModule.globalObject = {};
});
So here's the question(s). Would it be a bad idea to do something like this? Is there anything in the documentation that recommends not doing this? And if so, why would or wouldn't you recommend not doing this?
Demo:
http://jsfiddle.net/hrpvkmaj/8/
In general, Angular goes to great lengths to avoid global state. You can observe this in the dependency injection system that the framework is based on. To use a component, you must inject it as a parameter that is wired up behind the scenes. The framework also has a powerful scoping system that allows for nice and easy encapsulation. Relying on global variables works against these systems.
In particular, it would be a bad idea to do something exactly like your code example because it isn't how Angular was designed to be used. You shouldn't be adding your own properties to Angular's module object. At the very least, you should be injecting the $rootScope object and adding your global variables to that.
app.run(function($rootScope)
{
$rootScope.globalArray = [];
$rootScope.globalObject = {};
});
From the Angular documentation:
Every application has a single root scope. All other scopes are descendant scopes of the root scope.
If you went this route, you could inject $rootScope wherever you need to use those global values.
However, the Angular team discourages using $rootScope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
There is another way of defining global values in Angular that is even preferable over using $rootScope: defining a value provider.
A value provider is the simplest kind of provider. It defines a single value that can be injected throughout your app.
You can define one like this:
app.value("myValue", {
someProp: 'Hello World'
});
Then you can inject the value wherever you need it like this:
app.controller("myController", function ($scope, myValue) {
$scope.someValue = myValue.someProp;
});
Here's a fiddle using a value provider to inject a global value.
In the end, any answer you get, including this one, will include some level of subjectivity. There are many ways to handle global values, but Angular provides some really convenient ways of using the framework to accomplish this.

Categories

Resources