I have the following angularjs service:
angular.module('app.main').factory('MyService', ["$http", function ($http) {
return new function () {
this.GetName = function () {
return "MyName";
};
};
}]);
How can I call GetName function from MyService from legacy js code?
Use angular.injector. Using your code you can do something like the following:
angular.module('main.app', []).factory('MyService', ['$http', function ($http) {
return new function () {
this.GetName = function () {
return "MyName";
};
};
}]);
angular.injector(['ng', 'main.app']).get("MyService").GetName();
Here is the jsfiddle: http://jsfiddle.net/wGeNG/
NOTE - You need to add "ng" as your first module before loading your custom module since your example code depends upon $http provider which is in the ng module.
EDIT - Using get() as in OP's answer but note this code is fetching the service without relying upon the element being bound to the app module "main.app".
For me it worked with:
angular.element(document.body).injector().get("MyService")
I got 'Unknown provider' error when tried this:
angular.injector(['ng', 'main.app']).get("MyService")
and as i am using jqLite, i can't do
angular.element('*[ng-app]')
because selectors are not supported by jqLite, but i got [Dor Cohen] idea. My directive ng-app is on my body tag, then i can use:
angular.element(document.body).injector().get("MyService")
or
angular.element(document).find('body').injector().get("MyService")
Using the following line helps to execute my method from the angularjs service:
angular.element('*[ng-app]').injector().get("MyService").GetName ();
Here's a utility method that I use :
function getService(name, element) {
element = element || '*[ng-app]';
return angular.element(element).injector().get(name);
}
getSrv("name-of_service", document.body)
Related
Here in summary.controller.js at line 37 i'm calling the 'filter.jdpa' which is the method defined in the service: filter.js.
The method is meant to return an array jdpaarr but when i call it in the controller i get the whole method definition as the output
The code for the service is also attached below
(function () {
'use strict';
angular.module('app')
.service('filter', filter);
function filter() {
this.jdpaf=jdpaf;
this.yearf=yearf;
this.cityf=cityf;
function jdpaf(){
var jdpaarr=['All','JDPA','Non-JDPA'];
console.log(jdpaarr);
return 'jdpaarr';
}
function yearf(){
var yeararr=['2011','2012','2013','2014'];
console.log(yeararr);
return 'yeararr';
}
function cityf(){
var cityarr=['Delhi','Mumbai','Trivandrum','Banglore','Hyderabad'];
return cityarr;
}
}
})();
I have given console.logs in the service itself but that fails to work.
But why is the whole function definition being shown in the function call ?
You are basically assigning the definition only.
Try calling/executing it on initialization and saving the returned value in your scope like.
$scope.Filterarray.jdpa = filter.jdpaf();
Hope this helps.
I am using the following snippet to get the data from server to load the initial content of the page.
(function () {
'use strict';
angular
.module('app')
.controller('MyController', MyController);
MyController.$inject = ['UserService', '$rootScope', '$scope', '$cookieStore', 'AuthenticationService'];
function MyController(UserService, $rootScope, $scope, $cookieStore, AuthenticationService) {
/*Discussion Board related Functions*/
angular.element(document).ready(function () {
// Get Current User
$rootScope.globals = $cookieStore.get('globals') || {};
$scope.currentUser = AuthenticationService.GetAuthData($rootScope.globals.currentUser.authdata);
$.getJSON(
"http://localhost/getSomeServerData.php",
{ userName: $scope.currentUser },
$scope.getSomeDataResponse
);
});
$scope.getSomeDataResponse = function (jason) {
var servRet = jason;
alert("On Load Called-2");
};
}
})();
However, the response function $scope.getSomeDataResponse is not getting called.
Please let me know what is wrong with this approach.
However, the response function $scope.getSomeDataResponse is not
getting called.
Please let me know what is wrong with this approach.
The issue is, you are referencing getSomeDataResponse before it is being declared. Also, you are using jQuery's getJSON() to get the data from server using HTTP GET request in your angularJS code.
This is particularly not a recommended practise. If you include jQuery in your page, AngularJS will use jQuery instead of jqLite when wrapping elements within your directives, otherwise it'll delegable to jqLite(which might not work in all cases). To be at a safer side, use angular's $http.get() service instead of $.getJSON()
$http.get("http://localhost/getSomeServerData.php",{ userName: $scope.currentUser})
.then(function(jason){
//success handler function
var servRet = jason;
alert("On Load Called-2");
},function(err){
//error handler function
alert(err);
})
Ofcourse you'd need to inject $http service in your controller to make it work. Have a look at this thread for other possible alternatives.
Cheers!
First, you have to define your result function before using.
Second, you have to use $.getJSON correctly. So this worked for me after fixing
$scope.getSomeDataResponse = function (jason) {
var servRet = jason;
alert("On Load Called-2");
};
/*Discussion Board related Functions*/
angular.element(document).ready(function () {
// Get Current User
$rootScope.globals = $cookieStore.get('globals') || {};
$scope.currentUser = AuthenticationService.GetAuthData($rootScope.globals.currentUser.authdata);
$.getJSON(
"http://localhost/getSomeServerData.php",
{ userName: $scope.currentUser }
).always($scope.getSomeDataResponse);
the callback method was different in jQuery. use fail and done callbacks by looking at the jQuery documentation
http://api.jquery.com/jquery.getjson/
I recently dug a little deeper into unit testing. I was wondering if there is a way to use spies in production code as well. I've a tracking service. It would be nice to access other services and maybe even controllers, without haveing to alter their code.
Is there a way to spy on methods being called from services and controllers in the application code and what would be the best way to do so?
EDIT
Atm. I'm using this pattern for spying on services:
var vSetFNTrigger = function (sEvent, fnTrigger) {
fnTrigger.obj[fnTrigger.sMethod] = (function () {
var fnCached = fnTrigger.obj[fnTrigger.sMethod];
return function () {
$rootScope.$broadcast(sEvent, {});
return fnCached.apply(this, arguments);
};
})();
};
fnTrigger: {
obj: formData, // the service
sMethod: 'qPost' // the method to spy on
},
EDIT 2
I forgot to add a return to the inner function.
There should be nothing stopping you from doing this, although I think it is the wrong tool for the job.
If you are in Angular, you should consider using a decorator pattern. You can even use the provider decorator to intercept pretty much anything in Angular.
For instance, you might have a spy function that looks like this:
function createSpy(serviceName, source, spyNames, rootScope) {
var spy = angular.extend(angular.isFunction(source) ? function () {
console.log("Called " + serviceName + '()', arguments);
// broadcast with rootScope
return source.apply(source, arguments);
} : {}, source);
spyNames.forEach(function(name) {
var original = spy[name];
spy[name] = function() {
console.log("Called " + serviceName + '.' + name, arguments);
// broadcast with rootScope
return original.apply(spy, arguments);
};
});
return spy;
}
Then, you can create a generic function to generate a decorator:
function decorateWithSpy($provide, service, spyNames) {
$provide.decorator(service, function($delegate, $rootScope) {
return createSpy(service, $delegate, spyNames, $rootScope);
});
}
You can configure your spies like this:
app.config(function($provide) {
decorateWithSpy($provide, '$http', ['get']);
decorateWithSpy($provide, '$compile', []);
});
Doing this causes all of my $http and $compile functions to get printed to the console.
I have a provider defined as follows:
(function(angular) {
angular.module('myModule', [])
.provider('myService', function () {
var service = {};
service.configureSomething = function () { };
service.$get = function () { return {}; };
return service;
});
})(angular);
How can I test configureSomething()?
The example shown in the AngularJS documentation assumes the provider is a public function rather than being an anonymous function passed inside .provider() within a (function(){})() approach.
Please note that I don't want to test for the provider instance, I'm just interested in testing the configuration.
Here's the answer provided by Mark Gemmill based on Eitan Peer's answer to my same question posted in the AngularJS Google Groups.
I'm confused, I have this module which routes to different controllers:
var mainModule = angular.module('lpConnect', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/home', {template:'views/home.html', controller:HomeCtrl}).
when('/admin', {template:'views/admin.html', controller:AdminCtrl}).
when('/connect', {template:'views/fb_connect.html', controller:MainAppCtrl}).
otherwise({redirectTo:'/connect'});
}]);
and a Common service like so:
mainModule.factory('Common', ['$rootScope', '$http', function (scope, http) {
var methods = {
changeLanguage:function (langID) {
http.get('JSON/langs/' + langID + '/captions.json').success(function (data) {
scope.lang = data;
});
},
initChat:function () {
console.log(scope); // full object
console.log(scope.settings); // undefined
}
};
//initiate
http.get('JSON/settings/settings.json').success(function (data) {
scope.settings = data;
methods.changeLanguage(scope.settings.lang);
});
return methods;
}]);
the app loads and gets (through XHR) the settings object, and I can see the settings reflects in my DOM. (captions for example)
Now when I call the initChat method from my HomeCtrl I get an undefined value when trying to access the scope.settings property ... what's strange is that when I log the scope I can see the settings object ... What am I missing?
Update: I found out that what I'm doing wrong is calling my method directly from the controller body:
function HomeCtrl($scope, $location, Common) {
...
Common.initChat()
...
}
if I change the call to be triggered by a click all works fine, but I do need this code to run when the page loads, What is the right approach?
It's a simple problem, I think: You're calling initChat in your scope before the $http call retrieves scope.settings.
Couple of things.
http is async and that is your main problem (as Andy astutely pointed out)
ng-init is not recommended for production code, initializing in controllers is better
initializing your scope.settings = {} or a decent default may help you, once xhr is done then your settings will be available.
hope this helps
--dan