I have a json file. I want to get the data from that file using $http.get and store that in variable so that I can use it later in the controller. Something like this:
$http.get('items.json').success(function(response){
var data = response; //data can't be used outside this function
})
I want to use data outside the function.
You can do it in the below fashion:
var data;
$http.get('items.json').success(function(response){
data = response; //data can't be used outside this function
})
here data now will be accissible to all the methods of your controller.
But my suggestion is to make one angular service and put $http code inside it. And then inject this service
inside your controller and use it.
Below would be the code:
Service Code:
app.service('MyService', function($http) {
this.getData = function(successHandler, failureHandler) {
$http.get('items.json').then(function(response){
successHandler(response); //data can't be used outside this function
}, function(response) {
failureHandler(response);
})
}
});
Controller Code:
app.controller('MyCntrl', function($scope, MyService) {
var data;
function successHandler(res) {
data = res;
}
function failureHandler(res) {
data = res;
}
$scope.getData = function() {
MyService.getData(successHandler, failureHandler);
}
});
The above solution would help you to separate out the concerns related to service and controller and to make your application
more modular and maintainable.
You can create data outside that function. like
var data;
$http.get('items.json').success(function(response){
data = response; //data can't be used outside this function
});
But in this way also data will be undefined unless get call gives response, evenif you are using JSONP from local.
Ideal way to do this is using promises. as below
var callService = function(){
return $http.get('items.json').success(function(response){
return response; // Response variable will be input to promise
});
};
callService.then(function(data){
// this data variable will be equal to response.
});
Further reading on
https://docs.angularjs.org/api/ng/service/$q
dont create a variable inside call, declare that variable outside and just assign value for it.
var data;
$http.get('items.json').success(function(response){
data = response; //data can't be used outside this function
});
as all mentionned create the variable outside the function.
BUT USE THEN instead of success because it is depreceted
Deprecation Notice
The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
var data;
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
console.log(reponse); // response contain status , data, headers, config...
data = response.data ;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Related
I am trying to call a web service using ajax and then pass the results to an angular controller. I cannot get the values out of the callback function to pass into a scope variable. I think it's just my bad understanding of how the callback function works.
here is the code:
function ajaxKimono(callback) {
$.ajax({
url:"https://www.kimonolabs.com/api/cveeggn4?apikey=NWYzkeJpFDtb4aOYd6yD96L5PdLuZHjo",
crossDomain: true,
dataType: "jsonp",
success: callback,
error: function (xhr, status) {
//handle errors
console.log(xhr);
console.log(status);
}
});
};
angular.module('app').controller('gifCtrl', function(){
var self = this;
var gifs = [];
ajaxKimono(function(result){
var collection = result.results.collection1;
$.each(collection, function(i, item){
gifs.push({ gif: item.property5.href});
});
//this outputs the correct data
//so i know the ajax call is working correctly
console.log(gifs);
self.gifCollection = gifs;
});
//something about the scope is messing me up
//this outputs nothing...
console.log(self.gifCollection);
});
As mentioned in the comments, I guess the problem is that your console.log is called before your request has finished.
Place your http request in a separate factory or service. This makes testing and re-use easier. Note the use of angular's $http shortcut methods which returns a promise:
app.factory('DataService', function($http) {
var getValues= function() {
return $http.jsonp("/api/...") // returns a promise
};
return {
getValues: getValues
}
});
And then in your controller:
myApp.controller('MyController', function ($scope, DataService) {
DataService.getValues().then(
function(){
// successcallback
},
function(){
// errorcallback
})
});
Note that I have not implemented the above code, but should provide you with an outline
I have created a function expression and assigned it to scope, the idea being that the function will initiate an $http request, get a property and then return it.
$scope.getRequestDigest = function () {
var url = urlParams['SPAppWebUrl'] + '/_api/contextinfo';
$http.post(url)
.success(function (res) {
return res;
});
}
However when I call $scope.getRequestDigest() it simply returns undefined, presumably because the ajax call hasn't completed yet. Is there any way to delay the return until the $http request is complete? I've tried using the .success() promise but that doesn't seem to work.
$http.post returns a promise (see $q). In order to use the result, bind res to $scope.res:
controller:
$scope.getRequestDigest = function () {
var url = urlParams['SPAppWebUrl'] + '/_api/contextinfo';
$http.post(url)
.success(function (res) {
$scope.res = res;
});
}
Then, you can use $scope.res (or res in the template) anywhere you'd like.
After the promise chain is resolved (after success), Angular will run a digest cycle and rebind everything on $scope.
Try
$scope.getRequestDigest = function () {
var url = urlParams['SPAppWebUrl'] + '/_api/contextinfo';
return $http.post(url);
}
var digestPromise = $scope.getRequestDigest();
digestPromise.then(function(response){
console.log(response.data);
});
This way you are actually returning a promise, which AngularJS implements through the $q service.
If you were to output (console.log(digestPromise)) digestPromise, you will see that you can all sorts of functions on it, like success or complete, for example.
You could use chain promise using .then
$scope.getRequestDigest = function () {
var url = urlParams['SPAppWebUrl'] + '/_api/contextinfo';
return $http.post(url) //this will return a promise
.then(function (res) {
return res.data; //on success this will return a data to caller function
});
}
Then the caller function will have call the function and get the data like this
$scope.getRequestDigest().then(function(data){
console.log(data)
//here you can get data returned from `getRequestDigest` method
})
Please forgive me if this is a simply problem for an angular guru, i am fairly new to services.
Below is a snippet of my controller where i have attempted make a service request to call out data from my JSON file "jobs.json".
I am not receiving an data when i load my web page neither i am seeing the JSON file in inspector element.
I assume there's something incorrect in my below code. Does anyone what the issue is?
Click here if you need to play about with the code
"use strict";
var app = angular.module("tickrApp", []);
app.service("tickrService", function ($http, $q){
var deferred = $q.defer();
$http.get('app/data/items.json').then(function (data){
deferred.resolve(data);
});
this.getItems = function () {
return deferred.promise;
}
})
.controller('tickCtrl', function($scope, tickrService) {
var promise = tickrService.getItems();
promise.then(function (data){
$scope.items= getData;
console.log($scope.items);
});
In your Plunkr, you had a few errors, such as the <script> tags around the wrong way (you need to have Angular first, so your code can then use angular.module). You also had the wrong attribute of ng-app-data instead of data-ng-app.
The key problem was with the JS code, the first parameter to the success handler for the $http.get() call is an object with a data property, which is the actual data returned. So you should resolve your promise with that property instead.
Then in the controller, like Michael P. said, getData is undefined, you should use the data parameter passed in.
app.service("tickrService", function($http, $q) {
var deferred = $q.defer();
$http.get('jobs.json').then(function(response) {
deferred.resolve(response.data);
});
this.getjobs = function() {
return deferred.promise;
}
})
.controller('tickCtrl', function($scope, tickrService) {
var promise = tickrService.getjobs();
promise.then(function(data) {
$scope.jobs = data;
console.log($scope.jobs);
});
});
See forked Plunkr.
In the success handler of your getItems function, you are storing getData, which is undefined. You want to store data instead.
Therefore, in the controller, your call to getItems() should be as follows
tickrService.getItems().then(function (data) {
$scope.items = data;
});
Also, you want to make the $http call in getItems. Like that :
this.getItems = function () {
var deferred = $q.defer();
$http.get('app/data/items.json').then(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
However, you can avoid the above boilerplate code around the promises, because $http.get returns itself a promise. Your service and controller could be much more concise and less polluted by boilerplate code.
The service could be as simple as :
app.service("tickrService", function ($http) {
this.getItems = function () {
return $http.get('app/data/items.json');
}
});
And the controller could be shortened to:
app.controller('tickCtrl', function ($scope, tickrService) {
tickrService.getItems().then(function (response) {
$scope.items = response.data;
})
});
Please note that the response resolved by $http is an object that contains (link to doc) :
data – The response body transformed with the transform functions.
status – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – The configuration object that was used to generate the request.
statusText – HTTP status text of the response.
Therefore in the success handler of getItems we are storing response.data, which is the response body, and not the whole response object.
Recently I started learning AngularJS. My problem is as follows.
I cannot access the data returned by $http.get() out side the method call.
Code :
(function(){
var productApp = angular.module('productApp', []);
productApp.controller('ProductController', ['$http', function($http){
var store = this;
store.products = [];
$http.get('http://localhost:8080/VeggieFresh/veggie/product/1')
.success(function(data){
store.products = data;
console.log(data);
});
console.log(store.products);
}]);
})();
When I print data inside $http.get() method, it could be printed without any problem, but when i try to print it outside method; it displays empty array.
I guess because of this I cannot access this data on HTML as well.
Any help in this regards is highly appreciated.
Since $http success is a asynchronous call you wont get data immediately outside the function you can call a function for "success" function , or use a callback function
As far as your code is concerned, you can save data on $scope variable
$http.get('http://localhost:8080/VeggieFresh/veggie/product/1')
.success(function(data){
$scope.store.products = data;
//console.log(data);
});
The success function runs async, so you will get the result inside success function.
Following code worked for me.
productApp.controller('ProductController', ['$http', function($http){
var store = this;
store.products = [];
var promise = $http.get('http://localhost:8080/VeggieFresh/veggie/product/1');
promise.success(function(data){
store.products = data;
});
}]);
I'm trying to store some user data in a service that will be accessible and modified across different controllers, and the data will be initially pulled via a $http call. Since the data has to be loaded, I've used promises in my previous code, but this can be quite irritating to write. For instance, even a basic getter function has to be written as the following
UserData.getData().then(function(data) {
//do something with the data
})
where UserData.getData() always returns a promise via deferred.promise (if the data has already been pulled, then resolve immediately). I'm wondering if there is anyway to split a) $http calls, and b) getter and setter methods into two different services so that if I call getter and setter methods from b), I don't need to wrap everything with then?
For instance, I'm trying to make UserFactory in charge of the $http call, and UserData in charge of getters and setters. However, I can't get the code to work since UserData.getData() will return undefined, and wondering if anyone can help? (I don't really want to have to use then everywhere).
angular.module('testApp', [])
//mocks a service that gets data from a server
.factory('UserFactory', function($timeout, $q) {
return {
getData: function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve({title: 'hello world'});
}, 1000);
return deferred.promise;
}
}
})
.factory('UserData', function(UserFactory) {
var data;
return {
//if already pulled, use existing data
getData: function() {
if (data) return data;
UserFactory.getData().then(function(res) {
data = res;
return data;
})
}
}
})
http://jsfiddle.net/QNLk2/1/
The then method is executed asynchronously so the return method as no effect there. That is why until the data has arrived every call to getData will return undefined.
You can try the following approach, where you can specify a callback if you want to be notified when data is ready, or simply wait for the data to be populated in the return variable.
.factory('UserData', function(UserFactory) {
var data = {};
return {
getData: function(callback) {
UserFactory.getData().then(function(res) {
angular.extend(data, res);
if (callback) {
callback(data);
}
});
return data;
}
}
})