Cannot access Firebase object attributes. Value displayed as undefined ANGULARFIRE - angularjs

I want to do a custom login for a demo of my doing, but I encountered a problem.
I use the username to access a reference url inside Firebase, I get a returned object. If I want to access a single attribute, I get the undefined value, but if I add in my html {{returnedObj.name}} the value is displayed.
Why is that?
angular.module('Demo').controller('loginCtrl', ['$scope', '$firebase', '$location', function($scope, $firebase, $location){
$scope.user = {};
$scope.check = function(){
console.log('https://fabritzio-demo.firebaseio.com/users/' + $scope.user.name);
$scope.returnedObj = $firebase(new Firebase('https://fabritzio-demo.firebaseio.com/usuarios/' + $scope.user.name)).$asObject();
alert($scope.returnedObj.name); // returns undefined value
};
}]);

Firebase values are loaded asynchronously. The value will not yet have been loaded into $scope.returnedObj when the alert fires.
There are a couple of ways to handle values loading asynchronously from Firebase, for example using $loaded to get a promise:
$scope.returnedObj.$loaded().then(function () {
alert($scope.returnedObj.name);
});
The value is displayed in the template because Angular watches all $scope variables for changes. When the value is loaded (milliseconds later), it is immediately displayed.

Related

Utilising $scope.apply()

I have the following which works fine, drawing info from a RESTful api feed
app.controller('servicesController', ['$scope', '$location', '$http', '$interval',
function($scope, $location, $http, $interval) {
var getData = function() {
// Initialize $scope using the value of the model attribute, e.g.,
$scope.url = "https://(remote link to JSON api)";
$http.get($scope.url).success(function(data) {
$scope.listOfServices = data.runningServices; // get data from json
});
};
getData();
$interval(getData(), 10000);
}
]);
However my view is not updating every 10 seconds as expected. I have read that I need to use $scope.apply() somewhere in this above code.
I tried placing the following (in the appropriate place above)
$http.get($scope.url).success(function(data) {
$scope.listOfServices = data.runningServices; // get data from json
$scope.apply(); //I also tried $scope.runningServices.apply()
});
$scope.apply is not your problem, the scope will be digested automatically at the end of the $http request and $interval. Certain actions automatically "inform" Angular that the scope may have changed and trigger a digest; only if you're writing "non-Angular" code may you have to explicitly trigger a scope digest, since otherwise Angular wouldn't notice any changes.
No, your issue is that you're calling getData(), and then have its return value (undefined) execute every ten seconds. Which is obviously nonsense. You just want to pass the function itself to $interval:
$interval(getData, 10000);
// look ma, ^^^^^, no parentheses

Can't reach field inside an object in my angular controller

I'm using a factory to get a television show from a database. I wanted to send just the episodes field from this object to a angular service but I keep getting undefined using dot notation and bracket notation. Can someone explain how to get this field.
Controller
angular.module('showApp.controllers', []).controller('ShowViewController', function($scope, $stateParams, Show, $http) {
$scope.show = Show.get({ id: $stateParams.id }); //Get a single show.Issues a GET to /api/shows/:id
console.log($scope.show)
console.log($scope.show.episodes)
})
Console Output
m
$promise:d
$resolved:true
__v:0
_id:"581a5b82ff9e9f10f22afff7"
airs_on:Array[1]
episodes:Array[11]
genre:Array[3]
network:"Netflix"
poster:"https://images-na.ssl-images-amazon.com/images/M/MV5BMTk5NTk1Mzg3Ml5BMl5BanBnXkFtZTcwNDAyNzY3OA##._V1._CR25,3,1010,1343_SY1000_CR0,0,752,1000_AL_.jpg"
program_time:60
rated:"TV-MA"
streams_on:Array[3]
title:"Black Mirror"
yearBegin:2011
__proto__:Object
undefined
you can wait for results by:
$scope.show.$promise.then(function(show) {
console.log(show.episodes);
})
you should call the service in the then function.
I think this is a timing issue. There should be a callback from the http get request, at which time $scope.show is valid - you should do your console logging in the callback

Change Firebase Array Ref based on Localstorage

i am stuck on the following problem:
i have a select element were the user picks an option.
this option is saved to the localstorage.
now i want to use this stored value as path for a firebasearray.
basically it seems to work but i cant get the firebasearray ref to update without hitting reload.
my firebasearray factory:
.factory("MyFireFactory", ["$firebaseArray", "$localStorage",
function($firebaseArray, $localStorage) {
var ref = firebase.database().ref('demodata/' + $localStorage.selectedoption);
return $firebaseArray(ref);
}
])
After reading the angular docs angular docs if found out that
"...All services in Angular are singletons..." wich basically means if i understood it correctly that they only run once.
Wich in my case meant the i had to move my factory code to the controller so that the data from localstorage can be used.
my now working controller:
var ref = firebase.database().ref('demodata/' + $localStorage.selectedoption);
$scope.demoscop = $firebaseArray(ref);

req.params.value is undefined

In my Node js Application, am using Angular js for data binding.
Am using ng-controller, inside which I use an http service to get data from the database.
On the button click event am calling clickedbutton function,where I pass a value to the service.
HomeController.js
app.controller('BasicHomeController', function ($scope, $filter,$http) {
$scope.clickedbutton=function(value){
$http.get('/getData/'+value)
.then(successCallback, errorCallback);
};
);
However am not able to get the service value from the browser using req.params. It gives undefined value.
app.js
app.get('/getData/:value', function(req,res){
var reqid = req.params.value; //It gives reqid as undefined
});

angularfireCollection: know when the data is fully loaded

I am writing a small Angular web application and have run into problems when it comes to loading the data. I am using Firebase as datasource and found the AngularFire project which sounded nice. However, I am having trouble controlling the way the data is being displayed.
At first I tried using the regular implicit synchronization by doing:
angularFire(ref, $scope, 'items');
It worked fine and all the data was displayed when I used the model $items in my view. However, when the data is arriving from the Firebase data source it is not formatted in a way that the view supports, so I need to do some additional structural changes to the data before it is displayed. Problem is, I won't know when the data has been fully loaded. I tried assigning a $watch to the $items, but it was called too early.
So, I moved on and tried to use the angularfireCollection instead:
$scope.items = angularFireCollection(new Firebase(url), optionalCallbackOnInitialLoad);
The documentation isn't quite clear what the "optionalCallbackOnInitialLoad" does and when it is called, but trying to access the first item in the $items collection will throw an error ("Uncaught TypeError: Cannot read property '0' of undefined").
I tried adding a button and in the button's click handler I logged the content of the first item in the $items, and it worked:
console.log($scope.items[0]);
There it was! The first object from my Firebase was displayed without any errors ... only problem is that I had to click a button to get there.
So, does anyone know how I can know when all the data has been loaded and then assign it to a $scope variable to be displayed in my view? Or is there another way?
My controller:
app.controller('MyController', ['$scope', 'angularFireCollection',
function MyController($scope, angularFireCollection) {
$scope.start = function()
{
var ref = new Firebase('https://url.firebaseio.com/days');
console.log("start");
console.log("before load?");
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
console.log("start() out");
};
$scope.start();
//wait for changes
$scope.$watch('items', function() {
console.log("items watch");
console.log($scope.items[0]); //undefined
});
$scope.testData = function()
{
console.log($scope.items[0].properties); //not undefined
};
}
]);
My view:
<button ng-click="testData()">Is the data loaded yet?</button>
Thanks in advance!
So, does anyone know how I can know when all the data has been loaded
and then assign it to a $scope variable to be displayed in my view? Or
is there another way?
Remember that all Firebase calls are asynchronous. Many of your problems are occurring because you're trying to access elements that don't exist yet. The reason the button click worked for you is because you clicked the button (and accessed the elements) after they had been successfully loaded.
In the case of the optionalCallbackOnInitialLoad, this is a function that will be executed once the initial load of the angularFireCollection is finished. As the name implies, it's optional, meaning that you don't have to provide a callback function if you don't want to.
You can either use this and specify a function to be executed after it's loaded, or you can use $q promises or another promise library of your liking. I'm partial to kriskowal's Q myself. I'd suggest reading up a bit on asynchronous JavaScript so you get a deeper understanding of some of these issues.
Be wary that this:
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
does correctly specify a callback function, but $scope.items doesn't get assigned until after you've ran the callback. So, it still won't exist.
If you just want to see when $scope.items has been loaded, you could try something like this:
$scope.$watch('items', function (items) {
console.log(items)
});
In my project I needed to know too when the data has been loaded. I used the following approach (implicit bindings):
$scope.auctionsDiscoveryPromise = angularFire(firebaseReference.getInstance() + "/auctionlist", $scope, 'auctionlist', []);
$scope.auctionsDiscoveryPromise.then(function() {
console.log("AuctionsDiscoverController auctionsDiscoveryPromise resolved");
$timeout(function() {
$scope.$broadcast("AUCTION_INIT");
}, 500);
}, function() {
console.error("AuctionsDiscoverController auctionsDiscoveryPromise rejected");
});
When the $scope.auctionsDiscoveryPromise promise has been resolved I'm broadcasting an event AUCTION_INIT which is being listened in my directives. I use a short timeout just in case some services or directives haven't been initialized yet.
I'm using this if it would help anyone:
function getAll(items) {
var deferred = $q.defer();
var dataRef = new Firebase(baseUrl + items);
var returnData = angularFireCollection(dataRef, function(data){
deferred.resolve(data.val());
});
return deferred.promise;
}

Resources