I have below code to query the index from users node then pass the index to todos node to get the data I want but it only watching when a child is added so when a child is removed in the index it doesn't update the view.
I have no idea how to get the object key if I use value in the index node.
Any idea? or any better way to query mastered data using angularFire?
FirebaseRef.$child(user.uid).$on('child_added', function(a) {
FirebaseRef.$child('todos/' + a.snapshot.name).$on('value', function(b) {
$scope.todoList[a.snapshot.name] = b.snapshot;
});
});
try the following (not tested).
FirebaseRef.$child(user.uid).$on('child_added', function(a) {
FirebaseRef.$child('todos/' + a.name()).$on('value', function(b) {
$scope.todoList[a.name()] = b.snapshot;
});
});
You shouldn't need 'snapshot' in your reference eg a.snapshot.name, you should just reference the object returned in your callback function
Related
I'm triggering a Cloud Function using Http Request.
The issue is to retrieve the entire List of Objects I have, without an event to then loop through them.
The List is under the account/userId Node.
Here is what I use but I get nothing:
return admin.database().ref('/account/' + userId).once('value').then(function (snap) {
let data = snap.val();
}
Without seeing your database structure it is a bit difficult to write an answer and be 100% sure it is a correct one, but the following should do the trick:
return admin.database().ref('/account/' + userId).once('value').then(function (snap)
snap.forEach(function(child) {
const childKey = child.key; // <- here you get the key of each child of the '/account/' + userId node
console.log(childKey);
const childVal = child.val(); // <- and here you get the values of these children as JavaScript objects
console.log(childVal);
});
});
In case this is not exactly what you are looking for, please update you Question with your database structure and the entire code of your Cloud Function.
Related to this question, I need to be able to get an element from a collection as a Firebase reference, ie given a $firebaseArray I need a $firebaseObject pointing to one of its elements. Unlike that example, I can't just hard-code a path the array and take a child from there because the location of the array will vary. And I can't use $firebaseArray.$getRecord() or the object provided by my ng-repeat followed by array.$save() because I may need to do a push() on this element.
So I settled on this reusable approach:
In a service:
function selectElement(array, element) {
var obj = $firebaseObject(array.$ref().child(element.$id));
return obj;
}
In the controller:
function onItemClicked(e) {
vm.selected = dataservice.selectElement(vm.observations, e);
}
In the template:
<div class="list-item" ng-repeat="o in vm.observations" ng-click="vm.onItemClicked(o)">
The first line of selectElement produces an error: array.$ref(...).child is not a function at Object.selectElement
Here array has all the properties you'd expect, but logging array.$ref() shows this obfuscated object:
Y {k: Ji, path: P, n: Ce, pc: true}
That is what it looks like from the time the array is created. What's going on here and how do I use this reference? Is there another way to get a working Firebase object out of an array?
I am trying to iterate over firebaseObject and firebaseArray fetched from my Firebase but they don't seem like normal javascript objects and arrays.
My data is stored in the following form
'mainKey': {
'key1':'value1',
'key2':'value2'
},
'mainkey2': {
'key3':'value3'
}
I've tried the following code
var firebaseRef = new Firebase("https://<my-app>.firebaseio.com/);
var fbArray = $firebaseArray(firebaseRef);
var fbObject = $firebaseObject(firebaseRef);
for(var i=0;i<fbArray.length;i++){
console.log(fbArray[i]);
}
console.log(fbObject);
console.log(fbObject.mainkey);
console.log(fbArray.length);
This gives the following output in the console
Object { $$conf={...}, $id="test", $priority=null, more...}
undefined
0
Though the object returned has mainkey property but I'm not able to access it.Why does this happen? And how should I iterate over them ?
You could try for..in loop to iterate over an object.
Below is an example:
for (var key in fbObject) {
console.log(fbObject[key]); // You could use this method with all objects in JS
}
here's the info you need to know
The $firebaseArray service takes a Firebase reference or Firebase Query and
returns a JavaScript array which contains the data at the provided Firebase
reference. Note that the data will not be available immediately since
retrieving it is an asynchronous operation.
You can use the $loaded() promise to get notified when the data has loaded.
https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray
fbArray.$loaded(function() {
//here you can iterate over your object
});
Clearly, I am doing something wrong with ReactiveVar because I cannot get it to work as I expect it should.
I am trying to set the value of an ReactiveVar by calling a Meteor.call method which returns the list of usernames. But it does not update when the usernames get changed in another part of the app.
I tried both:
Template.qastatistics.created = function () {
this.trackUsernames = new ReactiveVar(false);
var instance = Template.instance();
Meteor.call('trackUsernames', function (err, data) {
instance.trackUsernames.set(data);
});
};
and:
Template.qastatistics.helpers({
users: function () {
var usernames,
instance = Template.instance();
if (instance.trackUsernames.get() === false) {
Meteor.call('trackUsernames', function (err, data) {
instance.trackUsernames.set(data);
});
}
usernames = instance.trackUsernames.get();
...
But neither updates the list of usernames when these change in the database.
Is this even possible with ReactiveVars or have I completely misunderstood them?
EDIT: The usernames I mention are not from Meteor.users collection, but rather a distinct call from another collection that has usernames in it.
Fist of all I would use the onCreated function instead of defining created. That's a little more extendable and it's the new API. created is just kept around for backwards compatibility.
About your problem. You are right, you seem to have misunderstood what ReactiveVars do. They are a reactive data source. That means that when you call myReactiveVar.get in some Tracker.autorun (aka. reactive computation), the computation will rerun whenever myReactiveVar.set is called.
You got the first part right. Spacebars helpers always run inside their own computation. What you got wrong is thinking that a method call is a reactive action. That means, that you could call trackUsernames and set the trackUsernames ReativeVar again and the value in your template would update itself. But a method is only run once. It doesn't do anything fancy with reactivity.
A method call only transfers data once. When you publish a set of documents (like all users) on the other hand, they will be updated dynamically. Whenever a change happens inside that set of published documents, it will be synced to the client. So in general, it's a better idea to use publications and subscriptions to sync data reactively. If you'd want to use a method for the same thing you'd need to do some kind of polling (so your back in the stone-age again).
The easiest way to implement what you are trying to do is to use Meteor.users.find().fetch(). As it says in the docs fetch registers dependencies for all the documents you are fetching if it's being called from within a reactive computation.
First you'll need to properly set up your publications, so that users can see other users usernames. I'll leave that to you. Then you need to reimplement your helper
Template.qastatistics.helpers({
users: function () {
var usernames = _.pluck(Meteor.users.find().fetch(), 'username');
...
Thanks to suggestions from #kyll, I managed to get what I wanted by publishing the data I need:
server:
cope.publish.usernamesID = Random.id();
Meteor.publish("itemsusernames", function () {
self = this;
var initializing = true;
var handle = Items.find().observeChanges({
added: function (id) {
!initializing && self.changed(
"itemsusernames",
cope.publish.usernamesID,
Items.distinct("p4User"));
},
changed: function (id) {
!initializing && self.changed(
"itemsusernames",
cope.publish.usernamesID,
Items.distinct("p4User"));
},
removed: function (id) {
!initializing && self.changed(
"itemsusernames",
cope.publish.usernamesID,
Items.distinct("p4User"));
}
});
initializing = false;
self.added("itemsusernames", cope.publish.usernamesID, Items.distinct("p4User"));
self.ready();
self.onStop(function () {
handle.stop();
});
});
client:
users: function () {
var usernames = [],
oUsernames = ItemsUsernames.find().fetch();
if (!oUsernames[0]) return [];
usernames = $.map(oUsernames[0], function (value, index) {
if (!isNaN(index)) {
return [value];
}
});
...
And ofcourse: ItemsUsernames = new Mongo.Collection("itemsusernames");
I've got a Firebase with a simple bit of data:
There's a list of "players", each with a self-generated GUID, and each containing a value "Count". At my request (e.g. using once()), I want to be able to query the players sorted by the Count value. So, based on the Firebase documentation, I'm using orderByChild(), but it always comes up as undefined when I run the code:
var fb = new Firebase("https://morewhitepixels.firebaseio.com/");
fb.child("players").orderByChild("Count").once("value",function(data) {
// do something with data
});
But this code always returns Uncaught TypeError: undefined is not a function pointing to that second line of code.
What am I missing?
I'm not sure what you do inside the callback, but this works fine:
fb.child("players").orderByChild("Count").once("value",function(data) {
console.log(data.val());
});
Keep in mind that the data parameter is not the actual data yet. It's a DataSnapshot on which you have to call val() first.
You'll probably want to loop through the children, which you can do like this:
fb.child("players").orderByChild("Count").once("value",function(data) {
data.forEach(function(snapshot) {
console.log(snapshot.val().Count);
});
});
The above example prints out all your children in the order you requested:
120320
181425
185227
202488
202488
202488
202488
245197
245197
487320
Alternatively you can use on('child_added' instead:
fb.child("players").orderByChild("Count").on("child_added",function(snapshot) {
console.log(snapshot.val().Count);
});