I have made a little library of code for angular js. I have created a .config method in my library's main module that depends on my moduleConfigProvider. I expect the consumer of my library to call .configure on my config provider during the app.config stage (asap on app start).
The problem is that my .config in my module seems to run BEFORE the app.config of the main app module. How can I work around this problem?
e.g. This is how i'm consuming the config. I need to consume it during the .config stage because I need to configure things like $httpProvider.
// this module provides initial configuration data for module
angular.module('mymodule')
.config(['$httpProvider', 'someOptionsProvider', 'myConfigProvider',
function ($httpProvider, someOptionsProvider, myConfigProvider) {
console.log("Consuming config now: ", myConfigProvider.config);
}])
Here is the config provider:
angular.module('mymodule.config')
.provider('myConfig', function() {
var _this = this;
_this.configure = configureMethod;
_this.config = {};
function configureMethod(configData) {
_this.config = configData;
console.log("Config set to:", configData);
};
this.$get = function() {
return _this;
};
});
And finally here is my app.config:
angular.module('app')
.config(['myConfigProvider', function(myConfigProvider) {
console.log("Running App config:", myConfigProvider);
var config = { a: 1 };
console.log("Config ready to send:", config);
myConfigProvider.configure(config);
}])
;
Okay, it is simple, just use other providers in your provider function as dependencies.
Check the following snippet
angular.module('mymodule', [])
.provider('myConfig', [
'$httpProvider',
function($httpProvider) {
var _this = this;
_this.configure = configureMethod;
_this.config = {};
function configureMethod(configData) {
//Do here anything with the $httpProvider
_this.config = configData;
console.log("Config set to:", configData);
console.log('Configuring $httpProvider')
};
this.$get = function() {
return _this;
};
}
])
angular.module('app', ['mymodule'])
.config(['myConfigProvider', function(myConfigProvider) {
console.log("Running App config:");
var config = {
a: 1
};
console.log("Config ready to send:", config);
myConfigProvider.configure(config);
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
</div>
Related
I have an Angular service like this:
angular.module('MyModule')
.factory('SharedData', function( ){
return {
session_id: undefined,
getSessionId: function () {
return this.session_id;
},
setSessionId: function (new_id) {
this.session_id = new_id;
},
};
}).
controller( 'MyController', ['SharedData', function( SharedData ){
console.log( "Retrieved session id = " + SharedData.getSessionId());
// getting undefined here!
}]);
I called the service at an earlier time in another module like this:
angular.module( 'bootstrapper' )
factory("AnotherService", function(){
var injector = angular.injector(['MyModule', 'ng']),
shared_data = injector.get('SharedData');
shared_data.setSessionId( getUrlParameter('SESSIONID'));
...
});
The console output result is undefined.
I think the SharedData in 'MyController' and the SharedData in 'AnotherService' are not the same object. However, people are all saying that Angular services are singletons. Are they real singletons?
More details about my modules:
I used module 'bootstrapper' to manually bootstrap the other module 'MyModule':
angular.module( 'bootstrapper' )
.run(function () {
angular.bootstrap(document, ['MyModule']);
});
angular.factory are not constructors, it seems to me that using angular.service instead would solve your problem,
You can provide constants to the app at bootstrap time as a module dependency.
angular.module( 'bootstrapper' )
.config(function () {
var sessionIdProvider = function ($provide) {
$provide.constant("SESSIONID", getUrlParameter('SESSIONID'));
};
angular.bootstrap(document, ['MyModule', sessionIDProvider]);
});
For more information see the AngularJS $provide Service API Reference -- constant.
Update
You can also skip the bootstrap app and use a config block in the MyModule app.
angular.module( 'MyModule' )
.config(function ($provide) {
$provide.constant("SESSIONID", getUrlParameter('SESSIONID'));
});
For more information see the AngularJS angular.module API Reference,
After thinking a bit, I feel that you have chosen not very good approach. It's better to define bootstrapper application and make it initialize sharedData service, then share it with other dependent modules. Note, not applications like in your case, but dependent modules. This would be much simpler and cleaner.
Here is an example setup that would allow nice "modularization":
/**
* Bootstrapper application.
*/
angular.module('bootstrapper', ['dashboard'])
.factory('sharedData', function() {
return {
sessionId: undefined,
setSessionId: function(value) {
this.sessionId = value;
},
getSessionId: function() {
return this.sessionId;
}
}
})
.controller('BootController', function(sharedData) {
this.name = 'Bootstrapper app';
sharedData.setSessionId('34sd-3sdf345g-23a2421b');
});
/**
* Apllication kicked off by main bootstrapper.
*/
angular.module('dashboard', [])
.directive('dashboardModule', function() {
return {
controller: 'DashboardController as dashboard',
template:
"<div>" +
" {{ dashboard.name }} sessionId: {{ dashboard.sharedData.sessionId }}" +
"</div>"
};
})
.controller('DashboardController', function(sharedData) {
this.name = 'Dashboard';
this.sharedData = sharedData;
});
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<body ng-app="bootstrapper" ng-controller="BootController as boot">
<h3>{{ boot.name }}</h3>
<dashboard-module name="dashboard"></dashboard-module>
<!-- <some-other-module></some-other-module> -->
</body>
I'm having trouble getting my tests to run due to dependencies not beeing injected correctly.
The error I'm getting is defined in the title. I've included the actual test code, the app.js & index.html file from my solution.
The problem lies with the deferred bootstrap which I'm not fimiliar with as it was included by one of my colleagues. If I remove the "app.config(function (STARTUP_CONFIG..." from the app.js file then the test runs fine
How can I correctly inject the STARTUP_CONFIG in my test?
test code
..
..
describe("test description...", function () {
var app;
var mockupDataFactory;
beforeEach(module('Konstrukt'));
beforeEach(inject(function (STARTUP_CONFIG,BUDGETS,APPLICATIONS) {
//failed attempt to inject STARTUP_CONFIG
}));
beforeEach(function () {
app = angular.module("Konstrukt");
});
beforeEach(function () {
mockupDataFactory = konstruktMockupData.getInstance();
});
it('should be accessible in app module', function () {
expect(app.pivotTableService).toNotBe(null); //this test runs fine
});
it('test decr...', inject(function ( pivotTableService) {
... //Fails here
..
..
app.js
..
..
angular.module('Konstrukt', ['ngGrid', 'ngSanitize', 'ngRoute','pasvaz.bindonce', 'ngAnimate', 'nvd3ChartDirectives', 'ui.select', 'ngProgress', 'ui.grid', 'ui.grid.edit','ui.grid.selection', 'ui.grid.cellNav', 'ui.grid.pinning', 'ui.grid.resizeColumns']);
var app = angular.module('Konstrukt');
app.config(function (STARTUP_CONFIG, BUDGETS, APPLICATIONS) {
var STARTUP_CONFIG = STARTUP_CONFIG;
var BUDGETS = BUDGETS;
var APPLICATIONS = APPLICATIONS;
});
..
..
index.html
..
..
<script>
setTimeout(function(){
window.deferredBootstrapper.bootstrap({
element: window.document.body,
module: 'Konstrukt',
resolve: {
STARTUP_CONFIG: ['$http', function ($http) {
return $http.get('/scripts/_JSON/activeBudgets.JSON');
}],
BUDGETS: ['$http', function ($http) {
return $http.get('/scripts/_JSON/activeBudgets.JSON');
}],
APPLICATIONS: ['$http', function ($http) {
return $http.get('/scripts/_JSON/applications.JSON');
}]
}
})
} , 1500);
</script>
The deferredBootstrapper will not run in your unit tests, which means the constants it normally adds to your module won't be available.
You can add a global beforeEach that provides mocked versions of them:
beforeEach(function () {
module(function ($provide) {
$provide.constant('STARTUP_CONFIG', { something: 'something' });
$provide.constant('BUDGETS', { something: 'something' });
$provide.constant('APPLICATIONS', { something: 'something' });
});
});
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>
I have a code of
var viewerAngular = angular.module('ngAppDemo', ['restangular','btford.socket-io'])
.config(function(RestangularProvider) {
$.get('../config/config.xml',
function(data) {
$(data).find('contentserver').each(function() {
serverDetails.contentserver = assignServerDetails($(this));
var restprovider = RestangularProvider;
restprovider.setBaseUrl("http://"+serverDetails.contentserver.ip+":"+serverDetails.contentserver.port+"\:"+serverDetails.contentserver.port);
//$scope.init();
});
});
I need to invoke function init(), after reading the config(../config/config.xml) file.
I got an error of ReferenceError: $scope is not defined.
How can I add $scope in module.config? Or How can I call function from config?
If you need to add something to every scope in config, you can use $rootScope, but it's better practice to create a service for that data.
You can not ask for instance during configuration phase - you can ask only for providers.
var app = angular.module('app', []);
// configure stuff
app.config(function($routeProvider, $locationProvider) {
// you can inject any provider here
});
// run blocks
app.run(function($rootScope) {
// you can inject any instance here
});
See http://docs.angularjs.org/guide/module for more info.
var viewerAngular = angular.module('ngAppDemo', ['restangular','btford.socket-io'])
.config(function(RestangularProvider) {
$.get('../config/config.xml',
function(data) {
$(data).find('contentserver').each(function() {
serverDetails.contentserver = assignServerDetails($(this));
var restprovider = RestangularProvider;
restprovider.setBaseUrl("http://"+serverDetails.contentserver.ip+":"+serverDetails.contentserver.port+"\:"+serverDetails.contentserver.port);
var Scope=angular.element(document.querySelector('[ng-controller="controllerName"]')).scope();
Scope.init();
});
});
I have a simple question about the dependency injection in Angular. I create custom services in order to use them within each other. Unfortunately I receive errors the way I was trying it. This is my Code:
var myApp = angular.module('app', []);
myApp.service('$service1', ['$rootScope', function($rootScope) {
this.test = function() {
console.log('service1');
};
}]);
myApp.provider('$service2', ['$service1', function($service1) {
var service = 'service2';
this.registerService = function(mytext) {
service = mytext;
};
this.$get = function() {
var that = {};
that.test = function() {
console.log(service);
};
return that;
};
}]);
myApp.config(['$service2Provider', function($service2Provider) {
$service2Provider.registerService('changed service2');
}]);
myApp.controller('AppCtrl', ['$rootScope', '$service1', '$service2',
function($rootScope, $service1, $service2) {
$service1.test();
$service2.test();
}]);
Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:unpr] Unknown provider: $service1
http://errors.angularjs.org/1.2.0-rc.2/$injector/unpr?p0=%24service1
If you remove the dependency of $servic1 in $service2 it will work, but why?
The code is mostly right, except you have to inject service dependencies in $get, not in the provider constructor function, like this:
myApp.provider('$service2', function() {
var service = 'service2';
this.registerService = function(mytext) {
service = mytext;
};
this.$get = ['$service1', function($service1) {
var that = {};
that.test = function() {
console.log(service);
};
return that;
}];
});
It appears that provider can not inject such a dependency. If you rewrite $service2 using a factory, it works:
myApp.factory('$service2', ['$service1', function($service1) {
var that = {};
that.test = function() {
$service1.test();
console.log('service2');
};
return that;
}]);
See this plunker: http://plnkr.co/edit/JXViJq?p=preview
Also I believe that service names starting with a $ a reserved for AngularJS and its extensions. Use names without the $ at the beginning for services defined by your application.