Can we call the factory functions defined in one module from another module? If so, how?
Let's say my first module is defined in moduleOne.js file as:
var myModule = angular.module('MyServiceModuleOne', []);
myModule.factory('notify', function () {
return {
sampleFun: function () {
// some code to call sampleFunTwo()
},
};
});
And my second module in moduleTwo.js as:
var myModuleTwo = angular.module('MyServiceModuleTwo', []);
myModuleTwo.factory('notifytwo', function () {
return {
sampleFunTwo: function () {
// code
},
};
});
How to call sampleFunTwo() from sampleFun()?
Thanks.
You need to inject MyServiceModuleTwo into MyServiceModule:
var myModuleTwo= angular.module('MyServiceModuleTwo',[]);
var myModule= angular.module('MyServiceModuleOne', ['MyServiceModuleTwo']);
Then inject notifytwo into notify:
myModule.factory('notify', function(notifytwo) {
return {
sampleFun: function() {
notifytwo.sampleFunTwo();
}
};
});
myModuleTwo.factory('notifytwo', function() {
return {
sampleFunTwo: function() {
alert('From notify two');
}
};
});
And the code on plunker
Related
I have the following services:
DataService.js
app.service("DataService", [
function () {
this.getData = function () { return "original value" }
}
]);
LocationService.js
app.service("LocationService", ["DataService",
function(dataSvc) {
this.getLocationData = function () {
return dataSvc.getData();
}
}
]);
Now for testing LocationService.js, how do mock DataService inside of LocationService?
This is what I currently have for LocationService_tests.js:
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
describe("getLocationData", function () {
it("returns the location data", function () {
var mockLocationDataValue = "mocked value";
// ???
// I want to mock dataSvc.getData within getLocationData
// so it returns "mocked value" instead of "original value"
expect(locationSvc.getLocationData()).toBe(mockLocationDataValue);
});
});
});
You could mock whole service using $provide API's service method, and change your service to returned mock data.
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(module(function($provide) {
$provide.service('LocationService', function() {
this.getData = function() {
return "mock value";
}
});
});
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
...
});
My ctrl is like this:
(function() {
'use strict';
angular
.module('App')
.controller('DeviceStatesCtrl', DeviceStatesCtrl);
function DeviceStatesCtrl( $rootScope, $scope, $translate,DeviceStatesService) {
var vm = this;
DeviceStatesService.getObject().then(function(response){
vm.init(response);
});
vm.init= function(response){
$translate(['table.title']).then(function(translate){
some stuff here
}));
}
}})();
My jasmine test is like this:
describe('app module', function() {
//var controller = null;
var $controller, $translate,$compile,createController,DeviceStatesService,$translate, scope;
var mockInit= sth;
beforeEach(function () {
module('App');
});
// Provide will help us create fake implementations for our dependencies, do not useful
module(function($provide) {
// Fake StoreService Implementation returning a promise
//nothing works :(
$provide.value('DeviceStatesService', {
getStatesObject: function() {
return {
then: function(callback) {
return callback([{ some: "thing", hoursInfo: {isOpen: true}}]);
}
};
}
});
});
return null;
});
beforeEach(inject(function($controller,$rootScope, _$translate_, _DeviceStatesService_) {
scope = $rootScope.$new();
//for 'controller as' syntax
$controller('DeviceStatesCtrl as deviceStat', {
$scope: scope
});
createController = function(params) {
return $controller("DeviceStatesCtrl as deviceStat", {
$scope: scope,
$stateParams: params || {}
});
};
}));
describe("Unit:Device States controller", function() {
//test init function
it("init function get called correctly", function() {
//spyOn(DeviceStatesService, 'getStatesObject').and.callThrough();
//createController();
//expect(DeviceStatesService.getStatesObject).toHaveBeenCalled();
expect(scope.deviceStat.init).toBeDefined();
//in init, all things are warpped in the $translate
//spyOn(scope.deviceStat, 'init');
scope.deviceStat.init(mockInit);
scope.deviceStat.setChart('All');
//expect(scope.deviceStat.totalNum).toEqual(22);
});
});
});
My question is how to test the init function and the stuff in it? The init function is in a promise, which I do not know how to call it. As my code scope.deviceStat.init(mockInit), it do not work. Another question is in the $translate promise, how to pass parameter in it?
You use the done function, which is a parameter passed to the spec via the jasmine function it.. Example..
describe("My Test set", function() {
it("My Test", function(done) {
doAsync().then(function(result) {
done();
}).catch(function(err) {
fail();
}
}
}
Hope this helps.
I have a serviceProvider that needs some async init. I want my controllers to access this service only if the init is finished.
angular.module("myModule").provider("AsyncInit", {
myThing: {},
init: function(options) {
doSomeAsyncStuff(options).success(function(newThing) {
myThing = newThing;
});
},
$get: function() {
return {
theThing: myThing
}
}
});
//Initialisation of myModule
angular.module(myModule)
.config(function(AsyncInitProvider) {
AsyncInitProvider.init(options);
})
if I access AsyncInit.theThing in a controller it is not initialized at first but is later. This seems logical to me.
Is it possible to wait until the service is fully initialized?
If you really need to start the async call in the configuration process of your provider than you could use $interval.
this.$get = function($q, $interval) {
var deferred = $q.defer();
var handler = $interval(function() {
if (myThingHasBeenLoaded) {
$interval.cancel(handler);
deferred.resolve(myThingsValue);
}
}, 100);
return {
getMyThing: function() {
return deferred.promise();
}
};
}
// In your controller:
myThingService.getMyThing().then(function(myThing) { console.log(myThing); } );
I use this to load the Google experiments API and it works great. The interval will check all 100ms if your thing has been loaded successfully and then resolves the promise. The obvious catch here is that it only resolve every 100ms regardless of if your thing loads in 1ms. I would strongly suggest just to use a simple promise instead IF you don't have to make the async call in the configuration step:
angular.module("myModule").provider("AsyncInit", function () {
this.options = {};
this.init = function(options) {
this.options = options;
};
this.$get = function($q) {
var deferred = $q.defer();
var self = this;
return {
getMyThing: function() {
doSomeAsyncStuff(self.options)
.success(function(newThing) {
deferred.resolve(newThing);
})
.failure(function(errors) {
deferred.reject(errors);
});
return deferred.promise();
}
};
};
});
The code in your controller would be the same as in the example above.
Can i use one service into another angular service? Else what will be the best approach to accomplish the below?
First Service:
var app = angular.module("MyApp", []);
app.service('Service1', function () {
return {
FirstFunction: function () {
return "something";
}
}
});
Second service:
app.service('Service2', function () {
return {
SecondFunction: function () {
//How to use FirstFunction of Service1 ???
}
}
});
Thanks
app.service('Service2', function (Service1) {
return {
SecondFunction: function () {
Service1.FistFunction
}
}
});
As long as service2 doesnt depend on service1 there is no problem.
app.service('Service2', function (Service1) {
return {
SecondFunction: function () {
Service1.FirstFunction();
}
}
});
I have a ViewModel defined as below:
(function(ko, myApp) {
myApp.HomeViewModel = function () {
this.message = ko.observable("Helloy.....");
this.toolBarIsVisible = ko.observable(true);
this.isDataDirectoryManager = ko.observable(true);
};
myApp.HomeViewModel.prototype = {
sayHi: function () {
this.message("World");
}
};
ko.applyBindings(new myApp.HomeViewModel());
}(window.ko, window.myApp || {}));
How do I write a qunit test that instantiates an instance of myApp.HomeViewModel.
Thanks
Martin
You need to include your app code in the test file. The test code could be something like this:
(function (ko, myApp) {
var vm;
module( "HomdeViewModel", {
setup: function() {
vm = new myApp.HomeViewModel();
},
teardown: function() { }
});
test('Can create HomdeViewModel', function () {
ok(vm instanceof myApp.HomeViewModel);
});
test('Sets default values', function () {
strictEqual(vm.message(), 'Helloy.....');
ok(vm.toolBarIsVisible());
ok(vm.isDataDirectoryManager());
})
test('Can change message', function () {
vm.sayHi();
strictEqual(vm.message(), 'World');
});
})(window.ko, window.myApp)
Here's a jsFiddle with an example: http://jsfiddle.net/danne567/ptW9k/