I've created a comment system that posts comments in an ordered list. My requirememnts were to add hide/show toggle function to each comment.
Currently, the toggle function only works on the first comment (even when you try to click on 2nd, 3rd, etc.)
I've tried to use querySelectAll, but it didn't work for me. What am I doing wrong?
<div class="textbox">
<h3>Leave comments</h3>
<label for=msg>Name</label><br>
<input type=text id=fname> <br>
<label for=msg>Content</label><br>
<textarea id=msg> </textarea>
<br>
<input type=button onclick="postcomments()" value="Send" />
<input type="reset" value="Reset" />
<ol id="showcomments" style="max-width:200px; font-size:12px; padding-left:10px;">
</ol>
</div>
<script>
var ans = [];
function postcomments() {
var fname = document.getElementById("fname").value;
var msg = document.getElementById("msg").value;
var lastpos = ans.length;
var current = new Date();
console.log(current);
var time = current.getHours() + ":" + (current.getMinutes() < 10 ? '0' : '') + current.getMinutes();
var date = current.getDate() + "." + (current.getMonth() + 1) + "." + current.getFullYear();
var i = 0;
ans[lastpos] = '<img src="Media/minusicon.png" alt="minusicon" onclick="toggle(document.getElementById("txt"))" style="width:8%;" id="plusminusicon">' + " " + "Sent By" + " " + '' + fname + '' + " " + " In" + " " + date + " " + "At" + " " + time + '<br>' + '<span id="txt" class="toggle_panel">' + msg + '</span>' + '<br>' + '-------------------------------';
var ol = document.getElementById("showcomments");
ol.innerHTML = "";
for (var i = 0; i < ans.length; i++) {
ol.innerHTML += "<li id=" + (i + 1) + ">" + ans[i] + "</li>";
}
}
function toggle(x) {
if (x.style.display === "none") {
x.style.display = "block";
document.getElementById("plusminusicon").src = "Media/minusicon.png";
} else {
x.style.display = "none";
document.getElementById("plusminusicon").src = "Media/plusicon.png";
}
}
</script>
You have always the same id for all "txt" span, so the browser change always the first.
If you don't want change much of your code the simpliest solution is add the lastpost variable to the span id and to the parameter of toggle function.
Here the changes to do:
ans[lastpos] = '<img src="Media/minusicon.png" alt="minusicon" onclick="toggle(' + lastpos + ')" style="width:8%;" id="plusminusicon' + lastpos + '">' + " " + "Sent By" + " " + '' + fname + '' + " " + " In" + " " + date + " " + "At" + " " + time + '<br>' + '<span id="txt' + lastpos + '" class="toggle_panel">' + msg + '</span>' + '<br>' + '-------------------------------';
function toggle(x) {
let comment = document.getElementById("txt" + x);
let icon = document.getElementById("plusminusicon" + x);
if (comment.style.display === "none") {
comment.style.display = "block";
icon.src = "Media/minusicon.png";
} else {
comment.style.display = "none";
icon.src = "Media/plusicon.png";
}
}
To bind click listeners to dynamically added elements, you can use event delegation.
document.addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('comment')) {
// do something
}
})
jQuery makes it even easier.
$(document).on('click','.comment',function(){ //do something })
And here's a jsfiddle link to the complete code example. https://jsfiddle.net/ep2bnu0g/
So I have this command that's supposed to display a player's stats if it's found and says player not found otherwise. After I search a player and go to the previous screen, I get "player not found". I thought it was because my loop continues running after the player is found and my boolean becomes false, so I added a break statement. Won't work
function Search(Table, Stat1, Stat2, Stat3, Stat4, Stat5) {
onEvent("Search2.btn", "click", function() {
readRecords(Table, {}, function(records) {
var SearchPlayer = getText("text_input1");
var found = false;
for (var i = 0; i < records.length; i++) {
if ((records[i]).Player == SearchPlayer) {
setScreen("DisplaySearch");
setText("label3", records[i].Player + " Stats" + "\n" + records[i][Stat1] + " " + Stat1 + "\n" + records[i][Stat2] + " " + Stat2 + "\n" + records[i][Stat3] + " " + Stat3 + "\n" + records[i][Stat4] + " " + Stat4 + "\n" + records[i][Stat5] + " " + Stat5 + "\n");
setText("text_input1", "");
setText("label5", "");
found = true;
break;
} else if ((found == false)) {
setText("label5", "Player Not Found");
}
}
});
});
I would need to keep the value from the loop where authorId = 1 and then print it out as another value in the next loop (authorId = 3). I mean that I need to keep authorSurname.value (id = 1) and print it in the loop (authorId = 3) as the secondAuthor.value because in the loop (authorId = 3) the string authorSurname takes another value. Can you tell me how can I fix it?
if(authorId === 0) {
div.innerHTML = firstAuthorSurname.value + year.value + page.value + pageOtherValue;
}
else if (authorId === 1) {
div.innerHTML = firstAuthorSurname.value + " i " + authorSurname.value + " (" + year.value + ");
var secondAuthorSurname = authorSurname.value;
}
else if (authorId === 2) {
return secondAuthorSurname;
div.innerHTML = firstAuthorSurname.value + ", " + secondAuthorSurname.value + " and " + authorSurname.value + " (" + year.value + ") " + firstAuthorSurname.value + ", " + secondAuthorSurname.value + " and " + authorSurname.value + ", " + year.value + ")" + firstAuthorSurname.value + ", " + secondAuthorSurname.value + " and " + authorSurname.value + ", " + year.value + ") showed that... ";
}
Your code does not contain a loop but if you would like to save a value to use outside of a for loop declare the variable outside the loop and then you will have access to it outside the loop.
text = "";
cars = ["honda", "chevy"];
for (i = 0; i < cars.length; i++) {
text += cars[i];
}
console.log(text);
>>hondachevy
If you are trying to save a value to be used in a different condition in the if statement inside a for loop you can follow the same pattern
text = "";
for (i = 0; i < 4; i++) {
if(i === 0){
text += "to be used when i is 1";
}
else if(i === 1){
console.log(text);
text += " hello";
}
}
console.log(text);
output
>>to be used when i is 1
>>to be used when i is 1 hello
Also why don't you use a switch statement instead of a long if else. See the link below for how to do switch statements in javascript.
http://www.w3schools.com/js/js_switch.asp
I have some divs which are generated by jquery. Inside there is showing up the price, the title and the selected option value.
I've tried a lot of things to hide each div class "result" if no option is select, but with no luck.
Is there a way to hide each div without rewriting the whole code?
JS:
function pcc_calc_forms() {
jQuery(".calcolare").each(function (e) {
var t = jQuery(this).attr("id");
var n = pcc_form_data(t);
jQuery("#" + t + "-mostra").html('<h3 class="pcc-total">Totale : ' + n[0] + "" + "€" + '</h3><div class="content">' + n[1] + '<br /><br /></div>')
})
}
function pcc_form_data(e) {
var t = new Array(0, "");
var n = new Array;
var r = new Array;
$("#" + e + " select").each(function (e) {
var title = $(this).attr("data-title");
var inside = $(this).find("option:selected").attr("data-title");
var i = $(this).find("option:selected").html();
if (inside === undefined) {
inside = " ( " + i + " ) "
} else {
inside = " ( " + inside + " ) "
}
var i = $(this).find("option:selected").attr("data-price");
var s = parseFloat($(this).attr("data-mult"));
if (isNaN(s)) {
s = 1
}
var o = parseFloat($(this).find("option:selected").text());
if (isNaN(o)) {
o = 0
}
if (i !== undefined) {
if (i == "this") {
i = o
} else {
i = parseFloat(i)
}
t[0] = t[0] + parseFloat(i) * s;
if (s == 1) {
t[1] = t[1] + "<div class=\"result\"><b>" + title + "" + inside + "</b> : " + parseFloat(i) + "" + " € " + "</div>"
} else {
t[1] = t[1] + "<div class=\"result\"><b>" + title + "" + inside + "</b> : " + parseFloat(i) + " X " + s + " = " + parseFloat(i) * s + "" + " € " + "</div>"
}
}
});
n = [];
r = [];
return t
}
$(document).ready(function () {
pcc_calc_forms();
$(document).on("change", ".calcolare select", function () {
pcc_calc_forms()
});
});
THIS is the link to the fiddle
Thanks in advance for any hint.
$(document).on("change", ".calcolare select", function () {
var i = $(this).find('option:selected').index();
alert(i);
//if(i>0) ppc_calc_forms();
//else $('.results').hide();
})
This will find the index of the selected option... as you can see, it works, just not with your function...
I would simplify that script as much as possible..
I understand not wanting to rewrite the code substantially at this point. However, for comparison, here is the way I would do it while still holding to your general pattern:
function pcc_calc_forms() {
jQuery(".calcolare").each(function (e) {
var t = jQuery(this).attr("id");
var items = pcc_item_data(t);
var totalPrice = $.makeArray(items).reduce(function(total,item,i,a) {
return total+item.price;
},0);
text = '<h3 class="pcc-total">Totale : ' + totalPrice + "" + "€" + '</h3>';
text += '</h3><div class="content">';
items.each(function(i,item) {
if (item.mult > 1)
text += "<div class=\"result\"><b>" + item.title + " ( " + item.name + " )</b> : " + item.price + " X " + item.mult + " = " + item.price * item.mult + "" + " € " + "</div>";
else
text += "<div class=\"result\"><b>" + item.title + " ( " + item.name + " )</b> : " + item.price + "" + " € " + "</div>";
});
text += '<br /><br /></div>';
jQuery("#" + t + "-mostra").html(text);
});
}
function pcc_item_data(e) {
return $("#" + e + " select").map(function (e) {
if (this.selectedIndex > 0) {
var item = {};
item.title = $(this).attr("data-title");
var inside = $(this).find("option:selected").attr("data-title");
var i = $(this).find("option:selected").html();
item.name = inside ? inside : i;
item.price = parseFloat($(this).find("option:selected").attr("data-price"));
var mult = parseFloat($(this).attr("data-mult"));
item.mult = isNaN(mult) ? 1 : mult;
return item;
}
});
}
$(document).ready(function () {
pcc_calc_forms();
$(document).on("change", ".calcolare select", function () {
pcc_calc_forms();
});
});
What I've done:
Separate data collection (pcc_item_data) from data presentation;
this makes the code more readable and easier to maintain later.
Used map (http://api.jquery.com/jQuery.map/) and reduce (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) to transform / aggregate arrays; they're concise
and expressive once you're familiar with them.
I am having trouble with a checkbox, that when clicked toggles an attribute of my "contact" object from 0 to 1.
The checkbox is part of a DIV that is generated containing all the object details.
The attribute i want to toggle is called "toggled".
What I was trying to achieve, was that when the checkbox is clicked, it executes the UpdateStatus() method with the "ID" of the object passed in as a parameter. Then loop through all the objects in the array to match the "ID" of the object.
The problem is it toggles every objects "toggled" attribute, not just the one im trying to target.
The Code that generates the div with the checkbox
Contact.prototype.generateDiv = function(){
divid = divid + 1;
buttonid = buttonid + 1;
var control = [];
control[0] = divid;
control[1] = buttonid;
var mapLocation = " ";
myControls.push(control);
if(this.daysUntil<=14){ //This checks to see if the contacts birthday is within 7 days or less,and creates a warning flag variable so we can display a warning flag
birthdayFlag = "<img src=resources/birthday.png>"
}else{
birthdayFlag = " "
};
if(this.post){ // this checks to see if there is a value in the Postcode attribute, if not it will set the map location to the address entered
mapLocation = this.post;
}else{
mapLocation = this.address;
}
var childDiv =
"<div class='parentDiv'>" +
this.firstName + " " + this.surname + " " + birthdayFlag + "<input type='checkbox' onclick='updateStatus(this.ID)'>" + " " + "<button class='btnForDiv' id='" + buttonid + "'" + " > Click to Expand </button>" +
"<div class='childDiv' id='" + divid + "' " + ">" + "<img class=map src='http://maps.google.com/maps/api/staticmap?scale=1¢er=" + mapLocation + "&zoom=14&size=500x350&maptype=hybrid&markers=size:normal|color:RED|label:C|" + mapLocation + "&sensor=false' style='float: right;border-style:groove'>" +
" " + "<span style='color:#5f9ea0';> Surname: </span>" + "<br>     " + this.surname +
"<BR>  " + "<span style='color:#5f9ea0';> First Name:</span> " +"<br>     " + this.firstName +
"<br>  " + "<span style='color:#5f9ea0';> Date Of Birth:</span> " +"<br>     " + this.days + "/" + this.months + "/" + this.years +
"<br>  " + "<span style='color:#5f9ea0';> Telephone Number:</span> " +"<br>     " + this.phone +
"<br>  " + "<span style='color:#5f9ea0';> Address:</span> " +"<br>     " + this.address + " " + this.post +
"<br>  " + "<span style='color:#5f9ea0';> Email Address:</span> " +"<br>     " + this.email +
"<br>  " + "<span style='color:#5f9ea0';> Group:</span> " +"<br>     " + this.group +
"<br>  " + "<span style='color:#5f9ea0';> Days Until Birthday:</span> " +"<br>     " + this.daysUntil +
"</div>" + "</div>" + "<HR width=1000px>" + "<BR> ";
return childDiv;
The code that is supposed to toggle the "toggled" attribute
var updateStatus = function(thisID){
alert("firing");
for (i = 0; i < contacts.length; i += 1) {
if (thisID = contacts[i].ID){
if (contacts[i].toggled = "0"){
contacts[i].toggled = "1";
}else{
if (contacts[i].toggled = "1"){
contacts[i].toggled = "0";
}
}
}
}
}
And the entire code incase it is required
var surnameField,firstNameField,birthdayField, phoneField, addressField, postField, emailField, groupField ; //Declaring variables for the fields
var Contact = function(surname,firstName,date, phone , address , post, email, group, imglink){
this.surname = surname ;
this.firstName = firstName ;
this.birthdayDate = new Date (date) ;
this.phone = phone;
this.address= address;
this.email = email;
this.post = post;
this.group = group;
this.toggled = "0" ;
this.ID = "";
}
var contacts = [];
upcomingBirthdays = [];
divid = 0;
buttonid = 1000;
mapid = 100;
myControls = [];
var getDate = function() {
for (var i= 0, j=contacts.length;i<j;i++){
var y = contacts[i].birthdayDate.getFullYear();
var m = contacts[i].birthdayDate.getMonth();
var d = contacts[i].birthdayDate.getDate();
contacts[i].days = d;
contacts[i].months = m + 1;
contacts[i].years = y ;
var today = new Date() ;
var ty = today.getFullYear();
contacts[i].bdThisYear = new Date(ty,m,d, 0 , 0 , 0);
}
}
var daysUntilBirthday = function(){
for (var i= 0, j=contacts.length;i<j;i++){
var today = new Date() ;
contacts[i].daysUntil = Math.round((contacts[i].bdThisYear - today ) /1000/60/60/24+1);
if (contacts[i].daysUntil <= 0){
contacts[i].daysUntil = contacts[i].daysUntil + 365 ;
}
}
}
var birthdayCheck = function(){
for (var i= 0, j=contacts.length;i<j;i++){
birth = "\n" + contacts[i].firstName + " " + contacts[i].surname + " has a birthday in " + contacts[i].daysUntil + " days" ;
if(contacts[i].daysUntil <= 14){
upcomingBirthdays.push (birth);
}
}
if(upcomingBirthdays.length > 0){
alert(upcomingBirthdays);
}
}
Contact.prototype.generateDiv = function(){
divid = divid + 1;
buttonid = buttonid + 1;
var control = [];
control[0] = divid;
control[1] = buttonid;
var mapLocation = " ";
myControls.push(control);
if(this.daysUntil<=14){ //This checks to see if the contacts birthday is within 7 days or less,and creates a warning flag variable so we can display a warning flag
birthdayFlag = "<img src=resources/birthday.png>"
}else{
birthdayFlag = " "
};
if(this.post){ // this checks to see if there is a value in the Postcode attribute, if not it will set the map location to the address entered
mapLocation = this.post;
}else{
mapLocation = this.address;
}
var childDiv =
"<div class='parentDiv'>" +
this.firstName + " " + this.surname + " " + birthdayFlag + "<input type='checkbox' onclick='updateStatus(this.ID)'>" + " " + "<button class='btnForDiv' id='" + buttonid + "'" + " > Click to Expand </button>" +
"<div class='childDiv' id='" + divid + "' " + ">" + "<img class=map src='http://maps.google.com/maps/api/staticmap?scale=1¢er=" + mapLocation + "&zoom=14&size=500x350&maptype=hybrid&markers=size:normal|color:RED|label:C|" + mapLocation + "&sensor=false' style='float: right;border-style:groove'>" +
" " + "<span style='color:#5f9ea0';> Surname: </span>" + "<br>     " + this.surname +
"<BR>  " + "<span style='color:#5f9ea0';> First Name:</span> " +"<br>     " + this.firstName +
"<br>  " + "<span style='color:#5f9ea0';> Date Of Birth:</span> " +"<br>     " + this.days + "/" + this.months + "/" + this.years +
"<br>  " + "<span style='color:#5f9ea0';> Telephone Number:</span> " +"<br>     " + this.phone +
"<br>  " + "<span style='color:#5f9ea0';> Address:</span> " +"<br>     " + this.address + " " + this.post +
"<br>  " + "<span style='color:#5f9ea0';> Email Address:</span> " +"<br>     " + this.email +
"<br>  " + "<span style='color:#5f9ea0';> Group:</span> " +"<br>     " + this.group +
"<br>  " + "<span style='color:#5f9ea0';> Days Until Birthday:</span> " +"<br>     " + this.daysUntil +
"</div>" + "</div>" + "<HR width=1000px>" + "<BR> ";
return childDiv;
}
var updateStatus = function(thisID){
alert("firing");
for (i = 0; i < contacts.length; i += 1) {
if (thisID = contacts[i].ID){
if (contacts[i].toggled = "0"){
contacts[i].toggled = "1";
}else{
if (contacts[i].toggled = "1"){
contacts[i].toggled = "0";
}
}
}
}
}
var assignID = function(){
for (i = 0; i < contacts.length; i += 1) {
contacts[i].ID = "" + i + "" ;
}
}
var removeContacts = function () {
for (i = 0; i < contacts.length; i += 1) {
if (contacts[i].toggled = "1"){
contacts.splice(i,1);
}
}
updateList();
}
var addContact = function(surnameField,firstNameField,birthdayField, phoneField, addressField, postField, emailField, groupField ){
if(surnameField.value){
a = new Contact(surnameField.value, firstNameField.value,birthdayField.value, phoneField.value, addressField.value, postField.value, emailField.value, groupField.value);
contacts.push(a);
}else{ alert("Please complete all fields")}
}
var clearUI = function(){
var white = "#fff";
surnameField.value = "";
surnameField.style.backgroundColor = white;
firstNameField.value = "";
firstNameField.style.backgroundColor = white;
birthdayField.value="";
birthdayField.style.backgroundColor = white;
phoneField.value = "";
phoneField.style.backgroundcolor = white;
addressField.value = "";
addressField.style.backgroundcolor = white;
postField.value = "";
postField.style.backgroundcolor = white;
emailField.value = "";
emailField.style.backgroundcolor = white;
groupField.value="";
groupField.style.backgroundcolor = white;
}
var updateList = function(elements){
assignID();
myControls = []
var tableDiv = document.getElementById("parentDiv"),
cDiv = "<BR>" ;
for (var i= 0, j=elements.length;i<j;i++){
var cntct = elements[i];
cDiv += cntct.generateDiv();
}
tableDiv.innerHTML = cDiv;
getDate();
daysUntilBirthday();
saveContacts();
}
var add = function(){
;
addContact(surnameField,firstNameField,birthdayField, phoneField, addressField, postField, emailField, groupField, imgField);
clearUI();
daysUntilBirthday();
getDate();
updateList(contacts);
updateList(contacts);
};
var saveContacts = function(){
var cntcts = JSON.stringify(contacts);
if (cntcts !==""){
localStorage.contacts = cntcts;
}else{
alert("Could not save contacts");
}
}
var loadContacts = function(){
var cntcts = "";
if(localStorage.contacts !== undefined){
cntcts = localStorage.contacts;
contacts = JSON.parse(cntcts);
var proto = new Contact();
for (var i=0; i<contacts.length; i++){
var cntct = contacts[i]
cntct.__proto__ = proto;
cntct.birthdayDate = new Date(cntct.birthdayDate);
}
}
}
var clearContacts = function(){
contacts = [];
updateList(contacts);
}
var sort_by = function(field, reverse, primer){
var key = function (x) {return primer ? primer(x[field]) : x[field]};
return function (a,b) {
var A = key(a), B = key(b);
return (A < B ? -1 : (A > B ? 1 : 0)) * [1,-1][+!!reverse];
}
}
var sortBySurname = function(){
contacts.sort(sort_by('surname', false, function(a){return a.toUpperCase()}));
updateList(contacts)
}
var sortByFirstname = function(){
contacts.sort(sort_by('firstName', false, function(a){return a.toUpperCase()}));
updateList(contacts)
}
var sortByGroup= function(){
contacts.sort(sort_by('group', false, function(a){return a.toUpperCase()}));
updateList(contacts)
}
var sortByBirthday= function(){
contacts.sort(sort_by('daysUntil', false, parseInt));
updateList(contacts)
}
window.onload = function(){
loadContacts();
updateList(contacts);
surnameField = document.getElementById("surname");
firstNameField = document.getElementById("firstName")
birthdayField = document.getElementById("birthday");
phoneField = document.getElementById("phone");
addressField = document.getElementById("address");
postField = document.getElementById("post");
emailField = document.getElementById("email");
groupField = document.getElementById("group");
imgField = document.getElementById("image");
addButton = document.getElementById("addButton");
addButton.onclick = add;
delButton = document.getElementById("delButton");
searchField = document.getElementById("searchField");
searchButton = document.getElementById("searchButton");
//searchButton.onclick = doSearch();
//delButton.onclick = removeContacts();
sortSurnameButton = document.getElementById("surnameSort");
sortSurnameButton.onclick = sortBySurname;
sortFirstNameButton = document.getElementById("firstNameSort");
sortFirstNameButton.onclick = sortByFirstname;
sortGroupButton = document.getElementById("groupSort");
sortGroupButton.onclick = sortByGroup;
birthSortButton = document.getElementById("birthSort");
birthSortButton.onclick = sortByBirthday;
clearUI();
birthdayCheck();
}
The mistake in overcomplex toggler:
try this:
if (thisID === contacts[i].ID){ //<- HERE WAS MISTAKE - single =
contacts[i].toggled=contacts[i].toggled==="1"? "0": "1"
}
Best to index your contacts by id in Object to avoid loops by id... or just use id when accessing array, you can use this function to generate like UUIDs.
you can acheive that using:
var addContact = function(surnameField,firstNameField,birthdayField, phoneField, addressField, postField, emailField, groupField ){
if(surnameField.value){
a = new Contact(surnameField.value, firstNameField.value,birthdayField.value, phoneField.value, addressField.value, postField.value, emailField.value, groupField.value);
contacts[GUID()]=a;
}else{ alert("Please complete all fields")}
}
the objects will look than like:
{ef9cffdc-9132-af78-6147-6bfc2cb247dc: {object data}, 405e61ae-881e-4b11-eab6-2f2355ca54ae : {object data},}
and will be easy accessed with objects[ID];
single object delete will look like: delete(objects[ID]);
loop will look:
for (var id in objects) {
var object=objects[id];
}
easy enough ?