AngularJS retrieve data outside request - angularjs

I have a problem accessing data outside my service request. See my code below. The variable works within the service request. But when i want to acces the variable outside the request, i'm getting a undefined variable.
Does anyone know how to fix this?
API.getUser($scope.email, $scope.password).then(function(data) {
$scope.user_id = (data.id);
console.log($scope.user_id) // this works
});
console.log($scope.user_id); // <--- Here i'm getting undefined.

Use $apply() on scope in the callback function.
API.getUser($scope.email, $scope.password).then(function(data) {
$scope.user_id = (data.id);
$scope.$apply(); // <----- Here
console.log($scope.user_id)
});

The call to API.getUser is an asynchronous call and the code below that executes before the callback executes. That is why $scope.user_id is undefined. You can do anything you want to do with the variable inside the success callback and pass it to functions if you need to work more with this user_id.

Well, the problem is with the Javascript behavior for asyncs operations and the use of Promises ($q), when the interpreter run the code, does something like this:
1) Make this ajax request (An async operation), and return a Promise
API.getUser($scope.email, $scope.password)
2) Register the function in the Promise, to be executed when the operation ends
.then(function(data) {
$scope.user_id = (data.id);
console.log($scope.user_id) // this works
});
3) Print the current value of $scope.user_id
console.log($scope.user_id);
Print undefined because in this moment the Async operation are not finished
4) On some time the Async operation finish and execute this code
$scope.user_id = (data.id);
console.log($scope.user_id) // this works
In the last part the $scope.user_id was set, and the console.log print the correct value.

Related

Angular $resource, lose scope variable after function call

var createAttendances = function(){
var stud = StudentResource.get(function(data){
$scope.students = data.students;
console.log($scope.students);
});
console.log(stud.students);
console.log($scope.sudents);
};
inside resource get function it prints out Array of two objects (which is good)
outside resource get it prints out undefined
it sees stud object but when i query to students params it returns undefined
as u can see main problem is to get $scope.students or data.students ouside StudentResouce.get func
StudentResource.get
is an async call, which means the lines below it can get executed even before the Resource GET call is completed, that is the reason why your variables are returning undefined outside the callback.
to access the data you fetched through GET call, you have to query it inside the call back itself.
This is an async call, so you can get result in this way, I got the same confusion in the beginning too.
StudentResource.get().$promise.then(function (result) {
$scope.students = result.students;
console.log($scope.students);
})

$scope variable is undefined when it is set inside a function

I have the following example code in my learning app. The service does his job and pulls some data out of a page with json code generated by php, so far so good.
service:
(function() {
'use strict';
angular
.module('app.data')
.service('DashboardService', DashboardService);
DashboardService.$inject = ['$http'];
function DashboardService($http) {
this.getFormules = getFormules;
////////////////
function getFormules(onReady, onError) {
var formJson = 'server/php/get-formules.php',
formURL = formJson + '?v=' + (new Date().getTime()); // Disables cash
onError = onError || function() { alert('Failure loading menu'); };
$http
.get(formURL)
.then(onReady, onError);
}
}
})();
Then i call the getFormules function in my controller and put all the data inside my $scope.formuleItems and test if everything succeeded and 'o no'... $scope.formuleItems = undefined! - Strange because my view is showing data?
part of the controller:
dataLoader.getFormules(function (items){
$scope.formuleItems = items.data;
});
console.log('+++++++++++++++++', $scope.formuleItems); // gives undefined
The first thing i did was search around on stackoverflow to look if someone else had the same issue, and there was: Undefined variable inside controller function.
I know there are some walkarounds for this, i've done my own research, but something tells me that this (see example below) isn't the best way to solve this problem.
solution one: put $watch inside of the controller
$scope.$watch('formuleItems', function(checkValue) {
if (checkValue !== undefined) {
//put the code in here!
}
}
or even:
if($scope.formuleItems != null) {}
The rest of the controller is relying on $scope.formuleItems. Do i really have to put everything into that $watch or if? Can i fix this with a promise? I never did that before so some help would be appreciated.
The code in your callback
function (items){
$scope.formuleItems = items.data;
}
is evaluated asynchronously. That means you first fire the request, then javascript keeps on executing your lines of code, hence performs
console.log('+++++++++++++++++', $scope.formuleItems); // gives undefined
At this point the callback was not invoked yet, because this takes some time and can happen at any point. The execution is not stopped for this.
Therefore the value of $scope.formuleItems is still undefined, of course.
After that - at some not defined time in the future (probably a few milliseconds later) the callback will be invoked and the value of $scope.formuleItems will be changed. You have to log the value INSIDE of your callback-function.
You urgently have to understand this concept if you want to succeed in JavaScript, because this happens over and over again :)

$scope variable not set from Factory

I'm new to Angular
I'm trying to pass some data into a controller from a factory method. I can see the the data when I log the Factory variable. I try to pass the data to a $scope variable ($scope.song) but outside of the method, the $scope variable is undefined. What am I doing wrong? Code Below:
.controller('MessagesCtrl', function($scope, FetchSong){
FetchSong.nextSong('audio-message')
.then(function(response){
$scope.song = FetchSong.queue;
console.log(FetchSong.queue); //logs the data
console.log(response.data); //also logs the data
});
console.log($scope.song); //returns undefined
})
Here is the timeline of the execution of the code:
// t0: ask the service for the next song: the service sends an HTTP
// request (I guess) to get it
FetchSong.nextSong('audio-message')
.then(function(response){
// t0 + 3 seconds: the http message has reached the server 10,000
// miles away from here, the server got the next song from its
// database, and sent it back. It took some time to travel the 10,000
// miles in the other direction, but it finally arrived, so we can
// store it in the scope
$scope.song = FetchSong.queue;
console.log(FetchSong.queue); //logs the data
console.log(response.data); //also logs the data
});
// t0 + 1 microsecond: try to print the next song
console.log($scope.song); //returns undefined
The key thing to realize is that, every time a service returns a promise on which you call then() and pass a callback function, it means it can't just return the value now. It returns... a promise that will be resolved later, because some work needs to be done asynchronously before the result can be available.
So, printing the result immediately after you called the service and got the promise back will never work. The result is only available once the callback function has been called, later.
I have written a blog post explaining how promises work and how to avoid traps like the ones you fell into.
The issue is, you try to access $scope.song before it been assigned value in FetchSong.nextSong promise callback, since promise is asynchronous, all code related to a promise return data should be put in its callback, see doc:
.controller('MessagesCtrl', function($scope, FetchSong){
FetchSong.nextSong('audio-message').then(function(response){
$scope.song = FetchSong.queue;
console.log(FetchSong.queue); //logs the data
console.log(response.data); //also logs the data
}).then(function(){
console.log($scope.song); //returns FetchSong.queue
});
})
you should use $scope.$apply(); see more in https://docs.angularjs.org/api/ng/type/$rootScope.Scope

angular js code in .then function executed before promise finishes

hmmm, i am stuck on this for a while, hopefully i can get some hints from you guys.
i put some sample code here to illustrate the issue:
http://jsfiddle.net/HB7LU/18216/
so basically, i am expecting console.log('out put data for member ' + number); get executed right after mySvc.get() rest call finishes every time i click on the member item.
$q.all([
mySvc.get({id: number})
]).then(function() {
console.log('out put data for member ' + number);
});
but it is not the case, it only works as expected the first time you click on it. second time you click on it, the opposite happens.
XHR finished loading: GET "http://fiddle.jshell.net/HB7LU/18216/show/test?id=1"
(index):53 loading data - rest call finished
(index):68 out put data for member 1 <- this is correct
(index):68 out put data for member 2 <- this is wrong, should wait till rest call finishes
XHR finished loading: GET "http://fiddle.jshell.net/HB7LU/18216/show/test?id=2
(index):53 loading data - rest call finished
ps: i tested it in chrome. havent tested it in other browsers
please let me know how i can fix it. thanks!
You are returning the same deferred each time instead of creating a new one, if you moved the creation of the deferred inside the get call or just returned the promise from the $http call it works fine
myService.get = function(requestParams) {
var deffered = $q.defer();
http://jsfiddle.net/jc04arnn/
You need to create a new deferred each time they call .get(). See the corrected code. Because you can only resolve a deferred once, your resolving it multiple times has no event. It only resolves it the first time. After that, any time it returns that promise, it will immediately fire the .then, cause the deferred is already resolved.
myService.get = function(){
var deffered = $q.defer();
http://jsfiddle.net/8qLrnz5o/
Other solution is return the promise that $http creates (first put the callback and then return the promise) :
myService.get = function(requestParams) {
var call = $http({
method: 'GET',
url: TEST_DATA_URLS,
params: requestParams
});
call.success(function (msg) {
console.log('loading data - rest call finished');
});
return call;
};
when you call mySvs.get you have the same promise:
mySvc
.get({id: number})
.then(function() {
console.log('out put data for member ' + number);
});
Here is the fiddle:
http://jsfiddle.net/tmbs0b1L/

asynchronous calls inside for loop angularJs

I'm trying to make a call to a function 'submittoServer' which is inside factory 'pService', which makes $http call and then broadcast the data. The call to the 'submittoserver' is happening inside a for loop. Problem here is that I couldn't see the actual call is being made until the last loop, which is sending only the last item, but as you see in the code below I want to update one particular variable after every call, can someone please suggest how can I don't that. I can't do call back here as I've other method that call this same factory function with different inputs.
for (var i = vr.lines.length - 1; i >= 0; i--) {
if (parseInt(vr.lines[i].id) === id && Boolean(vr.lines[i].IsVoided) != true) {
lineId = vr.lines[i].lineID;
pService.submitToServer(actionId, { "IData": id }, ineId)
linesRemoved = linesRemoved + 1;
}
if (linesRemoved === lineqty)
{
updateModel = true;
}
}
The problem here is that your service is a promise to return data. Your function will keep looping and running before the promise is resolved. You need to refactor your loop to take this into account.
Either add a .then(fn(){}) to handle the resolve promise. Gather up all the changed lineIds and submit them all at once and (again) handle the resolved promise with a .then(fn(){}). Lastly, given you next set of code logic, you probably want to do something more like $q.all to wait on all promise(s) to resolve before moving forward (see Wait for all promises to resolve)
Example
before your for loop:
var self=this;
self.linesRemoved = 0; // or init as needed.
Inside your for loop.
pService.submitToServer(actionId,{data}).then(function(resp){
self.linesRemoved++; // shortcut, this does +1 to itself.
});
Why do you have update model? With Angular your data is two-way bound and should just react to it being changed.
Sample $http call with return in a service, this is a promise itself:
return $http.post(url, data, { cache: true });
Use this in a controller like
service.callHttp(data).success(function(resp){
self.linesRemoved++;
}).error(function(resp){});
If you have to wait it might be better to hold all and wait until they are all finished.
var promises =[];
for(){
promises.push(service.callHttp());
}
$q.all(promises).then(function(){
// do work if(self.linesRemoved==lineQty)
// update... You can't evaluate until they are all finished right?
});

Resources