How to retrieve nested data with Angularjs ng-repeat in Firebase? - javascript

I am seriously having a hard time retrieving nested data from Firebase with AngularJS. I try to save data this way in Firebase, btw I am using Angularfire to save and retrieve data from the database. How can I retrieve the value of foo with ng-repeat? I also find that the documentations is scarce and tutorials are outdated. I like the real time updates and that is why I want to use it. There are no errors in the console btw. Thanks in advance for any suggestions.
--Unique id
--0
--foo:"bar"
--1
--foo:"bar"
Now when I do this in my HTML it gives me back the index number:
<div ng-repeat="(item, id) in list">
<span>{{item}}</span><button ng-click="remove(id)">x</button>
</div>
</div>
But when I do this, it does not give me the values of foo:
<div ng-repeat="(item, id) in list">
<span>{{item.foo}}</span><button ng-click="remove(id)">x</button>
</div>
</div>
Javascript
angular.module("app", ['firebase'])
.controller("ctrl", function ($firebase, $scope) {
var ref = new Firebase('https://testing12344.firebaseio.com/');
var x=[{foo:"bar"}, {foo:"bar"}];
var sync = $firebase(ref);
var list = sync.$asArray();
list.$add(x);
$scope.list = list;
console.log($scope.list);
$scope.remove = function (id){
list.$remove(id);
}
})

As I already commented: Firebase's documentation recommends against building nested data structures; partially because of the reason you encounter. The only time I find myself nesting data structures like this, is when a user is typically "inside" one of these top-level children. In that case the outermost ID is part of the context and I won't need a nested loop, like you do.
That said, you can easily make your code/view work if you ensure it matches the data structure correctly. Since you have a collection (with children 0 and 1) inside a collection (with the generated IDs), you'll need to ng-repeats to reach foo:
<ol>
<li ng-repeat="item in list">
{{item.$id}}
<ol>
<li ng-repeat="child in item">{{child}}</li>
</ol>
</li>
</ol>
A snippet from the output:
1. -Jgv9EmOXmXYNrYPG8jK
1. {"foo":"bar"}
2. {"foo":"bar"}
2. -Jgv9GEXJLnaQmYeYR2u
1. {"foo":"bar"}
2. {"foo":"bar"}
3. -JgvHQ1YJsgF9THdfmd7
1. {"foo":"bar"}
2. {"foo":"bar"}
I also noticed that you're logging console.log($scope.list);, which is a common mistake. By the time that console.log statement executed, the data may not have been loaded from Firebase's servers yet. Sometimes it shows up correctly in your browser's JavaScript console, but sometimes it doesn't.
The proper way to log the data once it is loaded is:
list.$loaded().then(function(list) {
console.log('Initial child count', list.length);
console.log(list[0][0].foo);
});
Note that $loaded will only trigger for the initially downloaded data, not for subsequent updates. If you care about those, you should look into AngularFire's $watch. But to be honest: you should normally not have a need for that. Once you bind your AngularFire data to the view correctly, it should update automatically in most use-cases.

Related

Angular filtering data in javascript is not displaying results and push of data causes error plunker provided

Ok, seems that I was having too many issues with the way in which my Angular site is setup, so I put it in a plunker as then anyone can see it.
Original question: Angular retrieve specific data into $scope variable is not working
Plunker
http://plnkr.co/edit/NsE29zjraQp9UeklJBiI?p=preview
My issues are
1. i'm not understanding how to use app.filter
2. Issue with app name
3. forEach with push inside $http.get throws error not defined
The plunker Index.html has the template code loop , app.module.js is root and the device.controller.js is where I'm using controller with $http.get call using json file to fake it.
I was attempting to use the other persons answer so this code
$scope.devices = result.data.Devices; // gives all data ...
Filter I was wondering if this with work
<div ng-repeat="device in devices">
{{ device.DeviceStatus }}
</div>
Then this code I'm not sure it in the correct "place"
seems like i'm not understanding "app"
app.filter('deviceStatus', function () {
return function (status_id) {
var statuses = ['Old Device', 'New Device', 'Activated', 'Unactivated'];
return statuses[status_id];
};
});
Example filter:
<td>{{device.DeviceId | deviceStatus}}</td>
Let me try to understand your issue.
As per your question, it seems that you have problems understanding what app is and how to use filter.
This is the working version of your plunkr. Check this url
app in your project is the ng-app directive. The ng-app directive tells AngularJS that the element is the "owner" of an AngularJS application.
For understanding filter functionality. check the below example.
You were trying to push into $scope.statuses which is not defined yet. So first define $scope.statuses to be an empty array i.e `$scope.statuses = [];
Hope this works for you!`
// To declare a filter we pass in two parameters to app.filter
// The first parameter is the name of the filter
// second is a function that will return another function that does the actual work of the filter
//here app is the module name of your project
app.filter('myFilter', function() {
// In the return function, we must pass in a single parameter which will be the data we will work on.
// We have the ability to support multiple other parameters that can be passed into the filter optionally
return function(input, optional1, optional2) {
var output;
// Do filter work here
return output;
}
});

Accessing Individual objects from NG Bind Result

Hi I'm fairly new to Angular so go easy on me.
I have a list of numbers that are popluated from a database. These are coming through fine as list of numbers. I would like to display these numbers in various parts of the webpage rather than in a list. I was wondering if there is a way to access or reference individual entries of the ng repeat response. Or is there another way I can access individual elements of the query .
This is my HTML
<li ng-repeat="x in myData">
{{x.Values}}
</li>
(some html ommited due to formatting)
and This is the controller I am using to populate it
app.controller('customersCtrl', function($scope, $http) {
$http.get("scripts/counts.php").then(function (response) {
$scope.myData = response.data.records;
});
});
so rather than have {{x.values}}
I would like to be able to assign aungular variables to each row.
Thanks.
If you want to access the individual entries, if it's an Object you can simply call it's property:
<li>{{myData.key}}</li>
Or if it's an array:
<li>{{myData[0]}}</li>

Ionic, List populating via search

I am using a backemnd service (parse in this case but that doesn't really matter for this question) and wanted to simply search it. I have a textbox that upon text being entered searches the server and returns an array of matchs.
My next step is to simply display my returned objects nicely in a list. Easy enough with ng-repeat but because the view has already been loaded the UI won't update to reflect the array being loading into the list. Does that make sense?
I was wondering if there was a technique to Refresh the list and show the returned search elements, and hopefully I am not being to greedy here but doing it in a way that looks good and not clunky.
I did a lot of googling with NO luck :( any advice would be amazing.
Without any code provided it is hard to guess what is wrong. Angular has two-way binding, so view should be updated automatically after changing content of an array. If it's not, it means that you probably did something wrong in your code. I present an example code which should work in this case.
Controller
angular.module('moduleName')
.controller('ViewController', ['ViewService', ViewController]);
function ViewController(ViewService) {
var self = this;
self.arrayWithData = [];
self.searchText = "";
// ---- Public functions ----
self.searchData = searchData;
// Function which loads data from service
function searchData(searchText) {
ViewService.getData(searchText).then(function(dataResponse) {
// Clear the array with data
self.arrayWithData.splice(0);
// Fill it again with new data from response
angular.forEach(dataResponse, function(item) {
self.arrayWithData.push(item);
});
});
}
// --- Private functions ---
// Controller initialization
function _initialize() {
self.searchData(self.searchText);
}
_initialize();
}
View
<div ng-controller="ViewController as view">
<input type="text" ng-model="view.searchText" />
<input type="button" value="Search!" ng-click="view.searchData(view.searchText)" />
<!-- A simple ngRepeat -->
<div ng-repeat="item in view.arrayWithData">
<!-- Do what you want with the item -->
</div>
</div>
Conclusion
By using splice() and push() you make sure that reference to your array is not changed. If you are using controllerAs syntax (as in the example), assigning new data with '=' would probably work. However, if you are using $scope to store your data in controller, losing reference to the array is the most probable reason why your code doesn't work.

Meteor: Data from External API call not rendering

I am relatively new to Meteor, and I'm trying to create a web store for my sister-in-law that takes data from her existing Etsy store and puts a custom skin on it. I've defined all of my Meteor.methods to retrieve the data, and I've proofed the data with a series of console.log statements... So, the data is there, but it won't render on the screen. Here is an example of some of the code on the server side:
Meteor.methods({
...
'getShopSections': function() {
this.unblock();
var URL = baseURL + "/sections?api_key="+apiKey;
var response = Meteor.http.get(URL).data.results;
return response;
}
...
});
This method returns an array of Object. A sample bit of JSON string from one of the returned Objects from the array:
{
active_listing_count: 20,
rank: 2,
shop_section_id: 1******0,
title: "Example Title",
user_id: 2******7
}
After fetching this data without a hitch, I was ready to make the call from the client side, and I tried and failed in several different ways before a Google search landed me at this tutorial here: https://dzone.com/articles/integrating-external-apis-your
On the client side, I have a nav.js file with the following bit of code, adapted from the above tutorial:
Template.nav.rendered = function() {
Meteor.call('getShopSections', function(err, res) {
Session.set('sections', res);
return res;
});
};
Template.nav.helpers({
category: function() {
var sections = Session.get('sections');
return sections;
}
});
And a sample call from inside my nav.html template...
<ul>
{{#each category}}
<li>{{category.title}}</li>
{{/each}}
</ul>
So, there's a few things going on here that I'm unsure of. First and foremost, the DOM is not rendering any of the category.title String despite showing the appropriate number of li placeholders. Secondly, before I followed the above tutorial, I didn't define a Session variable. Considering that the list of shop categories should remain static once the template is loaded, I didn't think it was necessary from what I understand about Session variables... but for some reason this was the difference between the template displaying a single empty <li> tag versus a number of empty <li>'s equal to category.length --- so, even though I can't comprehend why the Session variable is needed in this instance, it did bring me one perceived step closer to my goal... I have tried a number of console.log statements on the client side, and I am 100% sure the data is defined and available, but when I check the source code in my Developer Tools window, the DOM just shows a number of empty li brackets.
Can any Meteor gurus explain why 1) the DOM is not rendering any of the titles, and 2) if the Session variable indeed necessary? Please let me know if more information is needed, and I'll be very happy to provide it. Thanks!
You set the data context when you use #each, so simply use:
<li>{{title}}</li>
If a Session is the right type of reactive variable to use here or not is hard to determine without knowing what you are doing but my rough guess is that a Mini Mongo collection may be better suited for what it appears you are doing.
To get you started on deciding the correct type of reactive variable to use for this head over to the full Meteor documentation and investigate: collections, sessions, and reactive vars.
Edit: To step back and clarify a bit, a Template helper is called a reactive computation. Reactive computations inside of helpers will only execute if they are used in their respective templates AND if you use a reactive variable inside of the computation. There are multiple types of reactive variable, each with their own attributes. Your code likely didn't work at all before you used Session because you were not using a reactive variable.

ngResource remove record from query object with $delete

Fairly new to angular. I want to use angular's $resource library to consume our API services. I'm a little lost on the proper way to delete a record obtained via the query() method. Specifically, we have an endpoint for user notifications. We want to, on page load, get all user notifications, use ng-repeat to loop over the results and display the notifications in the nav bar. When a user clicks a remove icon, the corresponding notification should be deleted. Here's the stripped down version of the code I currently have:
Js:
angular.module('myapp', ['ngResource']).factory('Notifications',function($resource){
return $resource('/apiv2/user/notifications/:id', {id:'#id'});
}).controller('NavigationController',['$scope','Notifications',function($scope, Notifications){
$scope.notifications = Notifications.query();
$scope.deleteNotification = function(notification){
notification.$delete();
};
}]);
HTML:
<ul>
<li ng-repeat="notification in notifications">
<i class="icon-remove" ng-click="deleteNotification(notification)"></i>
</li>
</ul>
With this code, when a user clicks on the remove icon, the individual notification object is passed to the deleteNotification method and is properly deleted from the backend via the api. Up until this point, everything works as intended. However, if I look at the $scope.notifications object after the fact, the notification that was just deleted remains with broken data:
{$promise:undefined, $resolved:true}
Ideally, I want this record wiped from the object returned via the .query() method to reflect its state on the back end, without having to do a new .query().
Any help would be appreciated! I apologize for vague descriptions and/or incomplete/innaccurate code, I typed this all from memory via my phones keyboard whilst out at dinner, so god knows if I missed something.
Better way of doing it: (see AngularJS ngResource delete event)
$scope.deleteNotification = function (index) {
$scope.notifications[index].$delete();
$scope.notifications.splice(index, 1);
}
and in your markup just do
ng-click="deleteNotification($index)"
There probably is a better way to do this as this throws a console error (but still works), but this is what I am doing:
$scope.notifications = Notifications.query();
$scope.deleteNotification = function(notification){
notification.$delete();
$scope.notifications = $scope.notifications.filter( function(n)
return (n != notification);
}); // filter everything but
};
if you use underscore there is a more beautiful way to write the remove thing.

Categories