ReactJS for loop only displaying the last value in firebase query - javascript

I am trying to loop an array using for loop. As soon as the variable goes inside the firebase query, only the last value is displayed. Any idea why this is happening?
const handleClose = () => {
var tpList = TP;
for (var v in tpList) {
var tp = tpList[v];
console.log(tp);
Firebase.database().ref("Student").child(tp + "/Name/").once('value').then((res) => {
console.log("Name of " + tp + " is " + res.val());
})
}
The first console log works perfeclty fine, showing the correct values from index 0-5. However, the second console log shows only the index value of 5. Any suggestions what could be wrong here?

As mentioned in the comment, you'd use let instead of var in the loop:
const handleClose = () => {
var tpList = TP;
for (let v in tpList) { // Use let here
let tp = tpList[v]; // (optional) Also here to keep the scope inside the loop
console.log(tp);
Firebase.database().ref("Student").child(tp + "/Name/").once('value').then((res) => {
console.log("Name of " + tp + " is " + res.val());
})
}
The reasons for this is that in ES6 when using let in a loop, the declared variable will get a new binding for each iteration of the loop, so the closure will correctly capture each value of v, instead of capturing only the last one as it happens when using var.

Related

Concat In JavaScript

For some reason the keyText variable isn't showing any value when it should concat for each variable in keywords.
When someone clicks the button it runs addKeyword and grabs the value of the input.
Tried to Console.Log the keyText variable and didn't work at all.
var keywords = [];
var keyText = "";
function addKeyword() {
var keywordName = document.getElementById("keywordAdd").value
keywords.push(keywordName);
keywords.forEach(showKeywords);
function showKeywords(item, index) {
var newString = "<span class='keyword' onclick='delKeyword(" + index + ")'>✖ " + item + "</span>";
keyText.concat(newString);
document.getElementById("keywords").innerHTML = keyText;
}
}
No Errors shown in Console. Expected result is a list of but doesn't show.
The problem is that .concat doesn't mutate the string, it returns a new string.
You need to do something like this:
keyText = keyText.concat(newString);
By the way, your current approach is not that efficient because it changes the element's inner HTML at each iteration. You should probably do that only once after the HTML for all the elements is generated. Here is another approach that does that:
const result = keywords.map((item, index) => (`<span class="keyword" onclick="delKeyword(${index})">✖ ${item}</span>`)).join('');
document.getElementById("keywords").innerHTML = result;
Titus answer is correct, but you can simply use :
keyText += newString;

each() with counter - const names

I am trying to loop through some HTML elements, extract the content and set them as a const value with the index number like this...
jQuery('.myitems').each(function (index) {
const myitem + index = [jQuery(this).text()];
console.log(myitem + index);
});
This is not working, can anyone tell me the correct way to achieve?
You can use object instead of count. And your code will be broken.
See the following solution.
jQuery('.myitems').each(function (index) {
const count = {}
count[myitem + index] = [jQuery(this).text()];
console.log(count[myitem + index]);
});
Shouldnt you store the values in an array instead?
const myitem = [];
jQuery('.myitems').each(function (index) {
myitem[index] = jQuery(this).text();
console.log(myitem[index]);
});
You cannot do what you're attempting in JS. An alternative would be to populate an array with the values by using map():
var arr = $('.myitems').map(function() {
return $(this).text();
}).get();
If you still want to use the 'myitem' + index prefix on the values then you could instead use an object:
var obj = {};
$('.myitems').each(function(i) {
obj['myitem' + i] = $(this).text();
});
Here, I have first set constant and then on looping I have set value with index number. Currenlty , I have made output on console. You can check it. Let me know if you do not understand
const staff=[];
$('.staff').each(function(index){
staff[index]=$(this).text();
})
console.log(staff);

How to print out the entries of a Map into an html document

Hi there I have the following code:
function showsaveobj(){
let patient = creatobj();
let befaktoren = patient.addfaktoren();
console.log(befaktoren);
let show = document.getElementById("show");
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + (function() {for (let entry of befaktoren.entries()){return entry}})();
};
This last function is invoked when I press save inside the html document. It creates an object with a surname and a lastname and it has a method which creates a map out of the values the user has entered into the form. The form has 24 values corresponding to the 24h of the day. So the map is 24 entries long. I want to print these entries into the html document as you can see above. It works fine with the name and the surname but when I use the for..of loop to write the single entries It only prints out the first entry of the map.
When I add
for (let x of befaktoren.entries()){console.log(x);}
The console shows me 24 Arrays with the key and the value inside. When I do the same thing inside the string with innerHtml it only writes the first array of the map into the document.
I am doing something wrong here, but i cannot figure out what. After searching the web for several days now i hope someone here can help me.
Thanks in advance
I think you misunderstood the Map.entries() method. entries() does not return an iterable object that you can traverse with a for loop, but instead it returns an Iterator that contains all the entries which you can then retrieve with the next() method.
see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
A Map itself is iterable so you can use your for loop on the map itself.
Despite that
your code:
someString + (function() {
for (let entry of befaktoren.entries()) {
return entry
}
})()
will always put the first element only into your string.
instead do something like this:
var befaktorenFormatter = function(input) {
let formattedString;
// directly iterate over the input iterable
for (let entry of input) {
formattedString += entry;
}
// don't return the current entry, return the fully formatted string instead
return formattedString;
}
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + befaktorenFormatter(befaktoren);
Map has the convenience method forEach for iterating over its contents.
Also see: http://devdocs.io/javascript/global_objects/map/foreach .
Instead of using a for loop you could also do something like this:
let befaktoren = new Map([['foo', 'bar'], ['bar', 'foo']]);
let befaktorenFormatter = function(input) {
let formattedString;
input.forEach(function(value, key) {
formattedString += `${key}: ${value}<br>`;
});
return formattedString;
};
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + befaktorenFormatter(befaktoren);
I hope that helped.

defining static variable inside a function in angularJS

i am taking first steps in agularJS and got stuck trying to create a static variable in a function. the function gets a variable called cron_format and i want the function to save that value. thee function checks if user changed the value of cron_format and if so, posts the data.
this is the function:
$scope.saveCron = function(userId,scriptId,cronFormat,letter,comp,index){
//split cronFormat to match the value in the table, and than save changes
var newCron = $scope.split(cronFormat);
newCron[index] = letter;
//remove commas to match the cron's format
newCron = newCron.toString().replace(/,/g, " ");
if(letter!=comp) {
$.post("updateCronChange.php", "user_id=" + userId + "&script_id=" + scriptId + "&cron_format=" + newCron, function (data) {
console.log("cron changed to: "+newCron);
});
}
}
i want to store the variable newCron so that next time function being called, cronFormat will be equal to newCron from last execution...any help plz?
Use the fact that the function "closes over" the outer scope variables, and create one to store your previous value.
var prevCron; // Define a variable to hold the value between function calls.
$scope.saveCron = function(userId,scriptId,cronFormat,letter,comp,index){
//split cronFormat to match the value in the table, and than save changes
var newCron = $scope.split(cronFormat);
newCron[index] = letter;
//remove commas to match the cron's format
newCron = newCron.toString().replace(/,/g, " ");
if(letter!=comp) {
$.post("updateCronChange.php", "user_id=" + userId + "&script_id=" + scriptId + "&cron_format=" + newCron, function (data) {
console.log("cron changed to: "+newCron);
});
}
// Use the outer variable to store our current value.
prevCron = newCron;
}

Use "event's" output as a variable

I have a problem to manipulate checkbox values. The ‘change’ event on checkboxes returns an object, in my case:
{"val1":"member","val2":"book","val3":"journal","val4":"new_member","val5":"cds"}
The above object needed to be transformed in order the search engine to consume it like:
{ member,book,journal,new_member,cds}
I have done that with the below code block:
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr=[];
for (var i in value) {
arr.push(value[i])
};
var wrd = new Array(arr);
var joinwrd = wrd.join(",");
var filter = '{' + joinwrd + '}';
//console.log(filter);
//Ext.Msg.alert('Output', '{' + joinwrd + '}');
});
The problem is that I want to the “change” event’s output (“var filter” that is producing the: { member,book,journal,new_member,cds}) to use it elsewhere. I tried to make the whole event a variable (var output = “the change event”) but it doesn’t work.
Maybe it is a silly question but I am a newbie and I need a little help.
Thank you in advance,
Tom
Just pass filter to the function that will use it. You'd have to call it from inside the change handler anyway if you wanted something to happen:
formcheckbox.on('change', function(cb, value){
//...
var filter = "{" + arr.join(",") + "}";
useFilter(filter);
});
function useFilter(filter){
// use the `filter` var here
}
You could make filter a global variable and use it where ever you need it.
// global variable for the search filter
var filter = null;
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr = [],
i,
max;
// the order of the keys isn't guaranteed to be the same in a for(... in ...) loop
// if the order matters (as it looks like) better get them one by one by there names
for (i = 0, max = 5; i <= max; i++) {
arr.push(value["val" + i]);
}
// save the value in a global variable
filter = "{" + arr.join(",") + "}";
console.log(filter);
});

Categories