Why is $http.get() undefined in my Angular service? - json

I'm trying to load some JSON and store it using $rootScope so that it persists between controllers. When I run my app I get the following error:
TypeError: Cannot call method 'get' of undefined
The get method was working perfectly until I tried to introduce $rootScope... any ideas?
My service looks like this:
1 /**
2 * Service to get the quiz data from a JSON source
3 */
4 app.factory('quizService', ['$rootScope', function ($scope, $rootScope, $http) {
5 var promise;
6 var service = {
7 getQuiz: function($scope, $http) {
8 if ( !promise ) {
9 promise = $http.get('QuizFileName.quiz').then(function (response) {
10 return response.data;
11 });
12 }
13 return promise;
14 }
15 };
16 return service;
17 }]);
My controller looks like this:
7 // Get Quiz data from service
8 quizService.getQuiz().then(function(data) {
9 $scope.quiz = data;
10
11 // Redirect to scores if already completed this
12 if($scope.quiz.complete === true) {
13 $location.path('scores');
14 }
15 });

You are using the 'array pattern' in defining your factory. You should have a string for each of the services you use in your function, but you only have one.
That is, what you do is
app.factory('quizService', ['$rootScope', function ($scope, $rootScope, $http) {
//insert code
}]);
but what you should do is
app.factory('quizService', ['$scope', '$rootScope', '$http', function ($scope, $rootScope, $http) {
//insert code
}]);
AngularJS will map the functions named with the strings to the parameters. Try that and see if it fixes your issue.
EDIT: Ah,the answer from Reboog711 makes more sense in solving the issue, I somehow missed the latter part of the code. But I'm leaving this answer in since you should also fix the factory definition.

getQuiz is a function inside a factory:
getQuiz: function($scope, $http) {
When you call the getQuiz, you do not pass any arguments into it:
quizService.getQuiz()
$http is undefined because you call it without passing any arguments into it. Angular will not inject items into a function that you call manually. It will only do so with functions that AngularJS calls itself--such as controller or factory functions.
So, you have a few options. One is to pass the $scope and $http arguments into the function, like this:
quizService.getQuiz($scope, $http)
I'm sure this would solve the issue, but it would be a weird approach for sure.
I would probably remove the $scope and $http functions out of the function definition:
getQuiz: function() {
Then make sure that you modify your factory definition:
app.factory('quizService', ['$scope','$rootScope','$http', function ($scope, $rootScope, $http) {
Without this modification, the Angular services will not be passed into your function.
Then, when you access $http inside the function, it should access the value passed into the factory which should not be undefined.

OK, Reboog711 put me on the right track, I needed to modify my factory definition to include $http, I had previously tried to do this, but mistakenly put it together like this:
'$rootScope, $http'
Don't do this, it's bad and wrong! But Reboog711's answer also gave me errors because I think you can't use $scope in the way we both thought.
The correct (or working) solution was:
app.factory('quizService', ['$rootScope', '$http', function ($rootScope, $http) {
I hope this helps other newcomers to Angular. Many thanks to all who replied with their comments. I really respect this community for its great attitude to helping others :)

Related

Angular factory with $http [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am writing a factory that calls a JSON feed and returns the results.
Here is the factory using $http
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var locations = "Not sure why it don't work";
$http.get('/json/locations/').then(function(res){
locations = res.data;
});
return locations;
});
When I include this in the controller I get the first version of the locations variable. It's like there are 2 different scopes here. I am pretty sure that's my problem but I don't know why.
Here is me calling and printing out the console.log for the controller.
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
$scope.locationResponse = "Find your location";
$scope.locations = allTheLocationsFactory;
console.log($scope.locations);
});
What I need to know is why I have multiple scopes in my factory and how to fix it.
If anyone is interested the JSON data looks like this.
[
{
"Name":"#########",
"ID":#########,
"address1":"#########",
"address2":"#########",
"city":"#########",
"state":"#########",
"zip":"#########",
"phoneNumber":"#########",
"thumbnail":[
"#########",
#########,
#########,
#########
],
"permalink":"#########",
"weekdayHours":"#########",
"saturdayHours":"#########",
"sundayHours":"#########",
"coords":{
"longitude":"#########",
"latitude":"#########"
},
"options":{"animation":#########}
}, ......
You are dealing with asynchronous call, that gets data asynchronously for you. In this Your factory should return $http promise & you could get that promise inside your controller and put .then function, That will get call when the factory $http returns a locations from it success callback.
Factory
nearestLocationApp.factory("allTheLocationsFactory", function($http){
return $http.get('/json/locations/').then(function(res){
return res.data;
});
});
Controller
nearestLocationApp.controller("getTheLocation", function($scope, allTheLocationsFactory){
allTheLocationsFactory.then(function(data){
$scope.locations = data;
console.log($scope.locations);
})
});
Your factory instance should ideally return a promise instance that can be resolved either within a controller or ideally within a routers resolve option.
nearestLocationApp.factory("allTheLocationsFactory", function($http){
var jsonURL = '/json/locations/',
getLocations = function(){
return $http.get(jsonURL).then(function(result){
return result.data;
});
};
return {
getLocations: getLocations
};
});
Then within your application config or router something like;
var nearestLocationsApp = angular.module('myApp', [
'ngRoute'
])
.config(function($routeProvider) {
$routeProvider.when("/", {
templateUrl: "templates/someTemplate.html",
controller:'SomeCtrl',
controllerAs: 'ctrl',
resolve: {
locations: function(allTheLocationsFactory) {
return allTheLocationsFactory.getLocations();
}
}
});
});
And within your controller something similar to;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
'locations',
function($scope, allTheLocationsFactory, locations) {
$scope.locations = locations;
}
]);
Or without using the resolve option in your router;
nearestLocationApp.controller('someController', [
'$scope',
'allTheLocationsFactory',
function($scope, allTheLocationsFactory) {
allTheLocationsFactory.getLocations().then(function(res) {
$scope.locations = res;
});
}
]);
The former option is one I personally prefer rather to relying on promises within the controller. You can check out some other useful angular tips here
Hope some of that helps you out!

Angular factory $resource returns no value

I have recently downgraded my angular app from 1.3 to 1.2 as the client needs to support IE8.
My factory resource function was working in 1.3 but now the $values array is not seen in the returned JSON response.
Here is what the factory function looks like:
offersController.factory('Offer241GetAll', function ($resource, config) {
return $resource(config.apiUrl + '/TwoForOne/GetAll');
});
And the controller that calls the method:
offersController.controller('offers241Controller', function ($scope, Offer241GetAll) {
Offer241GetAll.get(function (data) {
$scope.offers = data.$values;
});
});
data.$values should contain an array but data only contains:
$promise: Object
$resolved: true
Strangely this $http.get() method works and I have confirmed that values are being sent by the API:
$http.get(config.apiUrl + '/TwoForOne/GetAll').then(function(r){
$scope.offers = r.data.$values;
});
How can I continue to use my resource function like before in version 1.3?
Are there any differences to how this works in different versions of angular?
$http and $resource methods works differently.
$http get method returns a promise.
$resource method Offer241GetAll.get returns to you an object with promise and state of promise.
You can try something like this:
offersController.controller('offers241Controller', function ($scope, Offer241GetAll) {
Offer241GetAll.get().$promise.then(function (data) {
$scope.offers = data;
});
});
More about this you can find here

Angular service/factory return after getting data

I know this has something to do with using $q and promises, but I've been at it for hours and still can't quite figure out how it's supposed to work with my example.
I have a .json file with the data I want. I have a list of people with id's. I want to have a service or factory I can query with a parameter that'll http.get a json file I have, filter it based on the param, then send it back to my controller.
angular
.module("mainApp")
.controller('personInfoCtrl',['$scope', '$stateParams', 'GetPersonData', function($scope, $stateParams, GetPersonData) {
$scope.personId = $stateParams.id; //this part work great
$scope.fullObject = GetPersonData($stateParams.id);
//I'm having trouble getting ^^^ to work.
//I'm able to do
//GetPersonData($stateParams.id).success(function(data)
// { $scope.fullObject = data; });
//and I can filter it inside of that object, but I want to filter it in the factory/service
}]);
Inside my main.js I have
//angular.module(...
//..a bunch of urlrouterprovider and stateprovider stuff that works
//
}]).service('GetPersonData', ['$http', function($http)
{
return function(id) {
return $http.get('./data/people.json').then(function(res) {
//I know the problem lies in it not 'waiting' for the data to get back
//before it returns an empty json (or empty something or other)
return res.data.filter(function(el) { return el.id == id)
});
}
}]);
The syntax of the filtering and everything works great when it's all in the controller, but I want to use the same code in several controls, so I'm trying to break it out to a service (or factory, I just want the controllers to be 'clean' looking).
I'm really wanting to be able to inject "GetPersonData" to a controller, then call GetPersonData(personId) to get back the json
You seems to be syntax issue in your filter function in the service.
.service('GetPersonData', ['$http', function($http){
return function(id) {
return $http.get('./data/people.json').then( function (res) {
return res.data.filter(function(el) { return el.id == id });
});
}}]);
But regarding the original issue you cannot really access the success property of the $q promise that you are returning from your function because there is no such property exist, It exists only on the promise directly returned by the http function. So you just need to use the then to chain it through in your controller.
GetPersonData($stateParams.id).then(function(data){ $scope.fullObject = data; });
If you were to return return $http.get('./data/people.json') from your service then you will see the http's custom promise methods success and error.

Angularjs $resource and $http synchronous call?

I want write two services one with a $http.get method and one with $resource
This service should receive a Json Object and looks like this, at the moment this code is direct in my controller and not in a service:
var csvPromise= $http.get(base_url + 'DataSource/1').success(function(data) {
$scope.data4=JSON.stringify(data);
});
The problem is, I want save received data in $scope.data4 and I want use this data after the $http.get call but the value is empty.
Direct after this call there is and Object that needs this value:
new myObject($scope.data4)
so myObject must wait so long until the data has arrived.
or can I make a synchronous call with $http or $resource ?
How can i do this ? I have found so many examples with promise and .then but nothing has worked for me.
EDIT: I have now written a service but it didn`t work:
var test=angular.module('myApp.getCSV', ['ngResource']);
test.factory('getCSV',function($log, $http,$q, $resource){
return {
getData: function (id) {
var csvPromise= $http.get(base_url +'DataSource/'+id)
.success(function(data) {
return data;
});
return csvPromise;
}
}
});
and then in my controller I call this:
getCSV.getData(1).then(function(theData){
$scope.data4=JSON.stringify(theData);
new myObject( $scope.data4); });
but this did not work. I thought if the $http.get receives the data then the then Function is called.
I don't believe you can do synchronous calls. That said, you have at least two options:
1) Pass in the data using the $routeProvider resolve feature. From the documentation:
An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected
An example on how to use this:
$routeProvider
.when('/your/path', {
templateUrl: '/app/yourtemplate.html',
controller: 'yourController',
resolve: {
data: ['$route', '$http', function($route, $http) {
return $http.get(base_url +'DataSource/1');
}]
}
})
And then in your controller:
app.controller('yourController', ['$scope', 'data', function($scope, data) {
$scope.data4 = JSON.stringufy(data);
var yourObj = new myObject($scope.data4);
}]);
2) The second option is to use promises and only instantiate your new myObject($scope.data4) once the promise successfully completes.
Your code needs to be changed just a bit:
$scope.data4 = '';
var csvPromise= $http.get(base_url +'DataSource/1');
csvPromise.then(function(data){
$scope.data4 = JSON.stringify(data);
}, function(data){
//error handling should go here
window.alert(data);
});
This should give you what it sounds to me like you need.
As i know, there's no way to sync~ call the http or resource. They're hard coded on AngularJS core file :
xhr.open(method, url, true);
And you don't want to hurt your users too by blocking the browser wait the data arrived. You'll better show how you make the nothing has worked for me so we can start working to fix it.
Have you try call new myObject($scope.data4) inside success method?
$http.get(...).success(function(data){
$scope.data4 = JSON.stringify(data); // I've no idea why do you need this.
var stuff = new myObject($scope.data4); // THis is now your.
});

Angularjs - Update JSON

I'm very new to Angularjs and am having issues figuring out how to update a $scope element I created from JSON. Basically I have a service that contains the function which grabs the JSON:
app.service('JSONService', function($http){
return{
getJSON: function(){
return $http.get('posts.json')
.then(function(response){
return response.data;
});
}
};
});
I then have a Controller that contains a function that gets the JSON data on button click and puts it in $scope.data and a second function that I would like to use to update $scope.data:
app.controller('PostController', function PostController($scope, JSONService){
$scope.data;
$scope.getJSON = function(){
$scope.data = JSONService.getJSON();
};
$scope.addPost = function(){
// Add to $scope.data
};
});
Currently, I successfully grab the JSON data and am able to use it to populate aspects of my view, but I am stuck on how to proceed with updating $scope.data so that:
It actually updates
The update is reflected in my view
I have tried $broadcast, $scope.data.push, $scope.data.posts.push. These have either flat out not worked or given errors. I'm sure it might be a simple answer, but I feel I may be inexperienced with Angularjs and JSON to pick up on it. Thanks in advance.
So I think there are a couple issues with the code above. Hopefully this can help you get it straightened out:
The $http.get() function returns a "promise". Promises have a then() function, which you are using, but you should probably adjust to take the data that gets returned and put it straight into $scope. Doing a "return" statement inside the then() in your service does not really have anywhere to go at that point since the request was async. Angular knows how to work with promises, so you can bind to the data in the UI, but you will actually not find the data directly under $scope.data. $scope.data will still be a promise object, and the data will be in another property (something like $scope.data.promiseData -- don't remember exactly what the property is though). You could adjust like this:
app.service('JSONService', function($http){
return {
getJSON: function() {
return $http.get('posts.json');
}
};
})
Controller:
app.controller('PostController', function PostController($scope, JSONService){
$scope.data;
$scope.getJSON = function(){
JSONService.getJSON()
.then(function (response) {
$scope.data = response.data;
});
};
$scope.addPost = function(postText){
// Add to $scope.data (assuming it's an array of objects)
$scope.data.push({postText: postText});
};
});
HTML:
<div data-ng-repeat="post in data">{{post.postText}}</div>
<input type="text" ng-model="newPostText">
<button type="button" ng-click="addPost(newPostText)">Add Post</button>
Actually, whilst the above code is correct, in this case, the getJSON function isn't actually called anywhere, so the $scope.data is never populated.