Closure issue - Nested for loops only print out once - javascript

Here is a very well know post on stack overflow JavaScript closure inside loops – simple practical example but I can't seems to get my head around with it.
My little script below successfully print out each location on the screen. When I click on the marker on the maps it will bring up the pop up windows and it will display the correct image and the menu inside the info windows. The problem I am facing now is I fail to output if each store has more than one image and menu. For example, If I assigned 2 image and 2 menu to a specific store, the output I got on screen is always the last row from the database. From my understanding, i believe it has to do with JavaScript closure but I am yet to arrive that level of understanding.
var funcs = [];
for (var i = 0; i < locations.length; i++) {
for (var x = 0; x < store.length; x++) {
if (i < store.length) {
if (store.location_id == locations[i].id) {
//alert(gon.store[x].menu);
var contentString = "";
(funcs[x] = function() { //closure
contentString =
'<div id="content1">' +
'<div class="container">' +
'<div class="p-3 mb-6 bg-dark text-white text-center" style="margin-bottom:30px;" >Available Store</div>' +
'<div class="row">' +
'<div class="col">' +
'<img src="' + store.image + ' width="150px" height="150px">' +
'</div>' +
'<div class="col text-center">' +
'<table class="table">' +
'<tbody>' +
'<tr>' +
'<th scope="row">Menu</th>' +
'<td>' +
store.menu +
'</td>' +
'</tbody>' +
'</table>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
})(x);
}
}
}
//contentString+=contentString;

Related

why gihub pages wont load conditionals of JS script

My code is working properly on liveserver, but when I merge on github and open using github pages both conditionals "if" dont work at all. It's something that should be apllied on all pages.
This is how I load on HTML
<head>
<script src="./JS/header.js" defer></script>
</head>
<body>
<header id="header"></header>
This is the JS code:
function insertHeader(){
var codeBlock1 = '<div class="container">' +
'<img class="logo" src="./assets/logo.jpeg" alt="logo página">' +
'<div class="menu-section">' +
'<div class="container-menu">' +
'<input type="checkbox" id="checkbox-menu" />' +
'<label class="menu-button-container" for="checkbox-menu">' +
'<span></span>' +
'<span></span>' +
'<span></span>' +
'</label>' +
'<nav>' +
'<ul class="menu">' +
'</ul>' +
'</nav>' +
'</div>' +
'</div>' +
'</div>';
document.querySelector("#header").innerHTML += codeBlock1;
const urlAtual = window.location.pathname.substring(1);
if (urlAtual !== 'index.html'){
var codeBlockHome = '<li>' +
'Home' +
'</li>';
document.querySelector(".menu").innerHTML += codeBlockHome;
};
var codeBlockLocais =
'<li>' +
'Locais' +
'<ul class="submenu-locais">' +
'<li>Pontos Turísticos</li>' +
'</ul>' +
'</li>';
document.querySelector(".menu").innerHTML += codeBlockLocais;
if (urlAtual !== 'team.html'){
var codeBlockTeam = '<li>' +
'Equipe' +
'</li>';
document.querySelector(".menu").innerHTML += codeBlockTeam;
};
var codeBlockContato = '<li>' +
'Contato' +
'</li>';
document.querySelector(".menu").innerHTML += codeBlockContato;
for (i=0; i< estados.length; i++){
estadosNome[i] = estados[i].slice(0, -5);
estadosSigla[i] = estados[i].split(' ').pop();
var codeBlock2 = `<li>${estadosNome[i]}</li>`;
document.querySelector(".submenu-locais").innerHTML += codeBlock2;
}};
insertHeader();
Only "ifs" dont work, and I already solved this problem with CSS. But I'm still curious to why it worked on liveserver and not on github pages.

click a div in an .append with a loop

I am using an .append to populate a div-id and all that works fine, i even get the loop inside, however i would like to make an item clickable inside the loop and load a div that holds details of that item. This is what i got so far.
<div id="GameContainer"></div>
var gamesData; //A global variable to hold Ajax response.
$.ajax({
type: 'Get',
url: "http://"URL/" + GamesList,
success: function (data) {
gamesData = data; // add the Ajax data to the global variable
var dynamic = "";
for (i = 0; i < data.length; i++) {
dynamic += '<div id="' + data[i].id_game + '" class="TopContainerCel" onclick="GameDetails(' + data[i] + ')">'
+ ' <div class="TopContainerCelBackground">'
+ ' <img class="TopContainerCelImage" src="' + data[i].CoverImage + '" />'
+ ' </div>'
+ ' <div class="TopContainerCelName">' + data[i].Name + '</div>'
+ ' </div>'
};
$('#GameContainer').append(''
+ '<div class="TopContainerScroll">'
+ dynamic
+ '</div>');
}
})
// based on the solution of K K [extended with an array.find]
added the global variable gamesData and filled it with the Ajax reponse
$(document).on("click", ".TopContainerCel", function () {
var elem = $(this);
console.log(elem[0].id) // the actual id clicked is there
console.log(gamesData) // all the data of the Ajax response is there
GameID = elem[0].id;
var gameData = gamesData[elem.data("id")]; // part that does not work
var gameData = gamesData.find(x => x.id_game == GameID); // works!
//gameData has the data
console.log(gameData)
});
So i found a diffent way of combining the two data together by using a find in the array. Is there a better way of doing this? If so why and what is the difference?
Try something similar to this:
var gamesData;//A global variable to hold Ajax response.
$.ajax({
type: 'Get',
url: "http://URL/" + GamesList,
success: function (data) {
gamesData = data;
var dynamic = "";
for (i = 0; i < data.length; i++) {
dynamic += '<div id="' + data[i].id_game + '" data-id="'+data[id]+'" class="TopContainerCel">'
+ ' <div class="TopContainerCelBackground">'
+ ' <img class="TopContainerCelImage" src="' + data[i].CoverImage + '" />'
+ ' </div>'
+ ' <div class="TopContainerCelName">' + data[i].Name + '</div>'
+ ' </div>'
};
$('#GameContainer').append(''
+ '<div class="TopContainerScroll">'
+ dynamic
+ '</div>');
}
})
$(document).on("click",".TopContainerCel",function(){
var elem = $(this);
var gameData = gamesData[elem.data("id")];
//gameData has your data
});
Note: The approach here is to store ajax response in a variable. From your code, the response is an array. So, when you iterate over the items, get the index of the clicked item in any way you prefer and access the detail of game using the index from gamesData.
you can add data-id to dynamic like : <div data-id="'+data[i].id+'".
then you can do :
var games = {};
for (i = 0; i < data.length; i++) {
games[data[i].id_game] = data[i];
dynamic += '<div id="' + data[i].id_game + '" class="TopContainerCel" onclick="GameDetails(' + data[i] + ')">'
+ ' <div class="TopContainerCelBackground">'
+ ' <img class="TopContainerCelImage" src="' + data[i].CoverImage + '" />'
+ ' </div>'
+ ' <div class="TopContainerCelName">' + data[i].Name + '</div>'
+ ' </div>'
};
$("#GameContainer").on('click','.TopContainerCel',function() {
var $this = $(this);
console.log(games[$this.data('id')])
// code logic here
});

Load iframe Inside Modal on Button Click

I'm building a retail website using Bootstrap. For the products there is a thumbnail with a "More Info" button that loads a modal. Inside of the modals is an iframe with more information for the bike. When I load the page it loads every iframe (about 60). I'm trying to figure out how to load the iframe (var bike_modal_descriptions_giant) when the appropriate button is clicked.
I have the site up for testing here: Site
I'm using a javascript loop to populate the thumbnails.
Screenshot of thumbnails.
Script that reads from other file to populate thumbnails, just changed for each brand:
<script>
for (i = 0; i < num_items_giant; i++) {
if (i % 3 == 0) {
document.getElementById('catalogue').innerHTML += '<div class="row">';
}
document.getElementById('catalogue').innerHTML += '<div class="col-sm-6 col-md-4">'
+ '<div class="thumbnail">'
+ '<img src=' + bike_pics_giant[i] + '>'
+ '<div class="caption">'
+ '<h3>' + bike_titles_giant[i] + '</h3>'
+ '<p>' + bike_descriptions_giant[i] + '</p>'
+ '<p><button onclick="" type="button" class="btn btn-default" id="btn-giant' + i + '">More Info</button></p>'
+ '<div class="modal fade" id="modal-giant' + i + '" role="dialog">'
+ '<div class="modal-dialog">'
//<!-- Modal content-->
+ '<div class="modal-content">'
+ '<div class="modal-header">'
+ '<button type="button" class="close" data-dismiss="modal">×</button>'
+ '<h4 class="modal-title">' + bike_titles_giant[i] + '</h4>'
+ '</div>'
+ '<div class="modal-body">'
+ '<p>' + bike_modal_descriptions_giant[i] + '</p>'
+ '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>';
if (i % 3 == 0) {
document.getElementById('catalogue').innerHTML += '</div>';
}
}
</script>
Modal Script:
<script>
/* Giant */
for (i = 0; i < num_items_giant; i++) {
setupButton("btn-giant" + i, "modal-giant" + i);
}
/* Liv */
for (i = 0; i < num_items_liv; i++) {
setupButton("btn-liv" + i, "modal-liv" + i);
}
function setupButton(button, modal){
$(document).ready(function(){
$("#" + button).click(function(){
$("#" + modal).modal();
});
});
}
</script>
Truncated version of modal content file. Each section is an array and each row creates a new thumbnail:
var num_items_giant = 38;
var bike_pics_giant = ["pictures/bikes/2016/road/Propel/Propel-Adv-SL-0/Propel-Advanced-SL-0-Comp.jpg",
"pictures/bikes/2016/road/Propel/Propel-Adv-SL-Team/Propel-Adv-SL-Team.jpg"];
var bike_titles_giant = ["Giant Propel Advanced SL 0",
"Giant Propel Advanced SL Team"];
var bike_descriptions_giant = ["This pro peleton standout is the pinnacle of aero road. A killer in the sprints, with sublime overall ride quality.<br><strong>$9000</strong>",
"This pro peleton standout is the pinnacle of aero road. A killer in the sprints, with sublime overall ride quality.<br><strong>$6900</strong>";
var bike_modal_descriptions_giant = ["<iframe style=\"border:none\" width=\"710\" height=\"700\" src=\"https://www.giantretailacademy.com/go/?c=US&axid=600043\"></iframe>",
"<iframe style=\"border:none\" width=\"710\" height=\"700\" src=\"https://www.giantretailacademy.com/go/?c=US&axid=615001\"></iframe>";

Javascript html gallery

Im editing/creating the following script for my website.
As you can see below I want him to add a <div class="row"> at the start of every row. (Hard to explain).
Then with the var "getal" I want him to END this DIV tag after 4 items in it (4x the foreach loop)
But the way I'm trying to do it with the If loops is not working. Any ideas? (The code is working fine without the <div class="row">, if loops and var getal.
function show_albums (response) {
var getal = 0;
//hide main loader
$('#loading_gallery').hide();
$.each(response.data, function(key, value) {
//create html structure
//rijen teller
if (getal = 0 ) {
var html = '<div class="row">';
$('#albums').append(html);
}
//albums
var html = '' +
'<div class="col-lg-3 col-md-3 col-xs-3 thumb" id="album_' + key + '"> ' +
'<img class="img-thumbnail" id="album_cover_' + key + '" />' +
'<img id="loading_' + key + '" src="images/ajax-loader.gif" />' +
'<h2>' + value.name + '</h2>' +
'<p>' + value.count + ' foto's</p>' +
'</div>';
getal++;
if (getal = 4) {
var html = '</div>';
$('#albums').append(html);
getal = 0;
}
$('#albums').append(html);
}
}
You are using the assignment operator = instead of the comparison operator == in your if statements. Try replacing those.

passing value to a dynamic created function in javascript

I am having some problems while creating a dynamic webpage in javascript.
My idea is to read a list of events and people signed up on them. I create a page with all events (each event is a button) and clicking on one of them, see the list of users.
This works fine. But now, I am adding a button to export some of these users to an excel file. And I want to add a button with an onClick function like this:
...onclick=functionÇ(id_Event, numberOfUsers, listOfUsers)...
Inside of the html code generated by javascript. I found some problems also doing like this so I changed so:
var td = document.createElement("td");
var input = document.createElement("input");
input.setAttribute("type","button");
input.setAttribute("value","Exportar a Excel CSV");
input.onclick = function() {
saveExcelFunctionControl(arrayNumberUsersInEvents[i], response);
};
td.appendChild(input);
document.getElementById("added"+element[i].id_Event).appendChild(td);
I created a global array called arrayNumberUSersInEvents in which I am adding in each possition, people subscribed. i, is the id counter for each position.
But even this, I am getting an undefined while reading the value of the firsdt parameter. I think it is a problem of dynamic data, I am not executing the function I want to each time I click the button. Do you know how to do something like this?
To sum up: My problem is that I want to pass some arguments to a function in a dynamic created page. I don't know how to pass the data and read the correct parameters inside.
I added my code because one user asked for it:
for(i = 0; i < element.length; i++){
$(".eventsControl").append(
'<li id="listControl'+ element[i].id_Event +'">'+
'<a href="#EventControl' + element[i].id_Event + '"' + 'data-transition="slidedown">'+
'<img class="crop" src= "' + element[i].image + '" />'+
'<h2>' + element[i].name + '</h2>'+
'<p>' + "Desc: " + element[i].description +'</p>'+
'</a>'+
'</li>'
).listview('refresh');
//console.log(response);
//BUCLE for setting all users in each event. Better use some string and after, join all of them
header = ' <div width="100%" data-theme = "e" data-role="page" id='+ element[i].id_Event +
' data-url="EventControl' + element[i].id_Event + '"> ' +
' <div data-theme = "a" data-role="header"><h1>Lista de Asistencia</h1> ' +
' </div>'+
' <div data-role="content"> ' +
' <fieldset data-role="controlgroup" data-type="horizontal" style="text-align: center">' +
' <div style="width: 500px; margin: 0 auto;">';
//header = header + '<input data-theme = "c" onclick="saveExcelFunctionControl(this)" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
eval('var numberUsers' +element[i].id_Event + "=1");
arrayNumberUsersInEvents[i] = 0;
if(response.length>0){
bucle = ' <table width="100%" border="1" align="left"><tr>'+
' <th>Nombre</th>'+
' <th>Primer apellido</th>'+
' <th>Segundo apellido</th>'+
' <th>NIF</th>'+
' <th>Asistencia</th>'+
' </tr>';
for(iData = 0; iData < response.length; iData++){
if(element[i].id_Event == response[iData].id_Event){
//console.log(response[iData].name);
bucle = bucle + '<tr><td>'+ eval('numberUsers' +element[i].id_Event) +'</td><td>'+ response[iData].name +'</td><td>'+
response[iData].surname1 +'</td><td>'+
response[iData].surname2 +'</td><td>'+
response[iData].NIF + '</td>'+
'<td> '+
'<input type="checkbox" id="checkBox'+element[i].id_Event+'_'+iData+'" name="option'+iData+'" value="'+iData+'"> '+
'</td>'+
'</tr>';
eval('numberUsers' +element[i].id_Event + "++");
arrayNumberUsersInEvents[i] = arrayNumberUsersInEvents[i]+1;
}
}
//header = header + '<input data-theme = "a" onclick="saveExcelFunctionControl(\""element[i].id_Event "\","" + numberUsers + "\",\"" + response+ "\"")" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
//header = header + '<input data-theme = "a" onclick="saveExcelFunctionControl(""+numberUsers+"")" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
bucle = bucle + '</table>';
$("#controlList").after(header + bucle + '<div id=added'+element[i].id_Event+'></div>');
var td = document.createElement("td");
var input = document.createElement("input");
input.setAttribute("type","button");
input.setAttribute("value","Exportar a Excel CSV");
input.onclick = function() {
saveExcelFunctionControl(arrayNumberUsersInEvents[i], response);
};
td.appendChild(input);
document.getElementById("added"+element[i].id_Event).appendChild(td);
}
}
},
error: function(xhr, status, message) { alert("Status: " + status + "\nControlGetEventsRegister: " + message); }
});
You can use closure to pass parameters to dynamically created onclick handler:
input.onclick = (function() {
var arr = arrayNumberUsersInEvents[i];
var resp = response;
return function() {
saveExcelFunctionControl(arr, resp);
}
})();
How do JavaScript closures work?
var td = document.createElement("td");
var input = "<input type='button' value='Exportar a Excel CSV'";
input+= "onclick='saveExcelFunctionControl(""" +arrayNumberUsersInEvents[i]+""","""+ response+""");' />";
};
td.textContent=input;
document.getElementById("added"+element[i].id_Event).appendChild(td);
try this way

Categories