Why can't I get an $location from the $injector? - angularjs

I am new to angular and trying to use the $location service outside of the scope using $injector.
When I run the following code I keep getting an error
angular.injector(['myApp']).get('$location');
Any suggestions?

The $location service is not part of the myApp module, it is part of the internal ng module.
To get the $http service, use:
var $http = angular.injector(['ng']).get("$http");
The $location service depends on the $rootElement service which is created at bootstrap time. To get the $location service use:
var $rootElementModule = function($provide) {
$provide.value('$rootElement', angular.element(document))
}
var $location = angular.injector(['ng',$rootElementModule]).get("$location");

Related

How to inject angular service in controller in ionic framework?

I am working on Ionic Framework and there is a requirement that I need to inject the angular services in controller to get the data or perform any CRUD operation in backend. Please Let me know how I can do this?
if you are using Ionic2 here is an example on how to inject a Service into a controller; note the #Injectable decorator in the Service, the [providers] parameter of the #Page decorator in the Controller, and how the service instance is a parameter of the constructor.
Ionic Framework is build upon angular.js, so there s no difference in doing this in Ionic.
Its simple like
var myapp = angular.module('myApp',['ionic']);
myapp.service('MyService',['$http', function($http) {
return {
doSomeThing: function() {
// do something here with $http or whatever
},
doSomeThingElse: function() {
}
}
]);
myapp.controller('MyController',['MyService',function(MyService) {
MyService.doSomeThing();
}]);
In addition to the answer provided by #mJunaidSalaat,
You need to inject IONIC module to angular app module
The remaining implementation will be as it is in Angular
As per below, you can:
angular.module('myApp', ['ionic'])

Is there a way to define service on controller only

I have this global set up for my angular App module:
var App = angular.module('App', [], function ($interpolateProvider) {
//$interpolateProvider.startSymbol('<%');
//$interpolateProvider.endSymbol('%>');
});
I include it in all pages with angular stuff.
I then have a controller loaded on a page that requires a service called 'angularFileUpload':
App.controller('FileUploadController', ['$scope', 'FileUploader', function ($scope, FileUploader) {
If i place that service inside the module array, it works fine. Is there a way of just attaching it to this controller instead... this means i do not have to load the script files for every page using this module regardless of if the controllers require the angularfileUpload service or not.
Edit: regarding the last comment
If i declare:
var App = angular.module('App');
How do i then add that service to the module?

Controller testing fails due to the service dependency injection

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.

Angular testing with qunit and httpBackend

I have bee struggling with this all day. Here is my test
injector = angular.injector(['ngMock','ng', 'cockpit']);
var equal = QUnit.assert.equal;
test('loginService', function () {
var app, service, scope, httpBackend;
app = angular.module('cockpit');
app.config(function ($provide) {
$provide.decorator('httpBackend',
angular.mock.e2e.$httpBackendDecorator);
});
httpBackend = injector.get('$httpBackend');
httpBackend.when("PUT", "/login").respond({ userId: 23 });
service = injector.get('loginService');
service.$http = httpBackend;
service.getUserId('easy', 'path');
httpBackend.flush();
equal(service.userId, 23, 'populates userId property');
});
Inside the getUserId method the $http service has not put method, so when I make the $http.put call, it fails. I must be setting the test up incorrectly.
I did not get that $httpBackend in Angular mocks is a wrapper for the $httpBackend in angular itself. You just have to instantiate it and set it up to intercept the $http calls the way you want. That said, I still can't get $httpBackend.flush() to work. Testing in angular isn't quite as easy as advertised.
$http and $httpBackend are two different services. $http uses $httpBackend. $http is the service which has the put() method.
So, the following line doesn't make sense:
service.$http = httpBackend;

How to get a service from angular on initialization?

I have been looking for a way to get services on initialization of my angular-js application, but could not find how to get it to work. In my case I want to get the $location service to observe the url.
Looking around, I found the services can be retrieved from the injector. To get the injector, I bootstrapped my application like this:
var angularApp = angular.module("MyApp", []);
var angularInjector = angular.injector(["MyApp", "ng"]);
angularApp.run(initializeAngularApp);
initializeAngularApp()
{
var location = angularInjector.get("$location");
}
This throws an Error:
Unknown provider: $rootElementProvider <- $rootElement <- $location
My understanding is that initializeAngularApp() should get called once the injector is done initializing. But judging from the error I get, it would not be the case.
What is the best way to get the services from the injector when my application initializes?
I found my answer and I did not need to instantiate the injector myself to get the service.
Services are injectable in the run() function, so doing:
angularApp.run(intializeAngularApp);
with
initializeAngularApp($rootScope, $location)
{
$rootScope.location = $location;
$rootScope.$watch("location.url()", function () { alert("url changed"); });
}
works.

Resources