Add div selections if visible to get total at the end - javascript

I have a list of divs that pull integer values from a SQL table. All of those divs are not visible unless a certain selection is made in the form. I want to create another div that sum's all visible divs at the end for the user to see their ending total.
Edit: The below code is now what I have but it totals all divs not ones that are only visible.
$("#clicky").click(function () {
var total = 0;
$('.equipmentmprice').each(function() {
total += parseFloat($(this).find('span.price').eq(0).text());
});
$('#totalamount').text('Total is: $' + total);
});
I know I can use javascript or jquery but I'm not sure really where to start.
Here is an example of one of my divs:
<div class="largeplantablefive equipmentmprice" style="display:none">
<?php
$connection = mysql_connect('localhost', 'test', 'testone');
mysql_connect('localhost', 'test', 'testone');
mysql_select_db('test');
$queryone = mysql_query("SELECT price FROM pricing WHERE value = 'plantablefive'");
$query_row = mysql_fetch_array($queryone);
echo "Plan Tables: $" . ($query_row[price]) . "<span style='color:red'><i> Price does not include cost of the physical table.</i></span>";
?>
</div>
Right now I'm thinking I will have to create another div or other tag inside the echo statement where the value equals $query_row.

You can do this with jQuery...
var divCount = $("div :visible").length;
If you need to loop through them...
$("div :visible").each(function(index) {
console.log( index + ": " + $( this ).text() );
//etc.. etc..
});

Found the answer with some searching and using multiple suggestions combining it into my own. Below is what I did and the answer. Just added the :visible into the class select.
$("#clicky").click(function () {
var total = 0;
$('.equipmentmprice:visible').each(function() {
total += parseFloat($(this).find('span.price').eq(0).text());
});
$('#totalamount').text('Total is: $' + total);
});

Related

Updating an Array with .innerHTML, issue when removing/adding

Trying to get my array to update onto the front end dynamically, when a user either adds/removes an item.
HTML/PHP for frontend below:
<div class="row">
<div class="col-12">
<div class="custom--css_pills">
<span class="tag filtering">Edit Products</span>
<span id="pills--container"></span>
</div>
<?php
$items = get_posts( array (
'post_type' => array('products'),
'posts_per_page' => -1
));
echo '<div class="enquire--surround_div">';
foreach($items as $item) {
echo '<input class="enquiry--add_chk" type="checkbox" value="'.$item->post_title.'" id="'.$item->post_title.'" />
<label for="'.$item->post_title.'">'.$item->post_title.'</label>';
}
echo '</div>';
?>
</div>
</div>
So far, I set my array
var pills = ["test","test2"];
Then setup a function which loops through this array and echos out a div, with the array item and a close icon
function looparray(){
var str = '';
pills.forEach(function(pill) {
str += '<div class="tag">'
str += '<span>' + pill + '</span>';
str += '<span class="tag-exit"></span>';
str += '</div>';
});
// Echo
document.getElementById("pills--container").innerHTML = str;
}
then call this function on load
looparray();
Then I have an onclick, for the radio buttons (Front end). Which will add to the array or remove depending if the checkbox is checked
$('.enquiry--add_chk').click(function(){
$valuetoaddcolour = $(this).next();
$valuetoaddcolour.toggleClass('enquiry--tabs_colour')
$valuetoadd = $(this).next().text();
if ( $(this).is(':checked')) {
console.log('notfilled');
pills.push($valuetoadd);
console.log(pills);
}
else{
pills.splice( $.inArray($valuetoadd, pills), 1 );
console.log(pills);
}
looparray();
});
And then an on close, to remove the selected from the array.
//On close..
$('.tag-exit').click(function() {
$valuetoremove = $(this).parent(); // Get parent to hide (surround div)
$valuetoremovetext = $(this).parent().text(); // Get text to remove from array
// remove from array
pills.splice( $.inArray($valuetoremovetext, pills), 1 );
$valuetoremove.hide(); // Hide the pill
looparray();
});
now the issue is, when I first select a remove, it will run fine. If i then add an item, then try to remove via the .tag exit, it doesn't run the function. I've narrowed it down to the looparray(); causing the issue, but can't see what the issue is. All i can think is it's wiping the data and re-adding, which may cause an issue with pre-defined functions?
I've put a little codepen together to give a better understanding.
https://codepen.io/anon/pen/QoQrZw
As #avraham said, this was due to the element not in the DOM.
Fixed by adding:
//On close..
$('body').on('click', '.tag-exit', function () {
// $('.tag-exit').click(function() {
$valuetoremove = $(this).parent(); // Get parent to hide (surround div)
$valuetoremovetext = $(this).parent().text(); // Get text to remove from array
// remove from array
pills.splice( $.inArray($valuetoremovetext, pills), 1 );
$valuetoremove.hide(); // Hide the pill
looparray();
});

How can I perform dynamic operations on dynamically added elements?

My objective:
Filling in the 'performer-payments' table dynamically with JS/Jquery
For each (dynamically added) row in the table, one of the data cells contains a dropdown box.
This dropdown box should, when a certain option is selected, make visible another dropdown box (in the same cell). Otherwise, this second dropdown should be invisible.
Elsewhere I am accomplishing the hide/show dynamics by means of a toggleVisible function, which simply adds custom classes which is marked by css to hide or show the element.
The relevant code:
The table I want to populate:
<table id='performer-payments' class='performer-profile payments-table'>
<tr>
<th> Period </th>
<th> Amount </th>
<th> Paid? </th>
</tr>
</table>
The code that populates the table:
for (period in data['Performers'][performer]['Payments']) {
var amount = utils.calcPerformerCut(data, performer, period);
var row = "<tr>";
row += "<td> " + period + " </td>";
row += "<td> " + amount + " $ </td>";
row += "<td>";
row += "<div class='performer-profile payment-status'>";
row += data['Performers'][performer]['Payments'][period];
row += "</div>";
row += "<select id='payment-status-" + performer + "-" + period + "' class='perfomer-profile hidden-onload displayNone payment-status-menu'>";
row += "<option value='paid'>Paid</option>";
row += "<option value='unpaid'>Unpaid</option>";
row += "<option value='transfer'>Transfer to...</option>";
row += "</select>";
row += "<select id='payment-transfer-period-" + performer + "-" + period + "' class='performer-profile hidden-onload displayNone payment-period-menu'>";
for (var i=0; i < data['Periods'].length; i++) {
row += "<option value='" + period + "'>" + period + '</option>';
}
row += "</select>";
row += "</td>";
row += "</tr>";
$('#performer-payments').append(row);
$('#performer-payments').on('change', {perf: performer, per: period}, function (even) {
if (even.target.value == 'transfer') {
utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), true);
} else {
utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), false);
}
});
}
For reference, the code that toggles visibility:
exports.toggleVisible = function (selector, visible) {
if (visible) {
selector.removeClass('displayNone').addClass('displayBlock');
} else {
selector.removeClass('displayBlock').addClass('displayNone');
}
}
There are (at least) two issues with this:
The #payment-transfer-period-... select box is never displayed, even when the 'transfer' option is chosen in the first select box. From debugging efforts it seems to me that it could be that the #payment-transfer-period-.. for some reason is not a valid object yet, or something like that.
(Obviously, really), the on-change event is triggered N times (N=number of periods) because I am just telling the program to trigger whenever something in the table changes. I would like it to trigger only for the relevant dropdown, but when I tried adding the #payment-status-... as a selector to the .on() function, it made it never trigger.
Note: I welcome feedback on this in general - I am an experienced programmer but have very little experience with HTML/JS/Jquery. Further, I have decided to not use templates for this project since I am trying to learn the basics, so if you get pancreatitis from seeing the way I am 'dynamically' adding the rows to the table, I apologize but it is partly intentional.
Other than that, please ask for clarifications if something is not clear here.
Edit: Here is the relevant part of the data structure:
data = {
'Performers': {
'Dira Klaggen': {
'Payments': {
'Q1': 'Paid',
'Q2': 'Paid',
'Q3': 'Unpaid'
},
},
'Holden Bolden': {
'Payments': {
'Q2': 'Transferred to Q3',
'Q3': 'Unpaid'
}
},
'Manny Joe': {
'Payments': {
'Q1': 'Paid',
'Q2': 'Unpaid',
'Q3': 'Unpaid',
}
}
},
'Periods': [
'Q1',
'Q2',
'Q3'
]
}
You do not attach the change handler to the right element. I should be the first select in the row... Instead of the whole table.
Try this change handler:
$('#performer-payments').find('#payment-status-' + performer + '-' + period).on('change', function(){
if ($(this).val() == 'transfer') {
$(this).next('select').show();
} else {
$(this).next('select').hide();
}
});
Second approach:
You could simplify that by using a class instead of a "complicated" unique id for the first select.
Say you use the class "payment-status":
The handler would be:
$('#performer-payments').on('change', '.payment-status', function(){
if ($(this).val() == 'transfer') {
$(this).next('select').show();
} else {
$(this).next('select').hide();
}
});
And this handler can be out of the row appending loop because it uses delegation.
Let's clean up your code by doing the following things:
Use classes instead of ugly IDs.
Use data-attributes or hidden input fields to hold extra information.
Use event delegation to bind dynamically-created elements. Inside the event handler, use tree traversal methods to limit the scope of the search based on the current element this.
Let's apply these things.
Build each row like this. {PLACEHOLDER} is where you put your variable stuff like you have in your code.
<tr>
<td>{PERIOD}</td>
<td>{AMOUNT} $ </td>
<td>
<div class='performer-profile payment-status'>
{SOMETHING-RELATING-TO-PERFORMER-PAYMENT-PERIOD}
</div>
<!-- remove ID -->
<!-- store performer and period in data-attributes -->
<select class='perfomer-profile hidden-onload displayNone payment-status-menu' data-performer='{PERFORMER}' data-period='{PERIOD}'>
<option value='paid'>Paid</option>
<option value='unpaid'>Unpaid</option>
<option value='transfer'>Transfer to...</option>
</select>
<!-- remove ID -->
<select class='performer-profile hidden-onload displayNone payment-period-menu'>
<option value='{PERIOD}'>{PERIOD}</option>
<option value='{PERIOD}'>{PERIOD}</option>
<option value='{PERIOD}'>{PERIOD}</option>
<!-- etc -->
</select>
</td>
</tr>
In your JavaScript, create a delegated event handler. Note the syntax.
$(function () {
// ...
for (period in data['Performers'][performer]['Payments']) {
// build and append row
}
// create delegated event handler once and outside FOR loop
$(document).on('change', '.payment-status-menu', function () {
// get the current status menu
var statusMenu = $(this);
// find its related period menu
var periodMenu = statusMenu.closest('tr').find('.payment-period-menu');
// toggle its visibility
periodMenu.toggle(this.value == 'Transfer');
// of course, this could be a one-liner
//$(this).closest('tr').find('.payment-period-menu').toggle(this.value == 'Transfer');
});
});
It doesn't seem like you need (2.) but if you do, within the event handler, use statusMenu.data('performer') or statusMenu.data('period') to get its performer and period values. You could also do this.dataset.performer or this.dataset.period.

JS to add form fields with a button

How I create a do...while loop (or if there is a better way to go about this - please advise) for a form with potentially additional information?
Background - I've got a form that will accept a users assessment of a particular location (such as a basement). Using only 1 location per form, this works nicely and submits to my db without a problem.
Now I want to enhance this form with a "add new location" button. I don't (obviously) want to create new pages but rather a loop that can store the first location, save it (which I know could be done with be a session variable) and then clear the fields for locations 2, 3, 4, etc.
My confusion is around the functionality of the button. What type of button is this? Reset with a unique id such as new_loc[]?
And then when I write this as a do...while loop should I do it like this:
<?php
do {
all my form fields
} while (some condition that looks for the button submit);
?>
ok so I have a created a simple JS that can "handle" this.
var counter = 1;
var limit = 5;
function addInput(locInformation){
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " locations");
}
else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "Entry " + (counter + 1) + " <br><br><input type='text' name='location[]'>";
document.getElementById(locInformation).appendChild(newdiv);
counter++;
}
}
Now the problem is that JS will add 1 new field - any suggestions on how to add a massive block of HTML to the JS? I tried adding all my fields to the JS and I get a whole bunch of unclosed string errors.
So first of all your form must have action="" method="post"
then add this php to your page:
session_start();
if (isset ($_POST['NameOfSubmitButtonInsideForm'])) {
if (!isset ($_SESSION['sessionName'])) {
$_SESSION['sessionName'] = 1
}
for ($i = 0; $i <= $_SESSION['sessionName']; $i++) {
echo 'some html code like a form with a input that has
<input type="submit" name="submit- . $i .'EndInputTag>';
};
}
So this will loop the number of times the user clicked the button and you can echo out html code based on that number, or what ever it is you need to do in the loop.
Ok I've figured this out. Thanks to Marc B for suggesting JS.
HTML for the button
<input style="margin-left:5px;" class="btn btn-primary" type="button" value="Add Additional Location" onClick="addInput('locInformation');">
JS
var counter = 1;
var limit = 5;
function addInput(locInformation){
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " inputs");
}
else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<h3>Location " + (counter + 1) + "</h3>" + document.getElementById('additionalLoc').innerHTML;
document.getElementById(locInformation).appendChild(newdiv);
counter++;
}
}
And then lastly is the new locInformation stuff:
<div id="additionalLoc" language="text">
huge block of HTML with additional fields
</div>

Append contents of each div to textarea

I have a list of divs created server-side, each with a price, quantity (entered by the user) and name. I've managed to use jQuery to calculate the total of each and add those up.
What I'd like to do now is to list the name, quantity and total of each item that has a value in my textarea, on a per-row basis.
So far I've got the following (the append part of which doesn't currently work):
$(document).ready(function () {
$(".product-row input").change(multInputs);
function multInputs() {
var mult = 0;
// for each row:
$("div.product-row").each(function () {
// get the values from this row:
var $price = $('.price', this).html();
var $quantity = $('.quantity', this).val();
var $total = ($price * 1) * ($quantity * 1);
// set total for the row
$('.multTotal',this).text($total);
mult += $total;
$('#textarea',this).append($name).append($total);
});
$("#total").html(mult);
}
});
If I can get this worked out, I'm pretty sure I can work out how to add the grand total and clear the textarea each time something is changed (I'm not looking for someone to do all the work).
Any feedback as to why my textarea isn't populating would be very much appreciated.
Edit: The solution, really well explained below by braks has resulted in the following (working!) code:
$(document).ready(function () {
$(".product-row input").change(multInputs);
function multInputs() {
var mult = 0;
// for each row:
$("div.product-row").each(function () {
// get the values from this row:
var price = $('.price', this).html();
var quantity = $('.quantity', this).val();
var name = $('.name', this).html();
var total = (price * 1) * (quantity * 1);
// set total for the row
$('.multTotal',this).text(total);
mult += total;
$('#textarea').val($('#textarea').val() + ' ' + name + ' ' + total);
});
$("#total").html(mult);
}
});
$(textarea).append(txt) doesn't work like you think. When a page is loaded the text nodes inside the textarea are set the value of that form field. After that, the text nodes and the value can be disconnected. As you type in the field, the value changes, but the text nodes inside it on the DOM do not. Then you change the text nodes with the append() and the browser erases the value because it knows the text nodes inside the tag have changed.
So you want to set the value, you don't want to append. Use jQuery's val() method for this.
You have to use something like $('#textarea').val($('#textarea').val() + ' ' + $name + ' ' + $total);
Except I'm not sure why you put $ in your variables, mix up with PHP ?

How do I create a div and give it an ID based on a changing variable?

I'm making a quiz. The user decides how many questions he wants to answer.
A function then takes this number and runs a loop to make an individual question div for each question. The quiz shows a Chinese character and the user has to pick the correct translation.
My code:
var fillInQuestion = function() {
questionDivIdHTML = 'question' + questionNum;
/****************************************
How do I make this Div's ID = to questionDivIdHTML?
// Creates question div
$('#questionArea').append("<div class='questionDiv'></div>");
//$('#questionArea:last-child').attr("id", questionDivIdHTML); <-- NOT WORKING
***************************************/
// Sets up a choice bank.
var choices = [];
// choices will be chosen from this.
var tempAnswerSet = allChoices.slice(0);
//find random item in the database for the question
var thisQuestion = allQuestions[Math.floor(Math.random() * allQuestions.length)];
// add that item to choices
choices.push(thisQuestion);
// remove item from 'database' so it cannot be used in another question
allQuestions.splice(allQuestions.indexOf(thisQuestion), 1);
// remove item from tempAnswer set so it can only be one choice
tempAnswerSet.splice(tempAnswerSet.indexOf(thisQuestion), 1);
// add three more items from the database (incorrect items)
var i = 3;
for (i; i > 0; i--) {
var addChoice = tempAnswerSet[Math.floor(Math.random() * tempAnswerSet.length)];
choices.push(addChoice);
// remove the one selected each time so they cant be chosen again
tempAnswerSet.splice(tempAnswerSet.indexOf(addChoice), 1);
//console.log("choices length: " + choices.length);
}
// shuffle the array
choices.shuffle();
// fill in the div with choices.
$('#questionDivIdHTML').append("Here is an question prompt:" + thisQuestion.english + " <br>");
$('questionDivIdHTMLwithHash').append("<input type='radio' name='question<script>questionNum</script>Choice' value='<script>choices[0].hanyu</script>'></input>" + choices[0].hanyu + "<br>");
$('questionDivIdHTMLwithHash').append("<input type='radio' name='question<script>questionNum</script>Choice' value='<script>choices[1].hanyu</script>'></input> " + choices[1].hanyu + "<br>");
$('questionDivIdHTMLwithHash').append("<input type='radio' name='question<script>questionNum</script>Choice' value='<script>choices[2].hanyu</script>'></input> " + choices[2].hanyu + "<br>");
$('questionDivIdHTMLwithHash').append("<input type='radio' name='question<script>questionNum</script>Choice' value='<script>choices[3].hanyu</script>'></input> " + choices[3].hanyu + "<br>");
};
var fillOutQuiz = function() {
for (questionAmount; questionAmount > 0; questionAmount--) {
fillInQuestion();
questionNum += 1;
}
};
I've gotten this code to work, but I broke it, when trying to add the dynamic ID and loop it.
You are saying that this portion of code is not working:
$('#questionArea').append("<div class='questionDiv'></div>");
$('#questionArea:last-child').attr("id", questionDivIdHTML);
Well, it does not work because the :last-child pseudo selector is used incorrectly (see below). It should be:
$('#questionArea').append("<div class='questionDiv'></div>");
$('#questionArea > :last-child').attr("id", questionDivIdHTML);
Or better, you can rearrange your code like this:
$("<div class='questionDiv'></div>")
.attr("id", questionDivIdHTML)
.appendTo("#questionArea");
#questionArea:last-child selects an element with id = questionArea which is also the last child of its parent
#questionArea > :last-child selects the last child of an element with id = questionArea

Categories

Resources