I know it is a bad practice to use this syntax to register controllers in angular:
var app = angular.module('app',[]);
app.controller('mainController',function(){
// code
});
because of global variables issue so it's recommended to use the getter syntax in angular:
angular.module('app',[]);
angular.module('app').controller('mainController',function(){
//code
};
but every time I have to write the name of my application to get it so I think in another solution to do that:
'use strict';
const _APP_ = (function(){
var appName = 'app';
var result = {
init: function(dependencies){
document.body.setAttribute('ng-app',appName);
if(!dependencies || !Array.isArray(dependencies)){
dependencies = [];
}
angular.module(appName,dependencies);
},
$: function(){
return angular.module(appName);
}
};
return Object.freeze(result);
})();
now app.js file just has:
'use strict';
(function(){
_APP_.init();
})();
and to create a new controller:
'use strict';
(function(){
_APP_.$().controller('mainController',ctrl);
function ctrl(){
// code
}
})();
I'm always interested in the best practices so I need your feedback about my solution or if there is a better.
Related
I'm new to Jasmine tests with Karma. I'm getting following error while executing the tests.
Here are my files.
message.service.js // Service file
(function() {
'use strict';
angular.module("app").factory('MessageService', [MessageService]);
function MessageService() {
var service = {};
//var gui = require('nw.gui');
service.alert = function() {
//gui.Window.open('/');
//$window.open('/message');
return 'hello';
};
return service;
};
})(); // IIFE
message.service.spec.js // Service test file
describe('Message Service', function() {
var messageService;
beforeEach(angular.mock.module('app'));
beforeEach(inject(function(_MessageService_) {
messageService = _MessageService_;
}));
it('should exist', function() {
expect(messageService).toBeDefined();
});
it('should return hello', function() {
expect(messageService.alert()).toEqual('hello');
});
});
app.module.js // Main app file
(function() {
'use strict';
angular.module("app", ['ngRoute', 'ui.bootstrap', 'ui.router']);
/*angular.module("app").run(['$rootScope', 'StartupService', function($rootScope, startupService){
startupService.init($rootScope);
}]);*/
})(); // IIFE
If I change following line in message.service.js
angular.module("app").factory('MessageService', [MessageService]);
to
angular.module("app",[]).factory('MessageService', [MessageService]);
Then tests work fine but application will not work(due to re initiation of module I guess). How can I make my app to work for both tests and normal app execution? Appreciate your help
It was my mistake. I haven't included the js file in Karma config related to the ui.bootstrap module. After that it worked fine.
For anyone who gets such error check whether you have included all the dependency files on Karma config, what you have defined in main app.
ex: assume your main app file is like below.
angular.module("app", ['ngRoute', 'ui.bootstrap', 'ui.router']);
Then your Karma config file should look like this
files: [
'assets/lib/angular/angular.min.js',
'assets/lib/angular-ui-router/angular-ui-router.min.js',
'assets/lib/angular-bootstrap/ui-bootstrap-tpls-1.3.2.min.js'
],
Thanks for your help.
I have two modules and factories in both, and I need to implement factory from the first module into another module.
angular.module('APIs', [])
.value ("myValue" , "12345")
.factory('apiUrl',['config','url',apiUrl])
function apiUrl(config,url){
}
angular.module('users.service', ['APIs'])
.factory('userService',['myValue',userService])
function userService(apiUrl,myValue){
//login function
function login(){
console.log('myValue',myValue)
console.log('loginUrl',apiUrl)
}
return {
login:login
}
}
notice: no problem when I inject myValue, but the problem in APIs Factory
and my log:
Error: [$injector:unpr] http://errors.angularjs.org/1.5.0/$injector/unpr?p0=urlProvider%20%3C-%20url%20%3C-%20apiUrl%20%3C-%20userService
at Error (native)
and sorry for my English.
I would do it like this:
If you create factory use angular.module('app').factory(). If you create service use angular.module('app').service()
Always try to have same module name. It is easier later, when you have big application, because of dependency injection.
Try to keep files separately, and concatenate it later, for example using gulp gulp-concat
Try to keep all you configuration in app.js file and, when you concatenating file, remember, this file should be on top.
I would keep values and constants in app.js file or would create new file like factory or service and include it, same as I injected it below.
app.js
(function () {
'use strict';
var app = angular.module('app', [
// other module
]);
app.value('myValue', '12345');
app.constant('myConst', 'some_constant');
app.config(['$interpolateProvider', function ($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);
}());
factory.js
(function () {
'use strict';
angular
.module('app')
.factory('apiUrlFactory', apiUrlFactory);
apiUrlFactory.$inject = [];
function apiUrlFactory() {
var self = this;
self.url = 'some_url';
return self;
}
}());
service.js
(function () {
'use strict';
angular
.module('app')
.service('userService', userService);
userService.$inject = ['apiUrlFactory', 'myValue'];
function userService(apiUrlFactory, myValue) {
var self = this;
self.login = function () {
console.log('myValue', myValue);
console.log('loginUrl', apiUrlFactory.url);
};
return self;
}
}());
If you have more questions, do not hesitate to contact with me. Also try angular style guide https://github.com/johnpapa/angular-styleguide It will help you a lot.
I'm trying to inject the factory Application into the ApplicationService factory. Both are defined in the same module.
Application factory (application.model.js)
(function(Object, coreModule) {
'use strict';
// the factory to expose that allows the creation of application instances
var ApplicationFactory = function() {
console.log("Application factory!");
return {foo: 'bar'};
}
coreModule.factory('Application', [ApplicationFactory]);
})(Object, angular.module('core'));
ApplicationService factory (application.service.js)
(function(coreModule) {
'use strict';
var ApplicationService = function(Application) {
var api = {
shout = function() {console.log(Application);}
};
return api;
}
ApplicationService.$inject = ['Application'];
coreModule.factory('ApplicationService', [ApplicationService]);
})(angular.module('core'));
Then I'm injecting ApplicationService factory into a controller and calling the method shout. I get undefined when in the console's log, Application is always undefined. If in a controller I innject Application it works. So i know both factories are working standalone.
Both files are being imported in my index.html.
I've spent hours looking for the issue but I can't find it. What am I doing wrong?
Please see working demo below.
You've got 2 options.
a) Remove square brackets here:
coreModule.factory('ApplicationService', ApplicationService)
b) Add injected Application as first element before ApplicationService:
coreModule.factory('ApplicationService', ['Application', ApplicationService])
var app = angular.module('core', []);
app.controller('firstCtrl', function($scope, ApplicationService) {
ApplicationService.shout();
});
(function(Object, coreModule) {
'use strict';
// the factory to expose that allows the creation of application instances
var ApplicationFactory = function() {
console.log("Application factory!");
return {
foo: 'bar'
};
};
coreModule.factory('Application', [ApplicationFactory]);
})(Object, angular.module('core'));
(function(coreModule) {
'use strict';
var ApplicationService = function(Application) {
var api = {
shout: function() {
console.log(Application);
}
};
return api;
};
ApplicationService.$inject = ['Application'];
coreModule.factory('ApplicationService', ApplicationService);
})(angular.module('core'));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="core">
<div ng-controller="firstCtrl">
</div>
</body>
for a variety of reasons, my company decided to follow this model for our various objects in Angular
(function(angular) {
'use strict';
function Principal($q, $http, $cookies) {
this.$q = $q;
this.$http = $http;
this.$cookies = $cookies;
}
Principal.prototype.isIdentityResolved = function() {
return angular.isDefined(this._identity);
};
}());
The module is being defined by a master one level above this.
var Principal = require('./Principal');
var AuthServ = require('./AuthorizationService');
var SecAng = angular.module('SecAng', []);
SecAng.service('principal', Principal);
SecAng.service('authorization', AuthServ);
module.exports = SecAng;
and then browsify resolves that to a name and its included in my module in my app.js
My problem is the line return angular.isDefined(this._identity);. I keep getting errors saying that angular is undefined. Any ideas why this would be happening?
Pass angular into your self-invoking function:
(function(angular) {
'use strict';
...
}(angular));
I wonder if someone could assist me in figuring out how to wire up my new angular service module.
I keep getting the same Javascript error :
Error: [$injector] Unknown provider: gridHierarchyServiceProvider" <-- gridHierarchyService
My new services/gridHierarchyService.js file :
(function () {
'use strict';
var controllerId = 'gridHierarchyService';
angular.module('app').controller(controllerId, ['common', gridHierarchyService]);
function gridHierarchyService(common) {
var service = {
getDataSourceSchema: getDataSourceSchema
};
return service;
function getDataSourceSchema() {
var i = 1;
// TESTING...
}
}
});
and in my dashboard.js file, I attempt to inject this new service module:
(function () {
'use strict';
var controllerId = 'dashboard';
angular.module('app').controller(controllerId, ['common', 'datacontext', 'gridHierarchyService', dashboard]);
function dashboard(common, datacontext, gridHierarchyService) {
...
}
and of course I'm loading it up in my index.html:
<!-- app Services -->
<script src="app/services/datacontext.js"></script>
<script src="app/services/gridHierarchyService.js"></script>
<script src="app/services/directives.js"></script>
However, I'm clearing missing something here.
I also tried mimicking my datacontext.js service, using the .factory() call:
angular.module('app').factory(serviceI,d [...]);
but it doesn't work.
========== UPDATE !!! ============
I'm happy to say it was a very easy fix, and thanks to the community here !
WORKING SERVICE :
(function () {
'use strict';
var serviceId = 'gridHierarchyService';
angular.module('app').factory(serviceId, ['common', gridHierarchyService]);
function gridHierarchyService(common) {
var service = {
getDataSourceSchema: getDataSourceSchema
};
return service;
function getDataSourceSchema() {
var i = 1;
i = 2;
}
}
})();
I see that you are defining your controllers inside anonymous functions but that you never execute those anonymous functions.
Your code:
(function(){
//declarations
alert('You will never see me because I do not execute');
});
Fixed code (notice the parens at the end):
(function(){
//declarations
alert('You can see me!');
})();
See the above code run here: http://jsfiddle.net/wilsonjonash/cDBc7/
See more about the module pattern here:
http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
Also, you were right to try factory for a service. To make your gridHierarchyService into a service (rather than a controller), just change controller to factory or service in
var controllerId = 'gridHierarchyService';
angular.module('app').controller(controllerId, ['common', gridHierarchyService]);
Hope that does the trick for you.