I am new to angularjs. I am using Angular 1.5
I want to load data from server and store it to scope and use it in view file.
My data is stored in the scope after load the view file. How can I store data to scope first and than load the view file so that I can use scope data in view file.
Here is my code
$scope.getProfile = function() {
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
if($auth.isAuthenticated()){
$scope.getProfile();
console.log($scope.user)//here data not print in console.
}
Code in .then blocks execute asynchronously after the function returns.
Have the function return a promise for the value and extract that value in a .then block:
$scope.getProfile = function() {
return Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
return $scope.user;
})
.catch(function(response) {
console.log(response.data.message, response.status);
throw response;
});
};
if($auth.isAuthenticated()){
var promise = $scope.getProfile();
promise.then(function(user) {
console.log(user);
});
};
By using a promise returned by the function, a .then block can be created that will execute after the data has returned from the server.
Explaination of Promise-Based Asynchronous Operations
console.log("Part1");
console.log("Part2");
var promise = $http.get(url);
promise.then(function successHandler(response){
console.log("Part3");
});
console.log("Part4");
The console log for "Part4" doesn't have to wait for the data to come back from the server. It executes immediately after the XHR starts. The console log for "Part3" is inside a success handler function that is held by the $q service and invoked after data has arrived from the server and the XHR completes.
For more information, see How to use $http promise response outside success handler.
Demo
console.log("Part 1");
console.log("Part 2");
var promise = new Promise(r=>r());
promise.then(function() {
console.log("Part 3");
});
console.log("Part *4*");
It's because of the Async behavior, you might need to use the callbacks. Give this a try
$scope.getProfile = function(callback) { //added callback function
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
callback($scope.user); //callback execution
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
And your caller should be like following:
if ($auth.isAuthenticated()) {
$scope.getProfile(function(user){
$scope.user = user;
});
}
Hope this will help
If you want to execute some code every time an angular page loads, you could make use of ‘resolve’, as long as ‘UI-Router’ setup.
If you just want to execute some code without loading data, you are better off using ‘$viewContentLoading‘ or ‘$viewContentLoaded‘. Please note the following documentation.
You can refer here for more information
change your code as shown below:
$scope.getProfile = function() {
Account.getProfile()
.then(function(response) {
$scope.user = response.data;
console.log($scope.user); //here data printed in console
if($auth.isAuthenticated()){
console.log($scope.user)//here data not print in console.
}
})
.catch(function(response) {
console.log(response.data.message, response.status);
});
};
$scope.getProfile();
Hope this helps. :-)
Related
i am trying to get response of post/get requests , getting response successfully inside post/get,but unable to get result out of post/get .
when i print on console it is showing "undefined". any suggestions , here is my code
index.html:
<div ng-app="myApp" ng-controller="customersCtrl">{{ponies}}</div>
Angular code:
var myApp = angular.module('myApp', []);
angular service:
myApp.factory('ponyService', function($http) {
var getPonies = function() {
return $http.get('https://www.w3schools.com/angular/customers.php');
};
return {
getPonies: getPonies
};
});
myApp.controller('customersCtrl', function($scope, ponyService) {
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
console.log($scope.ponies); // here want to print data because want to use whole controller
});
That's because posts and gets are asynchronous.
Your console.log won't wait for the response.
Put your console inside success in order check it's data.
Try like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
console.log($scope.ponies);
});
or you can watch it's changes (but it's not recommended just for test purposes),
Like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
$scope.$watch("ponies",function(val){
if(val)
console.log(val)
})
It is because a $http returns a promise (async request) so if you did something like this
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
});
console.log($scope.ponies);
it will log undefined, as you are trying to log it before the request is finished.So you need to chain to that promise in any code that needs to access the resolved data.Like:
ponyService.getPonies().success(function(data) {
$scope.ponies = data;
console.log($scope.ponies);
/* access data or $scope.ponies in here */
});
or you can use promise like
ponyService.getPonies().then(function (data) {
$scope.ponies = data;
console.log($scope.ponies);
/* access data or $scope.data in here */
});
How can I access the $scope or the data obtained from success in $http outside the $http.jsonp() request?
$http.jsonp('http://example.com/?callback=JSON_CALLBACK')
.success(function(data) {
$scope.info1 = data.name;
$scope.info2 = data.company;
});
console.log("access it here outside: ",$scope.info1);
currently the console prints undefined.
Thanks for the help.
You shouldn't consider asynchronous ajax call to be work in synchronous way. You have to wait until that ajax/promise gets finished. Though don't use .success/.error they are deprecated, use .then instead to chain promise.
You must rely on the promise to promise gets resolve/reject.
Code
var promise = $http.jsonp('http://example.com/?callback=JSON_CALLBACK')
promise.then(function(response) {
var data = response.data;
$scope.info1 = data.name;
$scope.info2 = data.company;
console.log("access it here outside: ",$scope.info1);
myOtherFunction($scope.info1);
})
.catch(function(error) {
console.log(error);
});
//declaring the module
var app = angular.module("sachin", ["ng-fusioncharts"]);
//declaring a factory
app.factory('team',function(){
return {
runs_aus : ''
};
});
app.controller("myCtrl", function($scope,$http,team){
$scope.australia=[];
$scope.total_runs_aus=0;
//fetching data from JSON
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
angular.forEach($scope.sachin_data, function(value, key){
// manipulating data
if (value.opposition=="v Australia"){
if (value.batting_score=="-"|| value.batting_score == "TDNB" || value.batting_score == "DNB")
$scope.total_runs=$scope.total_runs;
else if (value.batting_score.substr(value.batting_score.length - 1) == "*"){
value.batting_score = value.batting_score.substr(1);
$scope.total_runs_aus+=parseInt(value.batting_score,10)
}
else
$scope.total_runs_aus+=parseInt(value.batting_score,10);
});
$scope.australia.push({ runs:$scope.total_runs_aus});
team.runs_aus=$scope.total_runs_aus;
//got final result in $scope.total_runs_aus
console.log(team.runs_aus);
//printing inside the scope(works fine)
});
console.log(team.runs_aus);
//printing outside the scope(can't access)
I am trying to access the total runs scored outside the
then(function()) of the get request
first I tried global variables in javascript
Now I tried using a factory Any help would be appreciated
You can use a service to store that data:
app.service('MyService', function() {
var self = {
'myString': 1,
'myObject': {},
'myArray': [],
'doSomething': function(param) {
self.myString = param
},
'anotherFunction': function() {
return true;
}
}
return self;
});
You just need to inject MyService on your controller and access it like MyService.myObject = something.
The important part to understand is that you are working async operations. The code continues to execute and prints your console logs even though the data has not been returned from $http.get(). Your code needs to account for this and run the code that operates on the data after its been resolved.
.then() expects a function as the parameter of the method signature. For example:
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
}).then(function() {
console.log('Value in scope:', $scope.sachin_data);
});
or
function processData = function() {
console.log('Value in scope:', $scope.sachin_data);
};
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
}).then(processData);
or chain multiple promises together (you must add angular's $q as a dependency):
function processData1 = function(data) {
//Create a deferred object.
var defer = $q.defer();
//Do something with data.
console.log('Value in scope:', data);
//Pass data to next promise in promise chain.
defer.resolve(data);
//Resolve data to be returned.
return defer.promise;
};
function processData2 = function(data) {
//Create a deferred object.
var defer = $q.defer();
//Do something else with data.
console.log('Value in scope:', data);
//Pass data to next promise in promise chain.
defer.resolve(data);
//Resolve data to be returned.
return defer.promise;
};
$http.get("convertcsv.json")
.then(processData1)
.then(processData2);
Please have a look at:
http://www.html5rocks.com/en/tutorials/es6/promises/
https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
The code as is may have syntax errors as it has not been tested. Links are general reference and not specific to $q but the concepts are consistent.
I have the following code in a service and I am calling fetchData function from the controller.
Service
app.service("geturl", function($http) {
urllist = [];
geturl.fetchData = function() {
var data = [];
for (i = 0; i < urllist.length; i++) {
(function(index) {
return $http.get(geturl.urllist[index], {
timeout: 8000
})
.then(function(response) {
data[index] = response.data;
});
}(i);
return data;
});
};
});
I want to write the success and error function of $http.get in the controller since it is needed in the UI, how can I go about it?
..I want to write the success and error function of $http.get in the
controller..
Usually, the .then() function takes two function arguments. The first argument is the success handler and the second as an error handler.
$http.get(url,options).then(function (response){
//success handler function
},function(error){
//error handler function
})
Alternatively, you can specify the .success and .error functions separately.
$http.get(url,options).success(function (response){
//success handler function
}).error(function(error){
//error handler function
})
UPDATE:
From your code, it seems that you intend to return something from your service geturl and providing the callbacks there itself. This is not how it is supposed to be done. You should return a promise from your service .
...
app.service("geturl",function($http){
...
getData:function(){
return $http.get(url,options);
}
...
});
...
and handle the success/error callbacks in the module where you are consuming the service
geturl.getData().success(function(){
//handle success
}).error(function(){
//handle error
})
In case you need to make multiple http requests, never ever use the for loop . Remember, everything is asynchronous and you are not guaranteed to get the response from one of the previous request before you make a new one. In such scenarios, you should use $q service. See #pankajparkar's answer for more details
Seems like you want to return a data after all the ajax gets completed, You could achieve this by using $q.all()
Service
app.service("geturl", function($http, $q) {
this.urllist = [];
this.fetchData = function() {
var data = [], promises = [];
for (i = 0; i < urllist.length; i++) {
(function(index) {
var promise = $http.get(geturl.urllist[index], {
timeout: 8000
})
.then(function(response) {
data[index] = response.data;
});
promises.push(promise); //creating promise array
}(i);
};
return $q.all(promises).then(function(resp){
return data; //returning data after all promises completed
});
};
});
I have this angular controller:
app.controller('FeedCtrl', function ($scope, Profile) {
$scope.getID = function() {
Profile.getUID()
.then(function (data) {
if (data !== null) {
console.log(data.id); // returns correct id
$scope.data = data;
} else {
console.log("Could not retrieve id");
}
}, function (error) {
console.log(error);
});
console.log($scope.data); // logs: undefined
return $scope.data; // logs: undefined
};
var somedata = $scope.getID();
console.log(somedata); //just returns undefined
});
And this Factory that the controller uses for a JSON request.
module.factory('Profile', function($http, $localStorage) {
return {
getUID:function(){
return $http.get("https://graph.facebook.com/v2.2/me", {params: { access_token: $localStorage.accessToken, fields: "id,name,gender,location,website,picture,relationship_status", format: "json" }})
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
};
});
The Question
I am unable to change the value of $scope.data for use outside the $scope.getID function but inside the rest of the FeedCtrl.
If you look on the comments you see what I am getting returned in the console logs.
I've tried to understand this problem by searching here in StackOverflow and Google but it seems that I don't understand the $scope concept of AngularJS.
I am grateful for any push in the right direction.
That's a classic mistake, the code you're calling is asynchronous, look at your console and watch the order of your logs, the log that will return the correct id will be the last one because it will be called only after the promise has been resolved.
Is this enough of a push in the right direction for you?
A very simple example, but it's the same principle.
setTimeout(function(){
document.write('A2: Timeout is done');
}, 5000);
document.write('A1: Called timeout, this gets logged before A2 even though my line number is higher.');
That is not a scope problem, it's a time problem. You are trying to use the value before it exists.
In the controller you can only use the value after the result has arrived, i.e. in the callback for the then method. The return statement runs before there is a result, so you can't return it.
Once you have made an asynchronous call, the result has to be handled asynchronously. You can return a Future object to handle the result when it arrives, but you can never make a function that makes an asynchronous call and returns the result itself.
Your code is asynchronous. I wrote a response to this exact same problem in this post.
Returning after ajax call prints false