I'm confused about how to create services and inject (use) them in my controllers. It seems it is very simple but I can't get my code to work. I'm stuck with this error:
Error: [$injector:unpr] Unknown provider: Flickr
I define the service:
angular.module('myApp.services', [])
.provider('Flickr', function(){
// service code
})
Include it in my app module:
var app = angular.module('myApp', [
'ngResource',
'ngRoute',
'myApp.services'
]);
and then reference it in a controller:
app.controller('FlickrCtrl', ['$scope', '$routeParams', 'Flickr', function($scope, $routeParams, Flickr){
// controller stuff
});
and reference the files at the bottom of index.html
<script src='js/app.js'></script>
<script src='js/config.js'></script>
<script src='js/services/Flickr.js'></script>
<script src='js/controllers/flickr.js'></script>
Why can't angular find the service I defined when I ask it to inject it into the controller?
When using .provider, you are creating a provider that should return a configurable singleton. In many cases, this singleton is a singleton factory, spitting back an object that has services you can use.
First, you would need to refer to it as FlickrProvider instead of Flickr when you call it to set a config.
Without seeing more of your code, I can't tell if you're returning a new Flickr from your provider, which is what you would need to do in order to use a service instance in the way I think you're trying to do.
check out: http://docs.angularjs.org/guide/providers
Basically though, in order to inject and use Flickr like you are trying to do, you would need to do something like this:
.provider('Flickr',function FlickrProvider(){
this.$get = function(){
return new Flickr()
}
})
function Flickr(){
this.doSomething: function(){
//do something or return something
}
}
If you only want to define a service, and not make it a configurable provider, then use .factory instead, which will only need Flickr to be injected in order to be used.
Related
I was implementing angular translate in my project and everything works fine, but when I've moved my $translateProviderfrom my config block to my controller.js, I'm getting this error:
Unknown provider: $translateProviderProvider <- $translateProvider <-
myController
But every module seems to be correctly referenced, am I missing something here? or maybe this translations can't work inside of a controller?
controller.js
angular.module('myapp.controller', ['pascalprecht.translate'])
.controller('myController',
['$translateProvider',
function ($translateProvider) {
function init() {
$translateProvider.useUrlLoader('myweb.com/api/lang', {
queryParameter : 'en_US'
});
$translateProvider.preferredLanguage('en_US');
}
init();
}]);
UPDATE
Now I know that $translateProvider are not available to use it in controller class.
What I'm trying to accomplish:
I don't want to load all the traductions files from the rest, because there are many components that the user never see, so if I go to the page that contains ng-controller="myController", the init() function should call to the rest and get the traductions only for the current component. I've found this on the documentation:
angular.module('contact')
.controller('ContactCtrl', function ($scope, $translatePartialLoader) {
$translatePartialLoader.addPart('contact');
});
But how can I:
Specify the URL for my REST?
Specify the parameter 'contact' in the URL to my REST know that it should retrieve me the traductions only for the contact component.
When injecting a provider in a controller, you don't need the Provider suffix.
just inject it as
.controller('myController', ['$translate', function ($translate) { ... }])
I'm new to angular and unit-testing.
I have an application module MyApp including basic things an services, that are needed in all other modules, like service for logging loggingService
I also have an module for handling everything about map&geo-positon, called MapModule and I have an main module for application logic, called MainModule
The MainModule contains a controller, that I like to test: messageSendCtrl
The controller has some dependencies, like services from MapModule.
And: MainModule and MapModule has dependencies to the MyApp, because the loggingServiceis needed everywhere.
The code looks like that (pseudo-code):
MyApp
var MyApp = angular
.module('MyApp', ['ngRoute','MainModule','MapModule']);
MyApp.service('loggingService', function (one, two) {
[..] /*logging data somewhere for debugging application*/
});
MainModule
var MainModule = angular
.module('MainModule', []);
MainModule.controller('messageSendCtrl',
function($scope,$http, $location, locationService, loggingService) {
[...]
});
MapModule
var MapModule = angular
.module('MapModule', ['uiGmapgoogle-maps']);
MapModule.service('locationService', function (loggingService) {
[...]
What I like to test is the messageSendCtrl from the MainModule. (probably) I was able to inject the location service into the test environment. But injecting the locationService was not successful.
Probably because locationService also uses the loggingService.
Running the test results in
Error: [$injector:unpr] Unknown provider: loggingServiceProvider <- loggingService <- locationService
My test looks like that:
describe('saving a document', function() {
beforeEach(module('MainModule'));
beforeEach(module('MyApp'));
beforeEach(module('MapModule'));
describe ('messageSendCtrl', function () {
var scope,ctrl,locationService,loggingService;
beforeEach(inject(function($rootScope, $controller,_locationService_,_loggingService_) {
scope = $rootScope.$new();
ctrl = $controller('messageSendCtrl',
{$scope: scope,
locationService: _locationService_,
loggingService : _loggingService_ });
}));
it('should actual not saved', function(){
expect(scope.result).to.equal('unsaved');
});
})
});
So who can I solve the dependencies? Or is there an design problem at my application?
there are multiple things going on, let's check it one by one:
at your test, you don't need do load all your modules, load just that module, that you want to test, your ctrl is in your MainModule, so use just
beforeEach(module('MainModule'));
every module should declare its dependencies, so your MainModule declaration should look like this: var MainModule = angular.module('MainModule', ['MyApp']); because one of your controller in your MainModule dependent on a service that is in an other module (MyApp)
it is easier to test if one module do just one thing, so if you have a logging service, make a logging service module for that, and include that module where you want to use logging.
So don't make modules that is responsible for several different things, because if an other module need logging, that module will get every other service that your "godmodule" contains, and that makes difficult to test, and find bugs.
I am still relatively new to Ionic and AngularJS and I have the following problem: I created a service in the controller.js file and now need this service at loadup (app.js) to detect which start page I will route to. How can I export the service from controller.js into some other js file so that it will become available in both files app.js and controller.js.
Thanks,
EL
You import it using angular's dependency injection.
If your controller.js looks something like:
angular.module('myModule', [])
.service('myService', ['$scope', 'otherDependency', function($scope, otherDependency){
//some service code
}]);
Then the module you want to use the service in would need to import the module where the service is located and then inject the service itself. So something along the lines of:
angular.module('app', ['myModule'])
.controller('appCtrl', ['$scope', 'myService', function($scope, myService){
//some code using your service
}]);
This documentation might help:
AngularJS services - https://docs.angularjs.org/guide/services
AngularJS dependency injection - https://docs.angularjs.org/guide/di
When making use of a service in a controller test do you need to initialize the service in the same way you would the controller? By this I mean do you need to pass it its own dependencies?
For example I can initialize my controller like so:
// Instantiate the controller
searchController = $controller( 'VisibilitySearchController',{
$scope: scope,
dataService: dataService
});
}));
so do I need to initialize the service according to the components it needs like $http, $resource etc as well as make spyOn calls on its functions? Or is this/should this be sufficient? (Note - my tests fail when I do the following )
// Instantiate the dataService
dataService = $injector.get( 'dataService' );
it throws this error:
* Error: [$injector:unpr] Unknown provider: $resourceProvider <- $resource <- dataService
The relevant part of the service:
myAppServices.factory('dataService', ['$http', '$resource', 'authService', 'messageService', function ($http, $resource, authService, messageService) {
}
Side note
Note - we are using Maven as our build tool and only make use of Jasmine at this point - trying to bring Karma in as our test-runner as a Maven plugin.
You must provide all the dependencies but you can mock them. This can be done by jasmine like this for example:
var mockedDataService = jasmine.createSpyObj('dataService', ['getData', 'getOtherData']);
And then you inject this mocked service to $provider:
beforeEach(function () {
module(function ($provide) {
$provide.value('dataService', mockedDataService );
});
}
Instance of this mocked service can be retrieved like this then:
inject(function (dataService) {
var dataServiceInstance = dataService;
});
This will provider mocked dataService anytime it is needed. However if you need fully functional dataService you must instantiate it but always you can mock any of its dependecies.
While you can inject dependencies into the controller manually you don't need to do it as long as you have loaded the module the service belongs to.
In your case it looks like you have not loaded the ngResource module.
If you add beforeEach(module('ngResource')) to your test (and make sure the actual script file it lives in is included in Jasmine's fileset) you should not need to inject it manually.
Note that you do not need to load angular core services like $http, but since $resource is not part of core it needs to be loaded like this.
Injecting dependencies manually is mostly useful if you want to provide a mock implementation.
I'm learning Angular and I'm trying to include Restangular this way:
var app = angular.module('myapp',['restangular']);
app.controller('UsersController', ['$scope', function ($scope, Restangular) {
...
Then I'm using Restangular like this:
var data = Restangular.all('someurl');
Here I get an error: Restangular is undefined. According to the documentation, this should have been simple:
// Add Restangular as a dependency to your app
angular.module('your-app', ['restangular']);
// Inject Restangular into your controller
angular.module('your-app').controller('MainCtrl', function($scope, Restangular) {
// ...
});
However I am unable to get it to work. What gives?
You're using the bracket notation for your controller, but you forgot to add Restangular to the list of dependencies:
['$scope', 'Restangular', function ($scope, Restangular) {...}]
This article has more information on Angular and minification. Search for "A note on minification”.
That looks correct, just make sure you've added the import of Restangular to your html file
<script type="text/javascript" src="http://cdn.jsdelivr.net/restangular/1.1.3/restangular.js"></script>
They also mention it requires lodash or underscore.js so maybe make sure you're loading those as well