Retrieving data from Firebase and repeating it in an Angular Controller - javascript

since I am new to the new SDK of Firebase (I have used a little bit of angularfire) I wanted to retrieve data and with angular to display it.
Here is what I have done so far:
var app = angular.module('dApp',[]);
app.controller('listingControler',['$scope', function($scope){
$scope.downloads = [];
var config = {
//removed config
};
firebase.initializeApp(config);
var leadsRef = database.ref('/');
leadsRef.on('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
$scope.downloads.push(childSnapshot.val());
});
return $scope.downloads;
});
}]);
View
<body ng-app="dApp">
<div ng-controller="listingControler">
<ul>
<li ng-repeat="d in downloads">{{d.email}}</li>
</ul>
</body>

Based on the comments you are getting the data (you said console allows you to view object properties). You need to specify the property names to get the string data. snapshot.val().firstName, for example.

Related

Angular JS : how can I load the factory only once?

I am using a static json file to simulate my server and getting my array of orders from it.
I'm presenting the orders in a table in my html file with the option of deleting one from it.
Each time I load the html file the full list gets loaded, with the orders I have deleted throught the controller function.
How can I loat the data from the factory only once?
Here is my controller:
app.controller("MainPageCtrl", function($scope, getOrdersFactory)
{
$scope.orders = [];
// Getting the data frm the facrory
var dataPromise = getOrdersFactory.getDataFunc();
dataPromise.then(function(data){
$scope.orders = data.orders;
});
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
};
});
By default angular services and factories are singletons(loaded only once). The problem you are facing is with controller re-initialization. When route change happens the controller is re-initialized so therby getting the previous value from the factory.
You can use a setter function on your 'getOrdersFactory'.
Assuming your 'getOrdersFactory' to be
app.factory('getOrdersFactory',function(){
//code to read from file and set the file on a variable orderDetails
var orderDetails = contentsReadFromFile;
return{
getDataFunc:function(){
return orderDetails
},
setDataFunc:function(modifiedOrderDetails){
orderDetails = modifiedOrderDetails;
//code to set the new content to the static file
}
}
}
code to read the file from the static file will be rendered when you inject the factory for the first time, and on your controller set the order details on the delete function
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
getOrdersFactory.setDataFunc($scope.orders);
};
I guess you are losing your data i.e $scope.orders .If this is the scenario just change
dataPromise.then(function(data){
$scope.orders = data.orders;
});
to
dataPromise.then(function(data){
$scope.orders = angular.copy(data.orders);
});

Load JSON in AngularJS App (loading google spreadsheet)

I am trying to load up a Google spreadsheet in my application, but I am not managing to make it work. I've tried different ways of accessing the tree structure (via the controller and/or via the html), but none of them worked.
Any idea what may be wrong?
Here is my controller:
app.controller('SuperCtrl', ['$scope', '$http', function($scope,$http) {
$http.get("https://spreadsheets.google.com/feeds/list/1lZWwacSVxTD_ciOsuNsrzeMTNAl0Dj8SOrbaMqPKM7U/od6/public/values?alt=json-in-script&callback=x")
.success(function(response) {
$scope.items = response;
});
}]);
And here is the HTML:
<ul ng-controller="SuperCtrl">
<li ng-repeat="item in items.feed.entry">
{{ item.title.type }}
</li>
</ul>
created a working plunkr for you
http://plnkr.co/edit/JfXrVDWacvjF2RzxP18g?p=preview
But here's also the meat of the solution:
app.controller('SuperCtrl', ['$scope', '$http', function($scope,$http) {
var url = 'https://spreadsheets.google.com/feeds/list/1lZWwacSVxTD_ciOsuNsrzeMTNAl0Dj8SOrbaMqPKM7U/od6/public/values?alt=json'
var parse = function(entry) {
var category = entry['gsx$category']['$t'];
var description = entry['gsx$description']['$t'];
var title = entry['gsx$title']['$t'];
var url = entry['gsx$url']['$t'];
var yo = entry['gsx$yo']['$t'];
return {
category: category,
description: description,
title: title,
url: url,
yo: yo
};
}
$http.get(url)
.success(function(response) {
var entries = response['feed']['entry'];
$scope.parsedEntries = [];
for (key in entries) {
var content = entries[key];
$scope.parsedEntries.push(parse(content));
}
});
}]);
First problem you were using the 'json in script' version of the API which is complicated and not what you want. Changed the API result to just be JSON.
Second problem is parsing the result, see my function there that converts the confusing google spreadsheet entries into nice readable JSON.
The example works - have a tinker. My advice is find something other than google spreadsheets to store your data.
It's funny, I actually built an app on top of google spreadsheets too (trackerkeeper.co), which is why I could help you. Not super proud of the engineering but it was kind of fun:
Good luck.
Here is a new working plunker. The problem was that it can't find the "yo" variable anymore.
var parse = function(entry) {
console.log(entry);
var category = entry['gsx$category']['$t'];
var description = entry['gsx$description']['$t'];
var title = entry['gsx$title']['$t'];
return {
category: category,
description: description,
title: title,
url: url
};
}
http://plnkr.co/edit/YwskJRuORJBjw4S9wU7V?p=preview

Variable caching in AngularJS (factory)

I have the following controller in my application, but there is some strange behaviour that I cannot explain. I've numbered two of the lines to help with the description, they don't both exist at the same time in the live code.
var app = angular.module('movieListings', ['ngResource', 'ngRoute', 'ui.bootstrap', 'ng']);
var cachedMovieList = [];
//Controller for movie list
app.controller('MovieListController', ['$http', function($http){
var mlc = this; //needed for the $http request
this.movies = cachedMovieList;
this.loaded = false;
this.error = false;
if(this.movies.length == 0) {
console.log("Grabbing new movie list from DB");
$http.get('data/movies.json').success(function(data){
mlc.movies = data;
mlc.loaded = true;
cachedMovieList = data; //(1)
}).error(function(data){
mlc.error = true;
});
cachedMovieList = this.movies; //(2)
} else {
this.loaded = true;
}
}]);
With the code as above with line (1) present and line (2) not present, I am able to cache the result so that when I flick between pages I don't need to constantly re-get the data.
However if I remove line (1) and insert line (2), the variable "cachedMovieList" is never populated. I would expect it to be based on the fact that "mlc.movies" was assigned to... but I cannot understand why this is the case?
Any advice welcome.
Implement a factory that retrieves the data. Use angular.copy to preserve the array reference when the data returns from the $http call.
var app = angular.module('movieListings', ['ngResource', 'ngRoute', 'ui.bootstrap', 'ng']);
app.factory('movies', function($http) {
var movies = {
data: [],
loaded: false,
error: false
};
$http.get('data/movies.json').success(function(data){
angular.copy(data, movies.data);
movies.loaded = true;
}).error(function(data){
movies.error = true;
});
return movies;
});
Inject the factory into your controller:
//Controller for movie list
app.controller('MovieListController', ['$scope','movies', function($scope, movies){
this.movies = movies;
}]);
Factories (like services) are singletons. They are initialized once, and cached for the entire lifetime of the SPA.
Use the controller in the view:
<div ng-controller="MovieListController as ctrl">
<div ng-show="!ctrl.movies.loaded"> Loading... </div>
<ul>
<li ng-repeat="movie in ctrl.movies.data">
{{ movie.name }}
</li>
</ul>
</div>
If I've understood this correct, you're entering the if condition only when this.movies.length == 0. In such a case, this.movies will be null, so cachedMovieList would get populated with a null value.
Because (2) probably gets executed first before the $http.get() request is finished. $http.get() is an AJAX request.
If you want to cache, you might want to use $cacheFactory instead :)
I believe you are mistaking the live updation of values that happens in view to live updation that would happen with variable assignments. Your line 2 will set cachedMovieList to [] initially. I believe that is quite obvious. But you think that since callback updates this.movies that change would cascade to cachedMovieList. That won't happen as you are re-assigning the mlc.movies variable that means it refer to new variable instead of modifying existing value.
If you really want to make you logic work, please update mlc.movies variables like following
mlc.length = 0 // Empty the array
mlc.push.apply(mlc, data);
Please check following answer for more information
How do I empty an array in JavaScript?

AngularJS - updating the model shared by different controllers

I'm just starting with AngularJS, building my first test web app.
I have several controllers that share the same model.
This is my model:
uxctModule.factory ("ModelData", function () {
var data = {
param1: '',
param2: '',
param3: '',
[more params....]
}
return data
});
So this is an example of my controller
uxctModule.controller ('PageOne', function ($scope, ModelData){
$scope.data = ModelData;
[do things here]
});
I'm now trying to change the model by loading a string from a file, and I was expecting the app to update accordingly.
So in a controller I'm loading a file and trying to update the model:
uxctModule.controller ('NavigationController', function ($scope, ModelData) {
$scope.data = ModelData;
$scope.browsePressed = function (evt) {
var f = evt.target.files[0];
if (f) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
console.log (contents);
console.log ("ModelData was " + ModelData.param1);
ModelData = JSON.parse(contents);
console.log ("ModelData is now " + ModelData.param1);
}
r.readAsText(f);
}
else {
alert("Failed to load file");
}
}
});
I've built a "debugger" div in the html to see the model:
<div id="debuggerBox" ng-controller="Debugger" width='300'>
<pre>{{data | json}}</pre>
</div>
...whose controller is simply:
uxctModule.controller ('Debugger', function ($scope, ModelData){
$scope.data = ModelData;
});
Now, when changing the model content loading the external file I can see on the console the right logs (values changed), but on the debugger box the Model object is still holding the old values.
As I said, I'm an AngularJS beginner, so maybe I'm doing something really wrong here. Any help is appreciated :)
The problem is you're replacing the whole object:
ModelData = JSON.parse(contents);
with this, the ModelData references another object but the original object is not modified.
You could fix this by copying field by field to the ModelData. Sample code:
var tempModelData = JSON.parse(contents);
ModelData.param1 = tempModelData.param1;
or you could try angular.copy:
angular.copy(JSON.parse(contents), ModelData);
Also try $scope.$apply to let angular aware of the changes:
$scope.$apply(function(){
angular.copy(JSON.parse(contents), ModelData);
});

ng-repeat rendering empty li elements

I am using ng-repeatto loop through the Rotten tomatoes api and display the movie title. This is the code I have
JS:
var app = angular.module('app', []);
app.controller('ApiCtrl', function($http){
var app = this;
var url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json"
var key = "?apikey=myKey"
$http.get(url+key)
.success(function(data) {
app.movies = data;
console.log(data);
})
})
HTML:
<li ng-repeat="movie in app.movies">
{{movie.title}}
</li>
</body>
This is outputting 3 blank li elements on the screen, if I call just {{movie}}then the entire object is outputted so I know the binding is correct.
An example of the JSON:
"movies": [
{
"id": "771315918",
"title": "Divergent",
}]
Where's your $scope?
Try something like:
var app = angular.module('app', []);
app.controller('ApiCtrl', function($scope, $http){
var url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json"
var key = "?apikey=myKey"
$scope.movies = $http.get(url+key);
I'm not sure if the above code will work of $http. My suggestion is that before trying to get the data from a server, get all the angular stuff working. For instance, define $scope.movies like this:
$scope .movies = [
{
"id": "771315918",
"title": "Divergent",
}
];
first and get that working.
The rotten tomatoes API has it's own movies key, so I think you need to do:
.success(function(data) {
app.movies = data.movies;
}
$scope and 'this' don't necessarily refer to the same thing. I would do
$scope.app = null;
//When the deferred object is returned
.success(function (data) {
$scope.app = data;
});
By using 'this' you are referring to the controller but is not accessible by the view. Here is another post that is really helpful:
'this' vs $scope in AngularJS controllers

Categories