Angular factory not being instantiated - javascript

I have angular 1.4 app. Im using require.js. An included script have this:
define(['firstFactory', 'secondFactory'],
function(firstFactory, secondFactory){
var app = angular.module('services', []);
app.factory('firstFactory', firstFactory);
app.factory('secondFactory', secondFactory);
});
Inside require.config (in main.js) I have path to both the factories:
"firstFactory" : "factory/firstFactory",
"secondFactory" : "factory/secondFactory"
Finally in my main controller I have this:
function myCtrl(firstFactory, secondFactory) {
Thing is that in firstFactory.js I have this code:
define([], function () {
console.log('inside define firstFactory');
var firstFactory = function () {
console.log('inside function firstFactory');
};
return firstFactory;
});
While in the secondFactory.js I have this:
define([], function () {
console.log('inside define secondFactory');
var secondFactory = function () {
console.log('inside function secondFactory');
};
return firstFactory;
});
In the console I see:
inside define firstFactory
inside function firstFactory
inside define secondFactory
So I dont see
inside function secondFactory
Why? To me the symptom is that angular is not instantiating the second factory. I cannot understand that for the first one it is being instantiated but not for the second, as Im doing the same thing with both. Any clue?

In the secondFactory.js you are returning firstFactory, may be this is the reason.

Related

Stumped with Angular module inheritance

I'm trying to implement John Papa's Angular architecture, but I can't seem to get it to work. I feel like I'm missing something basic about how inheritance works.
I'm just trying to access a factory method =, test.ping, that lives in the base app module, from the feature module, foo.module.js. When I try to call the function, I get an error in the console:
ReferenceError: 'test' is undefined
//app.js
(function () {
angular.module("app", ['app.foo'])
.factory('test', [function () {
var service = {
ping: ping
};
return service
function ping() {
alert('PING Service method called.');
}
}])
})();
//foo.module.js
(function () {
angular.module('app.foo', []);
})();
//foo.js
(function () {
angular
.module('app.foo')
.controller('Foo', Foo);
Foo.$inject = [];
function Foo() {
var vm = this;
alert('Foo loaded'); //the alert is working
vm.ping = function () {
alert('Ping button clicked.'); //the alert is working
test.ping(); //this throws console error
}
}
})();
//html
<body data-ng-controller="Foo as fooCtrl">
<button data-ng-click="fooCtrl.ping()">PING</button>
You forgot to add test service in dependency injection.
Foo.$inject = [];
change this to
Foo.$inject = ['test'];
And also
function Foo() {
this to
function Foo(test) {

Why are my controllers methods not available?

after a long time I have to concentrate an angular again.
But I fail...
... ng-repeat="n in DataController.getObjects"
myApp.controller('DataController', [function () {
console.log('test 1');
var getObjects = function () {
console.log('test 2');
return [1,2,3,4,5,6,7];
};
}]);
It is writing test 1 to console but not test 2. And the frontend does not get the array.
Any hint for me?
Regards
n00n
You have to expose method/variable which you want to access on page on this(context) of your controller. So that you can access that method/variable via controller alias as you you seems to be using controllerAs pattern.
Code
myApp.controller('DataController', [function () {
var self = this;
console.log('test 1');
var getObjects = function () {
console.log('test 2');
return [1,2,3,4,5,6,7];
};
self.getObjects = getObjects;
}]);
I hope you have already defined controller alias while using ng-controller directive, If you haven't used it, follow below.
ng-controller="DataController as dataCtrl"
ng-repeat="n in dataCtrl.getObjects()"
And as you can see you should call method in ng-repeat like getObjects() to get a array from method.

Mocking ngResource in Angular unit tests

I have an ngResourceMockFactory which looks like this:
(function() {
'use strict';
angular.module('app')
.factory('NgResourceMock', ngResourceMockFactory)
;
ngResourceMockFactory.$inject = [];
function ngResourceMockFactory() {
function NgResourceMock() {
var context = this;
context.$promise.then = function() {
context.prototype.$promise.then.apply(context, arguments);
};
context.$promise.finally = function() {
context.prototype.$promise.finally.apply(context, arguments);
};
}
NgResourceMock.prototype.$promise = {
then: function(onSuccess, onError) {
this.$promise.onSuccess = onSuccess;
this.$promise.onError = onError;
},
finally: function(onComplete) {
this.$promise.onComplete = onComplete;
}
};
return NgResourceMock;
}
})();
I inject this into my tests in a beforeEach like so:
beforeEach(inject(function(NgResourceMock) {
ngResourceMock = new NgResourceMock();
}));
then I use it like this:
describe('initiateWorkflow function', function() {
beforeEach(function() {
vm.player = {id: 123};
spyOn(dataService, 'initiateWorkflow').and.returnValue(ngResourceMock);
vm.initiateWorkflow();
});
it('should call dataService.initiateWorkflow', function() {
expect(dataService.initiateWorkflow).toHaveBeenCalledWith({playerId: vm.player.id}, {});
});
});
but I keep seeing the following error:
TypeError: 'undefined' is not an object (evaluating 'context.prototype.$promise')
This leads me to believe that something is wrong with my ngResourceMockFactory, but I'm not sure what it is.
Don't know if this can be of any help, but if you are trying to evaluate asynchronous operations in your tests, you may want to use the done() method in Jasmine.
As per their documentation:
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
by passing done as a parameter of the beforeEach callback, any test run after the before each will wait until the done() function has been called.
Source: Jasmine (Asynchronous Support section).
Hope this helps.
Here is the solution to your problem.
The error TypeError: 'undefined' is not an object (evaluating 'context.prototype.$promise') is caused when you try to invoke the promise object before invoking the function into which it is defined or into which your parent function is defined.
Here the returnValue(ngResourceMock) is directly calling into the function without the context and parameters need to be defined.
Therefore you can try to add another beforeEach statement like
beforeEach(angular.mock.module(app));
to load your app module
Here may be the same concept related to your problem another link here.
Hope it may help you a bit.

Jasmine and AngularJS - how to test a factory function when the function is used as a dependency

I have the following simple factory that i would like write a unit test around.
(function () {
"use strict";
angular
.module("math")
.factory("addservice", [addTwoNumbers]);
function addTwoNumbers(a, b) {
return a + b;
}
return { add: addTwoNumbers };
})();
This is what i have so far in my test spec.
describe('adding two numbers', function () {
var addService;
beforeEach(function () {
module('math');
inject(function ($injector) {
addService = $injector.get('addservice');
});
});
it('should add two numbers and get 2', function () {
var result = addService.add(1, 1);
expect(result).toBe(2);
});
});
When trying to run this unit test i get TypeError: addService.add is not a function. I will note that i can get this to work if i change the factory declaration to the code seen below but we ran into a problem where minification was screwing up parameter names and changing them to a,b,c,etc. (when passing in $q, $http, and many other dependencies) and breaking the code so we moved to what is seen above. This is obviously a very basic example here which is why it is so frustrating on why i can't get this to work.
(function () {
"use strict";
angular
.module("math")
.factory('addservice', [function () {
function addTwoNumbers(a, b) {
return a + b;
}
return { add: addTwoNumbers };
}
]);
})();
It seems like I need to reference the addTwoNumbers function somehow but not sure how i would go about doing that. I'm probably missing something very obvious so any help is greatly appreciated.
Ok so i figured out what was wrong with this example. It ends up if i refactored my factory a bit I could simply make a call in my unit test to the property twoNumbersAddedTogether after i get the reference to the factory itself. I've provided the new unit test and factory code below.
factory code
(function () {
"use strict";
angular
.module("math")
.factory("addservice", [addTwoNumbers]);
function addTwoNumbers() {
return {twoNumbersAddedTogether: dotheMath}
function dotheMath(a,b) {
return a + b;
}
}
})();
unit test code
describe('adding two numbers', function () {
var addService;
beforeEach(function () {
module('math');
});
beforeEach(inject(function (_addservice_) {
addService = _addservice_;
}));
it('should add two numbers', function () {
var result = addService.twoNumbersAddedTogether(1, 1);
expect(result).toBe(2);
});});

The service call is returning the function definition than the actual return in angular

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.

Categories