From your plunker code you have a service which looks like this:
angular.module('plunker');
.service('myService', function($firebaseRef, $firebaseObject){
this.getUserData = function(el) {
$firebaseObject($firebaseRef.users.child(this.localStorage().uid)).$loaded(function(data) {
el(data);
})
}
});
and a controller like this:
app.controller('MainCtrl', function($scope, myService) {
myService.getUserData(function(response) {
$scope.uid = response;
})
console.log($scope.uid);
$scope.postRequest = function(val) {
$firebaseArray($firebaseRef.requests.child($scope.uid)).$add(val);
console.log(val)
console.log($scope.request);
}
});
The problem is that the line console.log($scope.uid);
prints undefined
.
You are thinking in the terms of a standard blocking programming, but in this case the call to getUserData
is non-blocking which means that you don't wait for the response
, instead you only send the request to the server (Firebase) and continue to the next statement which is console.log
.
The callback function(response) { $scope.uid = response; }
will be invoked when the client reads success response (HTTP 2xx) returned by the server. This takes at least the time request travels to the server and response to travel back + the time it takes for the server to actually get the data. For example 150ms.
So, basically at the time the console.log
statement is executed, the response
callback was still not invoked, ie. the $scope.uid
is not set which means that the console.log
will print undefined
.
To resolve this you need to execute your code, which depends on the response from the server, in the callback itself. For example something like this:
app.controller('MainCtrl', function($scope, myService) {
myService.getUserData(function(response) {
$scope.uid = response;
console.log($scope.uid);
// and any other code which depends on the $scope.uid
});
// ...
});
The cool factor would be to use AngularJS promises via $q
service. For example, you could redefine your service like this:
angular.module('plunker');
.service('myService', function($q, $firebaseRef, $firebaseObject){
var deferred = $q.defer();
this.getUserData = function(el) {
$firebaseObject($firebaseRef.users.child(this.localStorage().uid)).$loaded(function(data) {
deferred.resolve(data);
});
};
return deferred.promise;
});
then in your controller you can use your service method like this:
app.controller('MainCtrl', function($scope, myService) {
myService.getUserData()
.then(function(data) {
$scope.uid = data;
console.log($scope.uid);
// and any other code
// you can also return promises here and then chain
// them, read about AngularJS promises
});
// ...
});
This is basically same as the example before, but with added benefit of better readability which is accomplished by avoiding callback hell.
I noticed that you have postRequest
function which uses $scope.uid
. I guess that you do not want to execute this function if you do not have $scope.uid
. I also guess that this function is called by some event, like click on a button. My recommendation is that you disable the button or whatever else invokes this function until the $scope.uid
is loaded.
For example like this:
<button type="button" ng-click="postRequest(something)" ng-disabled="uid === undefined">Post</button>
Hope this helps.