Angular $resource, lose scope variable after function call - angularjs

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);
})

Related

AngularJS Factories - Access private variables from methods

I wrote the following factory :
.factory('UserFact', function() {
var user = [];
return {
'setUser': function(user) {
this.user = user;
console.log('(1) User set: ' + this.user);
console.log('(2) User id is now: ' + this.user.uid);
},
'updateSport': function(sportid) {
console.log('(3)Update sport ' + sportid + 'for user id ' + this.user.uid);
}
}
Use it the following way in my controller :
function ($scope, $stateParams, DatabaseFact, UserFact) {
// variables
$scope.sports = [];
$scope.sports = DatabaseFact.getSports();
// functions
$scope.updateSport = UserFact.updateSport;
// execution
UserFact.setUser({uid: '123456', name: 'forrest'});
}
And trigger it from my view through a list of trigger button :
updateSport(sport.id)
My problem is that console logs print the following :
(1) User set: [Object] Object
(2) User id is now: 123456
(3) Update sport 1 for user id undefined
Do you know why my user id is undefined in log 3?
Thanks
That makes sense to me, due to the reason of its implementation. In your controller, you are actually copying the method reference to $scope.updateSport. So whenever the method gets executed, it executes in the context of the controller and this -> $scope instance but not one the service instance.
As your controller doenst have uid, it just returns undefined.
To fix this you need to have a method body for updateSort and call UserFact.updateSport
$scope.updateSport = function(){
UserFact.updateSport();
}
I don't know how familiar you are with JavaScript, but I suspect you're being caught out by the this reference being different in your two function calls.
To debug this try logging this to the console in both functions. You should observe that they differ, which explains the cause of your problem.
The fix could be to not use the this keyword, e.g. function setUser would become:
'setUser': function(_user) {
user = _user;
}
You can find more information on JS this on Google, try https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this for a start.
It's undefined because your function uses this, but is copied from its original object (the user service) to the scope.
You can either stop to use this, and instead use the user variable that you declared and initialized to an empty array (why, BTW?), but never used anywhere else, or do
$scope.updateSport = function() {
UserFact.updateSport;
}
Note that you named your service "UserFact", but it's not a factry. It doesn't create anything. It only allows setting a user and updating its sport. That is not a factory. A factory is an object used to create things. The factory, here, is the function passed to module.factory(), and which is used to create and return the service instance, which should better be called UserService.

$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 :)

AngularJS retrieve data outside request

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.

How to loop through $resource returned query and get desired value?

I am using MEANJS
In my controller i have
// Find a list of Cars
$scope.findHome = function() {
$scope.cars = Cars.query();
console.log($scope.cars);
};
Which outputs
here i want to get the _id string inside the first array 0: Resource
I tried $scope.cars[0]._id which returns undefined, Please help.
You are inspecting the results of the query immediately after the call, but ngResource is asynchronous, so perhaps the data has not yet returned from the server by the time you are trying to access it. Try putting your access in the callback function passed to query().
$scope.cars = Cars.query(function() {
console.log($scope.cars);
console.log($scope.cars[0]._id);
});

TVRage consume service via AngularJS

i am trying to consume this webservice (http://services.tvrage.com/feeds/show_list.php) from TVRage using Angularjs.
I can 'connect' to the service (using firebug I see GET show_list.php STATUS 200 OK) but when i try to print any data from the response I get none.
This is the code that i use:
var TV_Episodes = angular.module('TV_Episodes', ['ngResource']);
TV_Episodes.controller('GetAllEpisodes', function($scope, $resource) {
var dataService = $resource('http://services.tvrage.com/feeds/show_list.php');
$scope.data = dataService.get();
console.log($scope.data());
});
any ideas on how I can just console.log the the response?
UPDATE 1:
After some more trying i found out that that i get the following error as a response from TVRAGE.
"XMLHttpRequest cannot load http://services.tvrage.com/feeds/show_list.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access."
therefor i tweaked my code so
var dataService = $resource('http://services.tvrage.com/feeds/show_list.php?key=xxxx',{},{headers: { 'Access-Control-Allow-Origin': '*' }});
but i still get the same error as before.
$resource.get() returns a promise, which means you are likely printing to the console prior to the data being retrieved. Instead use the appropriate callback function:
$scope.data = dataService.get(function() { console.log($scope.data); });
The get method is asyncronous. When it is called it returns immediately with a reference to an object (or array, if specified - but not a promise as indicated in MWay's answer). Then, later, that same reference is updated with the data that is returned from the server on success. Here's the relevant part from the documentation:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
As fast as the request might be, it won't resolve until the event loop comes around again. The resource is helpfully designed to free you up from having to worry about writing callbacks. If you need to though, the get method takes callback function parameters that will be invoked when the request resolves and the data is ready.
var TV_Episodes = angular.module('TV_Episodes', ['ngResource']);
TV_Episodes.controller('GetAllEpisodes', function($scope, $resource) {
var dataService = $resource('http://services.tvrage.com/feeds/show_list.php');
$scope.data = dataService.get(function () {
console.log($scope.data());
});
});
Or, you can access the promise used for processing the request by using *$promise", which is a property on empty instance object returned from get.

Resources