I have a few lines of code which retrieve data from a Firebase realtime database. I want them to grab a name from objects stored there and then use this to pick a random name. do this by first retrieving all objects and storing the name values in an array. I then retrieve the number of total objects in that database and use the random function to generate a random number, and then pick that value from the array. I am not sure why this is not behaving as it should. Here is the code I am using:
const dbRefObject = firebase.database().ref().child('names');
dbRefObject.on('value', gotData);
var names = [];
function gotData(data) {
dbRefObject.once('value', function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var childData = childSnapshot.val().names;
names.push(childData);
})
namesUpdated(names);
}
)
return names;
}
function namesUpdated(names) {
randomNumber = randomNumberGenerator();
console.log(randomNumber);
console.log(names[randomNumber]);
return names[randomNumber];
}
function randomNumberGenerator() {
dbRefObject.on('value', (snap) => {
var totalRecord = snap.numChildren();
return Math.floor(Math.random() * totalRecord);
});
}
I am not sure why this is not working as when I print out the names array in gotData function it works fine. However when I try to use this in namesUpdated it says the value is undefined. Similarly, the randomNumberGenerator works fine as it returns a value in that function but does not work when I use it in namesUpdated. That function looks fine to me so I am not sure why it isnt working. Thanks in advance for any help.
There are several problems in your code. I'll try to identify the main ones and I would suggest you update your question with a new version.
First, IMHO, you should move the declaration of the names array IN the gotData() function:
function gotData(data) {
var names = [];
Secondly, in the randomNumberGenerator() function you should use once() instead of on(). You should also do return dbRefObject.once('value', (snap) => {...}).
Then, in namesUpdated(), you should note that the call to randomNumberGenerator() returns a Promise, therefore you cannot do var randomNumber = randomNumberGenerator();. You should either use then() or use async/await.
Finally, by separating your code in different functions, you are fetching the database several times, without any added value.
Related
I have this code that is called in an ajax callback once the data is fetched:
function onFetchCallback(data) {
onFetchCallback.accumData ??= [];
onFetchCallback.timeLine ??= [];
onFetchCallback.tempValues1 ??= [];
onFetchCallback.tempValues2 ??= [];
onFetchCallback.char;
const hasNulls = data.includes(null);
if (!hasNulls) {
//push values into different arrays
} else {
//push the rest of no nulls if there is any...
}
}
I dont find this clean, bacause I am checking if the arrays that accumulate the data are initialized for every callback call. I think it woull be better to have the callback function initialized, so that the arrays are created, and then call the functions that will store the data in the arrays.
So I did:
function onFetchCallback() {
function init() {
onFetchCallback.accumData ??= [];
onFetchCallback.timeLine ??= [];
onFetchCallback.tempValues1 ??= [];
onFetchCallback.tempValues2 ??= [];
onFetchCallback.char;
}
function store(data) {
const hasNulls = data.includes(null);
if (!hasNulls) {
//push values into different arrays
} else {
//push the rest of no nulls if there is any...
}
}
onFetchCallback.init = init;
onFetchCallback.store = store;
}
So then when I need to use my callback I do:
onFetchCallback();
onFetchCallback.init();
myWhateverFunc(onFetchCallback.store);
Being myWhateverFunc the one calling the callback:
function myWhateverFunc(callback) {
$.ajax({
//whatever
})
.done(function (data) {
callback(data); //CALL
});
}
This works and I find it super javasScriptic so I do it all the time. Meaning the onFetchCallback initialization + other methods call to handle the function members. I do not know js in depth so I would like to know of there are any flaws with this pattern, or if there is any other better/cooler/javaScriptStylish way to do this.
The pattern you're using has a lot of resemblence with the function constructor which is more commonly used in JavaScript.
An implementation of your code in the function constructor pattern would like like this:
function FetchCallback() {
this.accumData = [];
this.timeLine = [];
this.tempValues1 = [];
this.tempValues2 = [];
this.char;
}
FetchCallback.prototype.store = function(data) {
const hasNulls = data.includes(null);
if (!hasNulls) {
// push values into different arrays
} else {
// push the rest of no nulls if there is any...
}
};
It enables you to create an object with properties and methods which are predefined. This removes the hassle of repetition when you need multiple instances of this same object.
To use the constructor you'll need to create a new instance with the new keyword. This will return an object with all the properties and methods set.
const fetchCallback = new FetchCallback();
// Note the .bind() method!
myWhateverFunc(fetchCallback.store.bind(fetchCallback));
Edit
You'll need to specifically set the value of this to the created instance that is stored in fetchCallback. You can do this with the bind() method. This methods explicitly tells that this should refer to a specific object.
The reason to do this is that whenever you pass the store method as the callback to the myWhateverFunc, it loses it's context with the FetchCallback function. You can read more about this in this post
The main difference between this and your code is that here the FetchCallback function will be unaltered, where your function is reassigned every time you call onFetchCallback() and onFetchCallback.init(). The constructor pattern will result in more predictable behavior, albeit that the this keyword has a learning curve.
Hello so I am creating a filter search and I 'm trying to collect all the key (tags) that the user press, inside an array, however every time that a new value is push it does override the entire array. So I tried a couple of things, like spread syntax, concat, etc. But with no luck.
So my action looks like this:
const setCurrentFilters = async (context, payload) => {
if (payload) {
context.commit('setCurrentFilter');
}
}
My state
state:{
filters: JSON.parse(sessionStorage.getItem('currentFilters') || '[]'),
}
The mutation
setCurrentFilter(state, payload) {
state.filters.push(payload);
sessionStorage.setItem('currentFilters', JSON.stringify(payload));
}
And my getter
currentFilters(state) {
return state.filters;
},
Thank you in advance for any help : )
This is simply because you set const filters = []; which means that the next condition if (filters.length) will always return false (as you just created this array) and therefore the else statement will execute.
in the else statement you basically push the new payload to the empty array you just initialized - which makes your array always hold only the new value
i believe that you just need to remove the const filters = []; line, and access the filters property that exists in your state
I'm using array value as variable and then call the function N method, how I get them in function N.
I really want to simulate the Javascript array method, I don't want to use parameters to achieve it. For example,
var p1 = [1,2,3,4,5]; p1.push(6);
function _Array() {
this._this = this;
}
_Array.prototype.show = function () {
this._this.forEach(function(item){alert(item);}) //how to print 1,2,3,4,5
};
var p1 = [1,2,3,4,5];
p1 = new _Array();
//p1._Array.call(p1); //not work
// new _Array().show.call(p1); //not work
// p1.show(); //not work
You have to store that in the instance
function N(arr) {
this._this = arr
}
N.prototype.say = function () {
this._this.forEach(function (item) {
console.log(item)
})
}
p1 = new N([1, 2, 3, 4, 5])
p1.say()
If you are insistent on wanting to write a method that takes the array by reference, you can modify the array prototype like so:
Array.prototype.show = function() {
this.forEach(item => alert(item));
}
However, it is a VERY BAD IDEA to modify the built in object prototypes, as this can cause conflicts with external libraries implementing their own "show" function that is being used differently, or cause incompatibilities with future versions of JS that implements this method.
It would be far more prudent in most situations to pass the array as a parameter, unless you have a very specific reason why you're not doing so. In that case, you should at least prefix the method with some sort of project identifier to minimize the chances of conflicts occurring.
Here is my question: Instead of calling a smart contract function like this
//assuming the name of the contract function is called "balanceOf"
contract.methods.balanceOf("0x", "0x").call(err, balance) => {
console.log({err, balance});
})
i want to know if it is possible to call like this:
var funcName = "balanceOf";
var parameter = "0x, 0x";
contract.methods.funcName(parameter).call(err, balance) => {
console.log({err, balance}];
})
Thank You.
The objects in javascript can be accessed like an array by using the keys as indexes. So in your case it would be:
var funcName = "balanceOf";
var parameter = "0x, 0x";
contract.methods[funcName]("0x", "0x").call(err, balance) => {
console.log({err, balance}];
})
But the way you passing the parameter is not going to work like that. You are just passing a string as a parameter. Think of it like passing parameters to any other function.
here the user_res is updated but not the state, and I have tried binding this function to this also. but same result :(
let user_res = usr_vote;
user_res.map((vote)=>{
if(vote.id==dat_id){
vote.status = stats
}
})
console.log("update user response:",user_res)
this.setState({user_response:user_res},()=>{
console.log("but this is not uodating : ",this.state.user_response)
});
I don't think even user_res is updating. map doesn't update the original variable. You need to assign the value of .map to something.
user_res = user_res.map((vote)=>{
if(vote.id==dat_id){
return {...vote, status: stats}
} else {return vote}
})
If you check documentation form Array.prototype.map(), you will see that map doesn't modify the original array, it returns a new array with the modified items.
The map() method creates a new array with the results of calling a
provided function on every element in the calling array.
So with that information you can modify your code accordingly,
// create a new array with the modified items
let user_res = usr_vote.map((vote) => {
if(vote.id == dat_id){
vote.status = stats
}
});
// update state with the new array
this.setState({user_response:user_res},()=>{
console.log("but this is not uodating : ",this.state.user_response)
});
PS: stats is not defined anywhere in your snippet. If you are not defining it somewhere in your code that your shared snippet doesn't contain, it is OK but otherwise you need to fix that part too.