Firebase return output from function - javascript

I am new in firebase and I'm trying to pass a $variable in a function to check if the $variable is exists.
function ifExistWaybillNo(waybill_no)
{
var databaseRef = firebase.database().ref('masterlist');
databaseRef.orderByChild("waybill_no").equalTo(waybill_no).on('value', function(snapshot){
alert(snapshot.exists()); //Alert true or false
});
}
The above function work's fine but when I changed alert(snapshot.exists()); to return snapshot.exists(); it doesn't working. It just return undefined, which should return true or false.
How can I do this? thanks in advance

Almost everything Firebase does is asynchronous. When you call the function ifExistWaybillNo it expects an immediate return, not to wait. So before your databaseRef.orderByChild("waybill_no") is finished the statement that called the function has already decided the return is undefined.
The way to fix this is by passing a callback function and using the return there. An exact explanation of this is done very well here: return async call.
You just need to rename some of the functions and follow syntax used there.
To start:
function(waybill_no, callback) {
databaseRef.orderByChild("waybill_no").equalTo(waybill_no).on('value', function(snapshot) {
var truth = snapshot.exists();
callback(truth); // this will "return" your value to the original caller
});
}
Remember, almost everything Firebase is asynchronous.

Related

Firebase user data after authentication error

The function worke perfectly, but if I want to print the content of the user, I receive in the firebase log this info:
Function returned undefined, expected Promise or value
The function is:
exports.accountCreate = functions.auth.user().onCreate(user => {
console.log("--->"+user.data);
console.log("ok");
});
Why the user.data is not able to retrieved the informations?
Thanks
Cloud Functions run in a container in a managed environment. The environment tries to minimize how long it keeps the container running, and to be able to do so, it must know when your function is done. Normally in JavaScript code is done when the last } has executed, but this gets more complex when you also need to consider asynchronous operations. For this reason Cloud Functions expects you to inform it when the function is done, in the case of functions.auth.user().onCreate by returning a value or promise.
When you explicitly return a value, it is clear that the function is done. When you explicitly return a promise, it's clear that the function needs to remain active until the promise is resolved/rejected. When you don't return a value, it is not clear what state the function is in.
In your case the fix is simple, and you for example just return true before the final }.
exports.accountCreate = functions.auth.user().onCreate(user => {
console.log("--->"+user.data);
console.log("ok");
return true;
});
The actual value is meaningless btw, a return null would work just as well.

JS - Assigning a variable while using a callback [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm relatively new to JS, and have been stuck on this problem for a while. I am trying to assign a variable from the return value of a function, like this:
var data = makeApiRequest(url);
However, the code continues before the makeApiRequest() function completes, causing data to be undefined.
I've been researching the problem for a while and found that the problem can be fixed with a callback. My issue is I'm not sure how to get data assigned to the result of makeApiRequest() in doing so.
I found this example (on callbackhell.com) that I think perfectly illustrates my problem:
var photo = downloadPhoto('http://coolcats.com/cat.gif')
// photo is 'undefined'!
Author's solution:
downloadPhoto('http://coolcats.com/cat.gif', handlePhoto)
function handlePhoto (error, photo) {
if (error) console.error('Download error!', error)
else console.log('Download finished', photo)
}
console.log('Download started')
The thing that I cannot figure out for the life of me is how photo is assigned (or even declared) in this example. I feel like if I could crack that, I could figure out my specific problem. Any help would be greatly appreciated. Thanks very much in advance.
makeApiRequest(url) is an asynchronous call. That means that if you try to evaluate it immediately after calling it, it will be undefined. The modern solution is to use a Promise.
However, a callback function is perfectly acceptable if your logic won't go layers deep. You can do so by altering the parameters on your makeApiRequest function like so:
function makeApiRequest (url, callback) {
// make the api call, and then:
callback(results);
}
Now, you will call makeApiRequest() as such:
makeApiRequest (url, function(data) {
// handle your data here.
console.log(data);
});
When download function completes, it invokes callback function handlePhoto with data (photo) passed to it as a second argument, so that it can be used inside of the handlePhoto function.
If you want to assign the return value of a promise then you could wrap the variable inside async function and later use await.
** But async and await is a new feature and not widely supported.
So in your case assuming makeApiRequest() returns a promise
async function any(){ /* using async before function declartion*/
var getValue = await makeApiRequest(); // using await
console.log(getValue); // returned value of makeApiRequest
}

ReferenceError message in javascript?

Why am i getting the following error:ReferenceError: result is not defined"
function returnData() {
_myService.getData().then(function(data) {
var result = data;
});
return result;
}
Because result is declared within the callback you passed into then. It doesn't exist outside.
You can declare it outside, but note that it won't have the data as of your return result; line later:
function returnData(){
var result; // <==== Note
_myService.getData().then(function(data){
result = data; // <==== No `var` here
})
// WON'T HAVE THE VALUE HERE, it's too soon
return result;
}
See How do I return the response from an asynchronous call? for why, and what to do about it. Basically, you don't need the returnData function at all, it doesn't add any value (other than perhaps encapsulation around _myService). It cannot return the value. So either use _myService directly, or if you're trying to hide that, just
function returnData() {
return _myService.getData();
}
...and use then in the calling code to receive it. Since again, returnData can't return the data.
#Yosvel's answer is correct, the reason is because you are making an Asynchronous call to your service.
In doing so, you must wait for a result to be returned to you, which can then be processed in your then function.
By having two return calls, your return value is undefined because it is not waiting for the callback function, but simply returning a null value.
I suppose that calling _myService.getData() you are making an Asynchronous call to a web service..
In that case you can return your service response data like this:
function returnData() {
return _myService
.getData()
.then(function(data) {
// Here you can work with the response data
return data;
});
}
Notice that you can work with the response in the callback, as you correctly passed into then.

Return result aSync function in method

First of all, I completely read all the answers on this question, but despite that I come to realize that after years of scripting I ended up in the aSync hell.
I have a method that uses an async function. Depending on the result of that function, the method should return true or false.
So, simply said:
example = {
overview: undefined,
aSyncFunction: function (callback) {
// Adds values to overview, which we will use in otherFunction
callback();
return this;
},
otherFunction: function (data) {
var result = false;
this.aSyncFunction( function () {
var available = this.overview[data.name];
// result == filter overview with supplied data)
}.bind(this));
return result;
}
};
I've created a JsFiddle to show you the exact situation I'm in: https://jsfiddle.net/copt436a/1/
Deleting the setTimeOut will deliver true, otherwise it is false.
Note, I'm cannot change aSyncFunction at the moment, so the solution must be somewhere in otherFunction
I tried to separate the callback function in a different function, but in that case the return value is stuck in that particular function otherFunction keeps returning undefined. Also using the return value of aSyncFunction does not give me the result I want, cause this returns this.
I'm completely stuck on this one, and probably the solution is quite simple.

How can I create an Angular factory with a getter and setter method without running into a race condition

I'm creating a factory to take a userId from one page, make a call to a REST API, and return the results on the following view. My initial attempts were largely taken from this answer but - unsurprisingly - I keep getting caught in a situation where the doesn't respond in time and the get() method returns an empty array.
Here's the factory itself
app.factory('GetMessages', function() {
var messages = []
function set(userId) {
Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
messages = docs
})
}
function get() {
return messages;
}
return {
set: set,
get: get
}
});
For what it's worth I'm having no trouble getting the userId into the factory as it's just passed in on a function like this
view:
<a ng-click='passToFactory(message.user.id)' href='/home/inbox/reply'>Reply</a>
controller:
$scope.passToFactory = function(id) {
GetMessages.set(id);
};
and the controller for the following view is just
$scope.messages = GetMessages.get()
The issue I'm having is that after the factory returns the empty set no further changes from the factory are recognized (even though after time elapses it does get the proper response from the API) and $scope.messages remains empty.
I've attempted to move the API call to the get method (this hasn't worked as the get method often does not get the userId in time) and I can't find a way to use a promise to force get() to wait on set() completing.
I'd prefer to keep using Restangular in the eventual solution but this is a small thing that has taken too much time so any fix works.
I'm fairly new to Angular so I'm sure there's something totally obvious but right now I'm just lost. Thanks.
The race condition that you have is that the function inside the .then method is executed asynchronously after the call to the set function. If the get function executes before the $q service fulfills the promise, the get function returns an empty array.
The solution is to save the promise and chain from the promise.
app.factory('GetMessages', function() {
var promise;
function set(userId) {
promise = Restangular.all('/api/messages/').getList({'_id': userId});
}
function get() {
return promise;
}
return {
set: set,
get: get
}
});
In your controller, chain from the promise.
GetMessages.get.then( function (docs) {
$scope.messages = docs;
}) .catch ( function (error) {
//log error
};
For more information on chaining promises, see the AngularJS $q Service API Reference -- chaining promises.
You are breaking the reference to the original messages array when you reassign it.
Try:
Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
messages.concat(docs) ; // keep same array reference
});
Simple example to explain why it isn't working
var arr = [];
var x = arr;
arr = [1,2,3]; // is now a different array reference
console.log(x); // is still empty array. x !== arr now
cherlietfl is right.
The problem is that you break the reference to the messages array since you assign a new array to messages inside your get function. But concat is doing this as well.
Try this:
Restangular.all('/api/messages/').getList({'_id': userId}).then(function(docs){
messages.splice(0, messages.length); // clear the array
messages.push.apply(messages, docs); //add the new content
});
Try assigning you function to the scope. Then call that function in the model. Like so:
// controller
$scope.getMessages = GetMessages.get;
View:
<div ng-repeat="message in getMessages()"></div>
This way when the request call finishes and the digest cycle goes through the watchers again, the get function will be called and you will get your messages.

Categories