I am trying to deploy a simple function to Firebase, but I am having some difficulties. Every time I try to use .once on a reference Firebase tells me that it is not a function. Here is my code
exports.testFunction = functions.database.ref('/Rooms/{firstID}/{pushId}/On').onWrite(event => {
const value = event.data.val();
var ref = functions.database.ref(roomNum);
return ref.once('value').then(snapshot => {
console.log(snapshot.numChildren);
return true;
}); });
I have also tried the following:
firebaseRef.once('value', function(dataSnapshot) {
console.log(snapshot.numChildren);
});
Nothing seems to work. Does anyone know of a fix or a different way of getting the number of children from a ref/snapshot?
Thank you.
functions.database.ref is a different object than the one you're used to using on the client. It's sole purpose is to listen for writes using it's only function, onWrite.
You can obtain your intended ref thru the event parameter.
var ref = event.data.ref
This is a reference to the path you specified in onWrite.
If you want the root reference:
var rootRef = event.data.ref.root
Further reading: https://firebase.google.com/docs/reference/functions/functions.database
Related
Below is pseudo-code for the way you write a listener for a Realtime Database event.
function callbackA(snapshot) {
console.log(snapshot.val());
}
route.on('value', callbackA);
Now imagine I want to pass some arguments to callbackA so that callbackA might look like this:
function callbackA(snapshot, myParam1, myParam2) {
console.log(snapshot.val());
console.log(myParam1);
console.log(myParam2);
}
How can I do this (without ruining the first arg that firebase automatically provides for us)?
You can't change the arguments that the Firebase SDK passes to the callback function. It will always attempt to pass exactly one argument: the snapshot.
Instead, you could simply provide the values as variables within the scope of the callback, and access them directly.
const myParam1 = ...
const myParam2 = ...
function callbackA(snapshot) {
console.log(snapshot.val());
console.log(myParam1)
console.log(myParam2)
}
Or you can use function currying to create a new function to pass as the callback. It might go something like this (this untested code - use your best judgement here):
function callbackA(myParam1, myParam2) {
return function(snapshot) {
console.log(snapshot.val());
}
}
const callbackB = callbackA("value-for-myparam1", "value-for-myparam2")
route.on('value', callbackB);
You will obviously need to know the values for the params before you call the Firebase SDK.
So, this is my current problem:
I have locations.js file that has several functions inside with different town/area names and they all include few switches. This is example:
let Locations = {
town1: function (eventType) {
switch (eventType) {
case "load":
// Stuff related to main starting point of this location
break;
}}
They have been all nice for everything else, but now I'm trying to create a "main access" when starting the program. Let's call main file as manager.js
let Manager = {
setStart: function () {
currentLocation = user.currentLoc;
// Call load function based on current location to start program from right spot
Locations.currentLocation("load");
}
Result:
TypeError: Locations is not a function
As you see, I want to call function with user.currentLoc information (town names), which are saved to database. But it seems like I cant add it to variable and just use it. What am I missing here? Do I type it wrong when calling a function? I'm quite sure that there's some easy solution to this, but even after several hours I still fail to do this right.
You are trying to access to a property field of the Locations object. This field is a function, however, if you are trying to call this function by the name of a variable, the Javascript interpreter will take it as a direct call of the function.
let manager = {
setStart: () => {
const currentLocation = user.currentLoc;
// Access the Locations property
const fn = Locations[currentLocation];
// Invoke the function
fn(`load`);
}
};
Hope it helps.
Perhaps Locations[currentLocation]('load') is what you mean to call, but all the same - it looks like Locations isn't in scope in your Manager file, you need to import it somehow. That could be a missing require or import depending on your project
let manager = {
setStart: () => {
const currentLocation = user.currentLoc;
// Access the Locations property
const fn = Locations[currentLocation];
// Invoke the function
fn(`load`);
}
};
This did it! Thanks VRoxa. I had no idea that Javascript works like this.
I've run into an issue where I'm unable to get the value I need from inside a callback that's passed to an instantiation of a JavaScript class.
let value;
const mutationObserver = new MutationObserver((mutations) => {
return values.map((mutation) => {
value = mutation.target.childElementCount;
return value;
})
})
console.log("value", value) <= undefined
const element = document.getElementsByClassName('pac-container')[0];
if (element) {
mutationObserver.observe(element, {
childList: true,
subtree: true
});
}
I'm using the MutationObserver because I'd like a way to know, in real-time, how the DOM is being mutated by the results from the googlePlaces API. Since I don't have control over that markup - this seems like the next best thing.
I have explored using the AutoCompleteService - but that would require us to re-implement the existing googlePlaces using the AutoCompleteService call, instead of the AutoComplete API endpoint.
The approach I'm using here is in perfect sync with the results.
I don't think I've run into before - and the difference here is that the value is set inside this instance of a class.
How do you allow the value retrieved inside the class to be defined outside the scope of the function inside the class where it's handled?
We're making the call to the googlePlaces API like this:
const autoComplete = new this.googleApi.places.Autocomplete(
this.props.inputRef,
INIT_OPTIONS
);
An object is returned after the call - and I can see the request being made - and there is new data after each search - but there is no clean JSON response - and the data is embedded in some optimized way deep in the object.
I am trying to use the region variable inside the callback however there is no way I can get the value of it.
As you might be already aware I am instantiating a JS objects using TS and the callback is part of the definition of this JS object.
I am already being able to use JS in my Angular components using () => { in those methods where I need to use any reference to 'this' inside JS callbacks but for this particular case it does not work at all.
showRegion = (region: string) => {
var service = new JS.service();
var prov = new JS.provider(service, {
callback: (data) => {
// cannot read region variable
}
})
Thanks,
In my global controller (assigned to the body in html) I have the following code to grab a snapshot of firebase one time.
ref.once('value', function(snapshot){
var data = snapshot;
}).then(function(data){
$rootScope.content = data.val();
});
I am using the content in my HTML templates to render them. All the questions I found had resulted in putting the "then" code inside the callback.
Literally all I need to do is be able to grab a snapshot one time and store it on $rootScope.content and access it outside of the function, i.e. anywhere in my app.
I'm pretty sure it's because everything is rendering prior to firebase returning anything, I'm just not sure the best way to tell it to wait.
Thank you in advance.
Try:
ref.once('value', function(snapshot){
$rootScope.content = snapshot.val();
});
Or:
ref.once('value').then(function(snapshot){
$rootScope.content = snapshot.val();
});
From the once() docs:
Return Value
Returns a Promise that can optionally be used instead of the successCallback and failureCallback to handle success and failure.
I think your second line var data = snapshot; may be the problem? If all you want is to get the whole database and assign it to a object called $rootScope.content, or anything else, the below would work. I don't use angular but $rootScope.content would need to be an object, aka var foo = {} would be able to take snapshot.val(). Note that snapshot.val() is full of stuff other than just your JSON formatted data and you will have to extract out your individual nodes by calling the property names (the key's), e.g. snap.val().firstName to get Bob.
firebase.database().ref('/').once('value').then(function(snap) {
$rootScope.content = snap.val();
});