Angular Service Undefined - angularjs

In the code snippet below, I'm getting "ReferenceError: 'ShoppingListService' is undefined". I can't see what the error might be, been banging my head against it and searched for a while now, anyone have clues?
var ShoppingListApp = angular.module('ShoppingListApp', [])
ShoppingListApp.factory('ShoppingListService', ['$http', function ($http) {
var ShoppingListService = {};
ShoppingListService.getListItems = function () {
return $http.get('/ShoppingList/GetListItems');
};
return ShoppingListService;
}]);
ShoppingListApp.controller('ShoppingListController', function ($scope) {
getItems();
function getItems() {
ShoppingListService.getListItems() //Error occurs here
.success(function (shoppingItems) {
$scope.items = shoppingItems;
console.log($scope.items);
})
.[removed for brevity].
The error occurs in the area indicated above. Angular.js version 1.4.9.

In your controller definition ShoppingListController you just have one injectable called $scope you need to add a second one called ShoppingListService.
ShoppingListApp
.controller('ShoppingListController', ShoppingListController);
ShoppingListController.$inject = ['$scope', 'ShoppingListService'];
function ShoppingListController($scope, ShoppingListService) {
getItems();
function getItems() {
ShoppingListService
.getListItems() //Error occurs here
.success(onSuccess);
}
function onSuccess(shoppingItems) {
$scope.items = shoppingItems;
console.log($scope.items);
}
//other code
}

Related

Cant read property from service in angular

In this case console logged all properties
app.controller("sgCtrl", function ($scope, $service)
{
var asd=service.getPerson();
console.log(asd);
}
But when im try to get some property its returned me undefined
...console.log(asd.person.Id)
My service
function service($http, $q) {
var service = {
person:[]
};
service.getPerson = function (personId) {
return $http.get('/P/GetP',
{params:{personId:personId}}).success(function (res) {
service.person = res.Person;
});
};
Issue is
1. $http.().success(function() {}) is asynchronous function. So service.person will be available only when control will come inside success callback handler.
2. You have not created service in the correct way.
You can try with below code:
Service code
function service($http, $q) {
this.getPerson = function (personId, successHandler) {
$http.get('/P/GetP',
{params:{personId:personId}}).success(function (res) {
successHandler(res.Person);
});
};
app.service('MyService', service);
Controller Code
app.controller("sgCtrl", function ($scope, MyService) {
function successHandler(person) {
console.log(person.IsActive);
}
MyService.getPerson('somePersonId', successHandler);
}
I believe it will resolve your issues.
Cheers!

Trying to test an angular controller with jasmine - errors

I am very new to angular/jasmine/karma and I'm having trouble getting a test written for my controller. The test itself is running successfully, but in the test running I'm getting the following error:
Error: userFactory() method does not exist
userFactory() is a method call made in my controller to a service that returns a promise. I'm not sure how to make sure this is correctly defined in the test.
Here is my code:
app.js
(function () {
angular.module('mdotTamcCouncil', ['mdotTamcCouncil.core', 'blurb']);
angular.module('mdotTamcCouncil.core', []);
})();
blurb-service.js
(function () {
angular.module('mdotTamcCouncil.core').factory('blurbsFactory', function ($http) {
var promise = null;
return function () {
if (promise) {
// If we've already asked for this data once,
// return the promise that already exists.
return promise;
} else {
promise = $http.get(jsGlobals.blurbsDataURL);
return promise;
}
};
});
})();
user-service.js
(function () {
angular.module('mdotTamcCouncil.core').factory('userFactory', function ($http) {
var promise = null;
return function () {
if (promise) {
// If we've already asked for this data once,
// return the promise that already exists.
return promise;
} else {
promise = $http.get(jsGlobals.userDataURL);
return promise;
}
};
});
})();
blurb-controller.js
(function () {
angular.module('blurb')
.controller('BlurbController', ['$scope', 'blurbsFactory', 'userFactory', function ($scope, blurbsFactory, userFactory) {
$scope.content = "";
$scope.blurbs = {};
$scope.currentUser = {};
this.editMode = false;
userFactory().success(function (data) {
$scope.currentUser = data;
});
blurbsFactory().success(function (data) {
$scope.blurbs = data;
$scope.content = $scope.blurbs[$scope.textKey];
});
this.enterEditMode = function () {
this.editMode = true;
};
this.saveEdits = function () {
this.editMode = false;
$scope.blurbs[$scope.textKey] = $scope.content;
};
}]);
})();
blurb-module.js
(function () {
'use strict';
angular.module('blurb', ['ngSanitize', 'mdotTamcCouncil.core']);
})();
and my test spec:
describe('BlurbController', function () {
var scope, controllerService;
beforeEach(module('mdotTamcCouncil'));
beforeEach(module('mdotTamcCouncil.core'));
beforeEach(module('blurb'));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controllerService = $controller;
}));
it("should get 'user' from 'data/user.json'", inject(function ($httpBackend) {
$httpBackend.expectGET("data/user.json").respond({"userName": "myera","email": "something#something.com","isAdmin": true});
$httpBackend.expectGET("data/blurbs.json").respond('{"mainPageIntro": "<h2>Welcome</h2>"}');
ctrl = controllerService('BlurbController', { $scope: scope });
$httpBackend.flush();
expect(scope.currentUser).toEqual({"userName": "myera","email": "something#something.com","isAdmin": true});
expect(scope.blurbs).toEqual({ "mainPageIntro": "<h2>Welcome</h2>" });
}));
});
I've pieced this together from reading blogs and stackoverflow answers. I'm not sure that I'm even doing it correctly.
The tests themselves actually pass, but I am getting the error in the console about the missing "userFactory()" method. I assume I would also get the message for the "blurbFactory()" method if it was getting that far. I don't believe I can test the actual functionality of the controller without first resolving these errors.
What am I doing wrong? Thanks so much for any help you can provide.
I believe the issue you are seeing is because you didn't include the 'mdotTamcCouncil.core' module as a dependency in the blurb module. When defining it, you should be able to pass in a list of dependencies using
angular.module('blurb', ['mdotTamcCouncil.core']);
You are only getting the one console error because the execution stops when the userFactory() fails. I'm not sure why the tests are showing as passing, it should pick up the exceptions and fail - could be an oddity with your chosen test runner.

pass data between controllers in AngularJS dynamically [duplicate]

This question already has answers here:
Share data between AngularJS controllers
(11 answers)
Closed 2 years ago.
i have tow controller in angularjs. if one controller change data other controller display updated data. in fact first controller has a event that it occur second controller display it. for this propose i wrote a service. this service has tow function. here is my service code.
app.service('sharedData', function ($http) {
var data=[]
return {
setData: function () {
$http.get('/getData').success(function(response){
data = response;
})
},
getData: function(){
return data;
}
}
});
in first controller
app.controller("FirstController", function ($scope, $http,sharedData)
{
$scope.handleGesture = function ($event)
{
sharedData.setData();
};
});
in second controller:
app.controller("SecondController", function ($scope,sharedData) {
var data=[];
data = sharedData.getData();
}
);
in first controller setData work with out any problem but in second controller not work correctly. how to share data dynamically between tow controllers?
You are on the right track with trying to share data between controllers but you are missing some key points. The problem is that SecondController gets loaded when the app runs so it calls sharedData.getData() even though the call to setData in the firstController does not happen yet. Therefore, you will always get an empty array when you call sharedData.getData().To solve this, you must use promises which tells you when the service has data available to you. Modify your service like below:
app.service('sharedData', function ($http, $q) {
var data=[];
var deferred = $q.defer();
return {
setData: function () {
$http.get('/getData').success(function(response){
data = response;
deferred.resolve(response);
})
},
init: function(){
return deferred.promise;
},
data: data
}
})
And the secondController like this:
app.controller("SecondController", function ($scope,sharedData) {
var data=[];
sharedData.init().then(function() {
data = sharedData.data;
});
});
For more info on promises, https://docs.angularjs.org/api/ng/service/$q
You had multiple syntax problems, like service name is SharedData and you using it as SharedDataRange, the service is getting returned before the get function.
What I have done is corrected all the syntax errors and compiled into a plunkr for you to have a look. Just look at the console and I am getting the data array which was set earlier in the setter.
Javascript:
var app = angular.module('plunker', []);
app.controller("FirstController", function ($scope,sharedDateRange)
{
sharedDateRange.setData();
});
app.controller("SecondController", function ($scope,sharedDateRange) {
var data=[];
data = sharedDateRange.getData();
console.log(data);
});
app.service('sharedDateRange', function ($http) {
var data=[];
return {
setData: function () {
data = ['1','2','3'];
}
,
getData: function(){
return data;
}
}
});
Working Example
If you want to keep sharedDataRange as the variable name and service name as sharedData have a look at this example
javascript:
var app = angular.module('plunker', []);
app.controller("FirstController", ['$scope','sharedData', function ($scope,sharedDateRange)
{
sharedDateRange.setData();
}]);
app.controller("SecondController", ['$scope','sharedData', function ($scope,sharedDateRange) {
var data=[];
data = sharedDateRange.getData();
console.log(data);
}]);
app.service('sharedData', function ($http) {
var data=[];
return {
setData: function () {
data = ['1','2','3'];
}
,
getData: function(){
return data;
}
}
});
You can bind the data object on the service to your second controller.
app.service('sharedData', function ($http) {
var ret = {
data: [],
setData: function () {
$http.get('/getData').success(function(response){
data = response;
});
}
};
return ret;
});
app.controller("FirstController", function ($scope, sharedData) {
$scope.handleGesture = function () {
sharedData.setData();
};
});
app.controller("SecondController", function ($scope, sharedData) {
$scope.data = sharedData.data;
});
What you need is a singleton. The service sharedData needs to be a single instance preferably a static object having a static data member. That way you can share the data between different controllers. Here is the modified version
var app = angular.module('app', []);
app.factory('sharedData', function ($http) {
var sharedData = function()
{
this.data = [];
}
sharedData.setData = function()
{
//$http.get('/getData').success(function(response){
this.data = "dummy";
//})
}
sharedData.getData = function()
{
return this.data;
}
return sharedData;
})
.controller("FirstController", function ($scope, $http,sharedData)
{
sharedData.setData();
})
.controller("SecondController", function ($scope,sharedData) {
$scope.data=sharedData.getData();
});
I have removed the event for testing and removed the $http get for now. You can check out this link for a working demo:
http://jsfiddle.net/p8zzuju9/

Scope Variable calling http service stays undefined

This might be a beginner question, but why does the $scope.usercountry Variable stays undefinded, although the service is successful?
http://jsfiddle.net/9twyLna1/
var myApp = angular.module('myApp', []);
myApp.factory('myService', function ($http) {
return {
userCountry: function () {
$http.get("http://ipinfo.io/json").success(function (data) {
var userCountry = data.country;
alert(userCountry);
return userCountry;
});
}
};
});
function MyCtrl($scope, myService) {
$scope.usercountry = myService.userCountry();
}
$http works in asynch way, what it means is when you call a service userCountry, an asynch call to the end point will be made and code will come back to the calling function. So basically you are trying to show the data before it is actually fetched. This is the basic behaviour when you work with promises.
To overcome this you will need to return a promise from the service and from calling function you should wait until data comes back from http request.
you can read about this here.
updated fiddle : http://jsfiddle.net/9twyLna1/3/
var myApp = angular.module('myApp', []);
myApp.factory('myService', function ($http) {
return {
userCountry: function () {
return $http.get("http://ipinfo.io/json");
}
};
});
function MyCtrl($scope, myService) {
$scope.usercountry = myService.userCountry().then(function(data){
return data.data.country;
});
}

Correct way to make a factory module in angularJs

I have a controller function like this:
$scope.localTimezone = function (userTimezone,datetime) {
// ....
return data;
}
What is the correct way to make it a factory module? I tried the following but it's giving errors.
angular.module('localTimezone', [])
.factory('localTimezone',function(userTimezone,datetime) {
// ...
return data;
});
angular.module('app', ['localTimezone'])
.controller('tasksController',function ($scope,localTimezone) {
// ...
});
I am missing out on some concept or logic.Can anyone please point me in the right direction?
CONTROLLER Example
Bad:
function MainCtrl () {
this.doSomething = function () {
};
}
angular
.module('app')
.controller('MainCtrl', MainCtrl);
Good:
function MainCtrl (SomeService) {
this.doSomething = SomeService.doSomething;
}
angular
.module('app')
.controller('MainCtrl', MainCtrl);
Factory Example
Bad:
function AnotherService () {
var someValue = '';
var someMethod = function () {
};
return {
someValue: someValue,
someMethod: someMethod
};
}
angular
.module('app')
.factory('AnotherService', AnotherService);
Good:
function AnotherService () {
var AnotherService = {};
AnotherService.someValue = '';
AnotherService.someMethod = function () {
};
return AnotherService;
}
angular
.module('app')
.factory('AnotherService', AnotherService);
For Detail Guidelines go through this blog :
Opinionated AngularJS styleguide for teams
Here is a working code example based on the assumption userTimezone and datetime are services which are apart of the localTimezone module.
The following has been modified
'data' which your factory is returning has been modified to return a string based on the factory pattern - as you were returning 'data' which referenced nothing
constructing the app has been moved to the top. This code should execute before anything else.
app variable removed - I don't like global variables.
Code:
angular.module('app', ['localTimezone']);
angular.module('localTimezone', []).factory('localTimezone',
function(userTimezone, datetime) {
var data = 'hello';
return { data: data } ;
});
angular.module('localTimezone').service('userTimezone', function() {
});
angular.module('localTimezone').service('datetime', function() {
});
angular.module('app').controller('tasksController',function ($scope,localTimezone) {
});
Codepen: http://codepen.io/anon/pen/wijmb (no errors appearing in console)
Take a look at http://angular-tips.com/blog/2013/08/understanding-service-types for information about the different service types in Angular.

Resources