for loop only showing last object from array - javascript

Hi Stack Overflow community. I'm a beginner in .js and jQuery and I am sort of racking my brain here.
I've created an array of objects
var questions = [
{
question: "What is Capital of Canada",
choices:["Ottawa","Toronto","Montreal","Vancouver"],
},
{
question: "What is the capital of France",
choices:["Paris","Lille","Bordeaux","Lyon"],
},
{
question: "What is the capital of Brazil",
choices:["Curitiba","Rio de Janeiro","Sao Paolo","Brasilia"],
},
I've created the 'click' handler for my button
$("#nextQ").bind('click', displayQuestion);
and lastly, I've created my function with the for loop that should cycle though my questions
function displayQuestion() {
for (var i = 0; i < questions.length; i++) {
$("#quiz").html("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
};
The problem I'm having is that every time I click the "#nextQ" button in my HTML, it always displays the last item in my array, no matter how many items I have in it. It will go straight from questions[0].question to questions[2].question and .choices, or questions[9].question and .choices if I have 10 questions for example.
Any help is greatly appreciated! Nothing in the search bar made much sense to me.

Assuming you only want to display one question at a time, you have no reason to use a loop of any sort. Something like this may be more in line with what you're trying to achieve:
var i = 0;
function displayQuestion() {
$("#quiz").html("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
i++;
});
If you are trying to display all questions at the same time, then your issue is that for each iteration of your loop, you're setting the html of #quiz rather than adding to it. This will display all questions on the screen:
function displayQuestion() {
var $q = $("#quiz");
for (var i = 0; i < questions.length; i++) {
$q.append("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
};
});

I think you are trying to pop the question from the array and display it.
function displayQuestion() {
var nextQuestion= questions.pop();
$("#quiz").html("<h2>" + nextQuestion.question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ nextQuestion.choices[0] + "</li>"
+ "<li id=choice2>" + nextQuestion.choices[1]
+ "</li>" + "<li id=choice3>"
+ nextQuestion.choices[2] + "</li>"
+ "<li id=choice4>"
+ nextQuestion.choices[3] + "</li> </ol>");
};
or if you want to keep the questions in the array and increment the question index to get the next question:
var i = 0;
function displayQuestion() {
++i;
$("#quiz").html("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
};

As one of the comments said, in the loop, you overwrite the HTML of your display division with one question after another. So on every click of the button you quickly rewrite that section with each question.
I'm assuming, though, that your requirements are just to show one question at a time. That means you need to keep track of the current question somewhere. Here's a naive version:
var current = -1;
function displayQuestion() {
current += 1;
var i = current % questions.length;
$("#quiz").html("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
}
This works as you can see in a fiddle.
But I call it naive because it introduces a global state variable, which is almost never a good idea. Rather, this version encapsulates that state in the closure of your function:
var displayQuestion = (function() {
var current = -1;
return function displayQuestion() {
current += 1;
var i = current % questions.length;
$("#quiz").html("<h2>" + questions[i].question +"</h2>"
+ "<ol id=question type=A> <li id=choice1>"
+ questions[i].choices[0] + "</li>"
+ "<li id=choice2>" + questions[i].choices[1]
+ "</li>" + "<li id=choice3>"
+ questions[i].choices[2] + "</li>"
+ "<li id=choice4>"
+ questions[i].choices[3] + "</li> </ol>");
};
}());
This one is in another fiddle.
Both of these make the simplifying assumption that you will loop around to the beginning of the list when you fall off the end. That many not be justified, and you may need to do something slightly more complex.
Also note that there is no real reason for keeping the current value separate from your i variable. I was just feeling lazy.

I think you are replacing every time the question by using $("#quiz").html
You should use append function of jquery to see all the questions

Related

Can this be turned into a for loop?

I would like to clean this up with a For loop. What would be the most efficient way coding this out?
I'm creating a search form that looks through a database for the specific form criteria. The way I have it coded would only work for the 8 Fields. But it is possible for the search form to have more then 8. For now though, I'd like to be able to map the results and display in a results page.
This is what I tried. This did not work at all and probably make no sense to anyone lol.
var obj =data[0]
$.get("obj", {data: $('select["Fields.DisplayName" + Fields.DataValue]').val()},
function(data){
$.each(data, function(i, item) {
alert(item);
});
}
);
This works for getting the data and displaying it how I'd like.
var obj = data[0];
document.getElementById("test").innerHTML =
"<p>"+ obj.Fields[0].DisplayName + ": " + obj.Fields[0].DataValue + "</p>" +
"<p>" + obj.Fields[1].DisplayName + ": " + obj.Fields[1].DataValue + "</p>" +
"<p>"+ obj.Fields[2].DisplayName + ": " + obj.Fields[2].DataValue + "</p>" +
"<p>"+ obj.Fields[3].DisplayName + ": " + obj.Fields[3].DataValue + "</p>" +
"<p>" + obj.Fields[4].DisplayName + ": " + obj.Fields[4].DataValue + "</p>" +
"<p>" + obj.Fields[5].DisplayName + ": " + obj.Fields[5].DataValue + "</p>" +
"<p>"+ obj.Fields[6].DisplayName + ": " + obj.Fields[6].DataValue + "</p>" +
"<p>" + obj.Fields[7].DisplayName + ": " + obj.Fields[7].DataValue + "</p>"
;
The next problem is if there is more then 1 data object. Currently I have it set to loop through the first object, but when I remove that I get cannot read property of '0' undefined.
Sure.
var html = "";
obj.Fields.forEach(({DisplayName, DataValue}) => {
html += `<p>${DisplayName}: ${DataValue}</p>`;
});
document.getElementById("test").innerHtml = html;
Use Array.map() and join the results:
var fields = data[0].Fields ;
document.getElementById("test").innerHTML = fields
.map(function(field) {
return '<p>' + field.DisplayName + ': ' + field.DataValue + '</p>';
})
.join('\n');

Try make a poll with getJSON() and jsonp the issue is the view is blinking

I try make a poll, basically I refresh my petition every 3s to the API using jsonp and getJSON the problem is my view also refresh at the same time and blink in the interface of the client (HTML), I have some like this
var chatbox = $("#chatbox");
singleChatView();
setInterval(function () {
chatbox.empty();
singleChatView();
}, 1000);
function singleChatView() {
var chatid = localStorage.getItem('chatid');
$.getJSON("http://myapi/?chatid=" + chatid + "&jsonp=?", function (chats) {
console.log(chats);
$.each(chats.DATA, function (key, c) {
$('.msgRecipientName').text(c.SENTBY.name);
if (c.SENTBY.id == userInfo.PROFILE.USERID) {
chatbox.append(
"<li class='msgThread group currentUser'>" +
"<div class='msgBalloon group'>" +
"<div class='msgHeader'>" +
"<div class='msgFull'>" + c.MESSAGE + "</div>" +
"</div>" +
"</div>" +
"<div class='msgDate'>" +
formatDate(c.CREATEDON) +
"</div>" +
"</li>"
);
} else {
chatbox.append(
"<li class='msgThread group'>" +
"<div class='msgAuthor' style='background: #fff url(myapi/100_couple.png) 50% background-size: cover;'>" +
"<a ng-href=''>" +
"<span></span>" +
"</a>" +
"</div>" +
"<div class='msgBalloon group'>" +
"<div class='msgHeader'>" +
"<div class='msgFrom'>" + c.SENTBY.name + "</div>" +
"<div class='msgFull'>" + c.MESSAGE + "</div>" +
"</div>" +
"</div>" +
"<div class='msgFrom'>" + c.SENTBY.name + "</div>" +
"<div class='msgDate'>" + formatDate(c.CREATEDON) + "</div>" +
"</li>"
);
}
});
});
}
I don't have any idea how I can do this and void this issue with the view, can some one help me, all this is new for me thanks
I would suggest trying the following. The blink is most likely due to you clearing the chatbox and not putting anything in there until the ajax returns. This version, aside from reducing the number of times the DOM is changed, also doesn't replace the chatbox until it has built all the html that should be in it.
var chatbox = $("#chatbox");
//start the chat loop
singleChatView();
function singleChatView() {
var chatid = localStorage.getItem('chatid');
$.getJSON("http://myapi/?chatid=" + chatid + "&jsonp=?", function(chats) {
console.log(chats);
//collect the messages
//if we update the page once, the browser has to do less work rendering
//all the changes
var messages = [];
//keep track of the "c.SENTBY.name"
//since you are doing a global selector and setter, the value will
//end up being the last value you update all them to be anyway
//no need to update multiple times
var sendby = '';
$.each(chats.DATA, function(key, c) {
sentby = c.SENTBY.name;
if (c.SENTBY.id == userInfo.PROFILE.USERID) {
messages.push(
"<li class='msgThread group currentUser'>" +
"<div class='msgBalloon group'>" +
"<div class='msgHeader'>" +
"<div class='msgFull'>" + c.MESSAGE + "</div>" +
"</div>" +
"</div>" +
"<div class='msgDate'>" + formatDate(c.CREATEDON) + "</div>" +
"</li>"
);
} else {
messages.push(
"<li class='msgThread group'>" +
"<div class='msgAuthor' style='background: #fff url(myapi/100_couple.png) 50% background-size: cover;'>" +
"<a ng-href=''>" +
"<span></span>" +
"</a>" +
"</div>" +
"<div class='msgBalloon group'>" +
"<div class='msgHeader'>" +
"<div class='msgFrom'>" + c.SENTBY.name + "</div>" +
"<div class='msgFull'>" + c.MESSAGE + "</div>" +
"</div>" +
"</div>" +
"<div class='msgFrom'>" + c.SENTBY.name + "</div>" +
"<div class='msgDate'>" + formatDate(c.CREATEDON) + "</div>" +
"</li>"
);
}
});
//update the recipent with the last sent by, once
$('.msgRecipientName').text(sentby);
//replace all the chatbox text with the collected html that would have
//otherwise been append one at a time
chatbox.html(messages);
//now that we've finished this iteration, start the next iteration after
//a second
setTimeout(singleChatView, 1000);
});
}

Trouble with jQuery loop through array of objects

I'm trying to nest 3 divs within a "row" div.
I had this working in "long format" (multiple var's instead of looping through the array). I've refactored my code and now I don't get any error codes AND my code does not append to the HTML file. When I console log I get an array with 3 objects. I'm sure i'm missing something minor.
Anyways some help would be great!
<div class="row">
**nested divs go here.
</div>
$(document).ready(function() {
$.get("http://api.openweathermap.org/data/2.5/forecast/daily?id4726206&cnt=3", {
APPID: "MY API KEY",
lat: 29.423017,
lon: -98.48527,
units: "imperial"
}).done(function(data) {
var stationId = data.city.name;
// Stattion Name
$('#station').append(stationId);
//console.log(data);
var forecast = data.list;
//Wind Direction in Compass Format
function getDirection(dir) {
var compass = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'];
var result = Math.floor((360 - dir) / 22.5);
return compass[result];
}
//Forecast Variables
$.each(forecast, function(i, v) {
var html = '';
html += "<div class='col-sm-3 wInfo'>" + "<div class='title'>High / Low</div>";
html += "<div class='cTemp'>" + (Math.ceil(forecast[i].temp.max)) + '°';
html += " / " + (Math.ceil(forecast[i].temp.min)) + '°' + "</div>";
html += "<div class='tempIcon'>" + "<img src='http://openweathermap.org/img/w/" + forecast[i].weather[0].icon;
html += ".png' alt=''></div>" + "<div class='conditions' id='castId'>" + '<span class="cond">' + forecast[i].weather[0].main;
html += "</span>: " + "<span>" + forecast[i].weather[0].description + '</span>' + "</div>";
html += "<div class='conditions'>" + "<span class='cond'>Humidity: </span>" + "<span>" + forecast[i].humidity + "%</span></div>";
html += "<div class='conditions'>" + "<span class='cond'>Wind: </span>" + "<span>" + (Math.floor(forecast[i].speed));
html += " mph / " + getDirection(forecast[i].deg) + "</span></div>" + "<div class='conditions'>";
html += "<span class='cond'>Pressure: </span>" + "<span>" + forecast[i].pressure + "</span></div>";
return html;
});
$('.forecast').append(forecast);
console.log(forecast);
});
});
You are trying to append the array forecast in html. which wont work. You should declare the html variable outside and then use it in append function.
I will also recommend to use string builder logic using array and then convert it to string and append it. remember string concatenation is heavy operator as it creates new instance of elememt every time concatenation is done :
var html = [];
$.each(forecast, function(i, v) {
html.push("<div class='col-sm-3 wInfo'>" + "<div class='title'>High / Low</div>");
html.push("<div class='cTemp'>" + (Math.ceil(forecast[i].temp.max)) + '°');
html.push(" / " + (Math.ceil(forecast[i].temp.min)) + '°' + "</div>");
html.push("<div class='tempIcon'>" + "<img src='http://openweathermap.org/img/w/" + forecast[i].weather[0].icon);
html.push(".png' alt=''></div>" + "<div class='conditions' id='castId'>" + '<span class="cond">' + forecast[i].weather[0].main);
html.push("</span>: " + "<span>" + forecast[i].weather[0].description + '</span>' + "</div>");
html.push("<div class='conditions'>" + "<span class='cond'>Humidity: </span>" + "<span>" + forecast[i].humidity + "%</span></div>");
html.push("<div class='conditions'>" + "<span class='cond'>Wind: </span>" + "<span>" + (Math.floor(forecast[i].speed)));
html.push(" mph / " + getDirection(forecast[i].deg) + "</span></div>" + "<div class='conditions'>");
html.push("<span class='cond'>Pressure: </span>" + "<span>" + forecast[i].pressure + "</span></div></div>");
});
$('.forecast').append(html.join(""));

Need assitance with pulling JSON item

I am working with a JSON DB and displaying ingredients on the page. I have a separate HTML page for each recipe. I am creating an unordered list on the page and manually typing in the recipe ingredients for the recipe on the page.
I am trying to pull in the recipe name from the DB but I cant get it to show. I want to pull in the correct item if it matches the item UPC in the DB. Please see below.
$(document).ready(function() {
'use strict';
$.ajax({
dataType: "jsonp",
url: '',
success: function(data){
$.each(data, function(i, item) {
$('#recipeIngredients').html(
"<ul>" +
"<li>" + '1/2 tsp sugar' + "</li>" +
"<li>" + '1/2 tsp salt' + "</li>" +
"<li>" + '3 tbsp ' + (item.itemFullUPC == "070796150062" ? item.itemName : "" ) + "</li>" +
"<li>" + '1 pkg active dry yeast' + "</li>" +
"<li>" + '3/4 cup warm water' + "</li>" +
"<li>" + '2 tbsp ' + (item.itemFullUPC == "070796150012" ? item.itemName : "" ) + "</li>" +
"<li>" + '2 cups shredded mozzarella cheese' + "</li>" +
"</ul>"
);
});
} }) });
You're overwriting the HTML every time through the loop, so the final result will just be from the last item in the array.
Instead, you should use an if statement, and only display the items that matches the UPC code you want.
Then you should use .append() rather than .html() so you add the <ul> to the list, instead of overwriting it.
$.each(data, function(i, item) {
if (item.itemFullUPC == "070796150012") {
$('#recipeIngredients').append(
"<ul>" +
"<li>" + '1/2 tsp sugar' + "</li>" +
"<li>" + '1/2 tsp salt' + "</li>" +
"<li>" + '1/2 tsp salt' + "</li>" +
"<li>" + '1 pkg active dry yeast' + "</li>" +
"<li>" + '3/4 cup warm water' + "</li>" +
"<li>" + '2 tbsp ' + item.itemName + "</li>" +
"<li>" + '2 cups shredded mozzarella cheese' + "</li>" +
"</ul>"
);
}
});

jquery $.each not giving all the information in the table

Fiddle
I want to put the names of all record in my array into a table my array isn't index correctly so i used $.each instead of iterating over the using for loop. My problem is I only get to show the last element but if i try to show a value that is existing to both the array it is showing correctly.
What am i missing in this code.
Any idea is appreciated
This is my javascript
for (var i = 0; i < name.length; i++) {
var names = name[i].Names;
$.each(names, function (item, names) {
tr = $('<tr class=""/>');
//console.log(complainant[obj]);
//var names = complainant[obj];
//if(names.hasOwnProperty('fname')){
console.log(names.suffix);
var acronymc;
var upper = names.mname.toUpperCase();
if (upper) {
var matches = upper.match(/\b(\w)/g);
//var matches = upper.replace(/^(\S+)\s+(\S).*/, '$1 $2.');
//acronym = upper.slice(0,1);
var acronym1 = matches.join('');
acronymc = acronym1.slice(-1);
} else {
acronymc = '';
}
tr.append("<td id=''>" + "<span id='fname'>" + names.fname + "</span>" + " " + "<span id='mname'>" + acronymc + "</span>" + " " + "<span id='lname'>" + names.lname + "</span>" + " " + "<span id='suffix'>" + names.suffix + "</span>" + "</td>");
tr.append("<td id=''>" + '<span id="street">' + names.street + '</span>' + " " + '<span id="brgy">' + names.brgy + '</span>' + " " + '<span id="town">' + names.town + '</span>' + " " + '<span id="city">' + names.city + '</span>' + "</td>");
tr.append("<td id=''>" + names.contactnum + "</td>");
tr.append("<td id=''>" + "<a href='#' class='editcomplainant'>Edit</a>" + "/" + "<a href='#' class='delete'>Delete</a>" + "</td>");
//}
});
$("#nameslist").append(tr);
}
Put the $('#nameslist').append(tr); call inside the $.each block.
Here is a way of improving the creation of tds:
var html =
"<td>" +
"<span id='fname'/> " +
"<span id='mname'/> " +
"<span id='lname'/> " +
"<span id='suffix'/>" +
"</td>";
var td = $(html);
td.find('#fname').text(names.fname);
td.find('#mname').text(acronymc);
td.find('#lname').text(names.lname);
td.find('#suffix').text(names.suffix);
tr.apppend(td);
Why is this better (imho)?
You will not create unintentional html tags by having < and > inside the variables.
Appropriate escaping (auml codes) will be automatically generated
It is easier to read

Categories

Resources