Checking variable for multiple inputs after onChange event - javascript

So I have a dynamic form that has two columns. One has a job name and the other has an input box where the user could enter their on description of the job.
while($install_table_r = tep_db_fetch_array($install_table_query))
{
echo'
<tr class="dataTableRow">
<td class="dataTableContent">
<input type="text" id="job_name" name="job_name"
value="'.$install_table_r['name_of_job'].'" disabled />
</td>
<td class="dataTableContent">
<input type="text" name="job_desc" value="'.$install_comment['comment'].'"
onChange="insertCommentInstall(this.value,)" />
</td>
</tr>
';
}
So as you can see I have a while loop that populates this form. So it could potentially have a lot of input boxes that you can use to describe the jobs.
The issue I am having is that, when I handle this form with the AJAX I have set up. The javascript simply grabs the last job on the list and uses that as it's jobs name. So in essence it is grabbing the input box correctly it's just placing it in the wrong row.
Here is the javascript that handles this change.
var job = document.getElementsByNames("job_name").value;
var comment = document.getElementsByNames("job_desc").value;
var url = "<?php echo FILENAME_ORDERS_EDIT_AJAX; ?>?action=insert_comment_install&oID=<?php
echo $_GET['oID']; ?> &new_comment=" + value + "&jobname=" + job;
I know I should be grabbing the elements with getElementByNames but I just don't know how to pair up the comment with the proper job that it's supposed to go with. So if someone comments next to the input box for Granite Job the comment should be paired up with the job name 'Granite Job' in the database. Instead currently it will just be paired up with the last job on the list which is 'Cabinet Assembly'.
Any help would be appreciated.

First of all, you have a HTML error for the attribute id
You may not in HTML standards to give a same value for id attribute to a multiple elements.
But fortunately we can use this unique identifier to make your code works
You can edit your PHP code to some thing like this:
$counter=0;
while($install_table_r = tep_db_fetch_array($install_table_query))
{
echo'
<tr class="dataTableRow">
<td class="dataTableContent">
<input type="text" id="job_name_'.$counter.'"
value="'.$install_table_r['name_of_job'].'" disabled />
</td>
<td class="dataTableContent">
<input type="text" id="job_desc_'.$counter.'" value="'.$install_comment['comment'].'"
onChange="insertCommentInstall(this.value,'.$counter.')" />
</td>
</tr>
';
$counter++;
}
You can see we added a counter to identify our rows
Updating your Javascript code will be as follow:
var insertCommentInstall=function(value,identifier){
var job = document.getElementById("job_name_"+identifier).value;
var comment = document.getElementById("job_desc_"+identifier).value;
var url = "<?php echo FILENAME_ORDERS_EDIT_AJAX; ?>?action=insert_comment_install&oID=<?php echo $_GET['oID']; ?> &new_comment=" + value + "&jobname=" + job;
}

When you use a selector like getElementsByClassName or getElementsByTagName you are retrieving a nodelist of all elements with the specified attribute (adding a classname to your inputs would make this easier). You need to specify one particular node out of the nodelist in order to fetch it's value. In order to retrieve all values in your nodelist you need to loop through it and push the values of all its nodes into an array.
//finds all elements with classname "jobs"
var jobs = document.getElementsByClassName("jobs");
//create new array that we push all the values into
var jobValues = [];
//loop through our jobs nodelist and get the value of each input
for (var i = 0; i < jobs.length - 1; i++) {
jobValues.push(jobs[i].value);
}
jobValues; //gives you a list of all the values you pushed into the array
jobValues[5]; //gives you the value of the 6th input you looped through

Related

How to create a clickable list with multiple values in an element?

I am trying to create a list of names an user could chose from to select a object with multiple hidden values. I work with a PHP backend.
The code I wrote works but I think it is probably not the right way to approach the problem and could be written alot better, but I can't seem to find a better way.
Right now I print a <div> for every object which are clients in my case. Within the div I have four checkboxes that are hidden, which I check and uncheck on the background with a javascript function. The values of those checkboxes is what I need in javascript for an API call after the user choses the client.
I select and deselect the with a javascript function.
foreach($clients as $client) {
echo '<div class="'.$client->name.'-'.$client->id.' client-style" name="'.$client->name.'">
<input type="checkbox" class="'.$client->id.'" name="client_id" value="'.$client->id.'">
<input type="checkbox" class="'.$client->id.'" name="client_fb" value="'.$client->facebook.'">
<input type="checkbox" class="'.$client->id.'" name="client_insta" value="'.$client->instagram.'">
<input type="checkbox" " class="'.$client->id.'" name="client_wb" value="'.$client->website.'"></div>';
}
For every element I create an on click event handler
for (var i = 0; i < clientList.length; i++) {
const {name, id} = clientList[i];
$(`.${name}-${id}`).on('click', function() {
selectClientFromList({name, id});
});
}
I am trying to get a list of clickable "names". When a "name" is clicked, you want to get the "name" but also "id", "facebook", "instagram", "website".
Might be useful to use the <select> tag with multiple values like this but I don't want a dropdown. I need a scrollable list, because I also have use searchbar for this list.
With a lot of clients the html would grow fast. How do I clean my php code and keep the information about a client that the user selected?
Thanks in advance!
A good approach can be to use a hidden input. Give your div a class and then
foreach($clients as $client) {
echo '
<div class="'. $client->name.'-'.$client->id.' client-style" name="'.$client->name.'">
<input type="hidden" class="aclass '.$client->id.'" name="client_id" value="'.$client->id.'">
<input type="hidden" class="aclass '.$client->id.'" name="client_fb" value="'.$client->facebook.'">
<input type="hidden" class="aclass '.$client->id.'" name="client_insta" value="'.$client->instagram.'">
<input type="hidden" class="aclass '.$client->id.'" name="client_wb" value="'.$client->website.'"></div>';
}
And then instead of creating a click handler everytime. One works too.
$(`.aclass`).on('click', function() {
let type = $(this).attr('name'); // client_id or client_fb
let client_id = $(this).attr('class').replace("aclass",""); // $client->id's value is here
let value = $(this).val(); // credentials
});

Javascript/HTML:Java script for Radio button not working properly

I have a problem with my java script and radio button.
I want to make radio button only can be choose only one in each row based on the id value from database, but in my case the function is working on the first row but the rest is not because it only return the first row value. the radio button is generate dynamically(the count of radio button row is based on how many id in db).
below is my java script:
function test1(){
var tes = document.getElementById('max');
var zes = document.getElementById('max1');
alert(tes.value)
if(tes.checked){
zes.checked = false;
}
}
function test2(){
var tes = document.getElementById('max');
var zes = document.getElementById('max1');
alert(zes.value)
if(zes.checked){
tes.checked = false;
}
}
This is my radio button code:
<td align = 'center'>
<?php
$test = $col['id'];
$testing = "select training.* from training inner join rekod on training.id = rekod.id where rekod.id = '$test'";
$userx = mysql_query($testing) or die (mysqli_error());
$u = mysql_fetch_assoc($userx);
echo $u['id'];
echo "<input type ='radio' name='x' onchange='test1();' required id='max' value ='".$u['id']."'>";?>
</td><td align='center'>
<?php
$te = $col['id'];
$tes = "select training.* from training inner join rekod on training.id = rekod.id where rekod.id = '$te'";
$us = mysql_query($tes) or die (mysqli_error());
$ux = mysql_fetch_assoc($us);
echo $ux['id'];
echo "<input type ='radio' name='x1' onchange='test2();' required id='max1' value ='".$ux['id']."'>";?>
</td>
The code above will generate something like this (the number is id):
I want to make like this:
but it become like this:
can someone tell me what wrong with my code ?
There is no need of JS logic, you have to use radio button grouping by name, if you are using loop then append same index in radio's name for both columns and then your html should be like,
<tr>
<td>
...
<input type="radio" name="x_1" .../>
</td>
<td>
...
<input type="radio" name="x_1" .../>
</td>
</tr>
<tr>
<td>
...
<input type="radio" name="x_2" .../>
</td>
<td>
...
<input type="radio" name="x_2" .../>
</td>
</tr>
Read more about input-type-radio
You are using document.getElementById and trying to access multiple elements, that is not correct. If you have multiple DOM elements to access and manipulate then you need to go with document.getElementsByClassName or document.getElementsBtTagName. In an HTML page, you can have only one element with a unique id (id of two elements can never be same).
In your case, you are using a loop and assigning the same id to all elements in the loop. That is the problem.
Thank you.

javascript/jquery: how to add/remove variables from array depending on whether a checkbox is selected

I'm outputting order addresses for a takeout restaurant: each individual order is output as a table, each table has a checkbox. I want to put the addresses into an array when the .ordercollected checkbox is ticked, and remove it from the array if it is unticked.
At the moment, rather than appending each new address I get each order address on its own in the array, which updates each time I tick the .ordercollected checkbox.
Really new to programming so any help appreciated!
//get the addresses from selected tables
$('.ordercollected').change(function() {
var activeaddress = [];
//loop through checkboxes with class .ordercollected
$(this).each(function() {
//if checkbox is ticked
if ($(this).is(':checked')) {
//get address from table
var address = $(this).closest('.ordertable').find('.address').text();
//append value of address into activeaddress array
activeaddress.push(address);
};
});
console.log('active address: ', activeaddress);
});
edit to add in the tables I am creating:
<table class="ordertable">
<tr>
<td>
<p>Order #
<?php echo $order_id; ?> —
<time datetime="<?php the_time('c'); ?>">
<?php echo the_time('d/m/Y g:i:s A'); ?>
</time>
</p>
</td>
<td>
<?php echo $order->billing_first_name . ' ' . $order->billing_last_name ?>
</td>
<td>
<?php if ($order->billing_phone) : ?>
Tel.
<?php endif; ?>
</td>
<td>
<p class="address"><?php echo $order->shipping_address_1 . ' ' . $order->shipping_postcode ?></p>
<td/>
<td>
<a class="maps-activate" href="#">Open in Maps</a>
</td>
<td>
<form action="">
<input type="checkbox" class="ordercollected" value="0" />
</form>
</td>
</tr>
</table>
Rather than remake your entire activeaddress array every time a checkbox changes, the best thing to do here would be to add or remove only the selected address when a checkbox changes. To do this activeaddress will have to be available outside of that function. I also think it will be cleaner if you use a JS object instead of an array.
var activeaddress = {};
$('.ordercollected').change(function() {
// get table id
var orderTableID = $(this).closest('.ordertable').attr('id');
// if checkbox is ticked
if($(this).is(':checked')) {
// get address from table
var address = $(this).closest('.ordertable').find('.address').text();
// append value of address into activeaddress object
activeaddress[orderTableID] = address;
} else { // checkbox is NOT ticked
// remove address from object
delete activeaddress[orderTableID];
}
console.log("active address: ", activeaddress);
});
As you can see, this code assumes that each table with class .ordertable has a unique id that can be used as the key in the activeaddress object. This is better than looping over the entire array/object each time because, especially if you have a very big set of orders. If you had included your HTML I would be able to help more, but as the question is this is as far as I can help. Let me know if you have any follow up questions.
A couple of things to note:
Using pascalCase for variable names and class names makes code more readable (e.g. activeAddress instead of activeaddress)
In my opinion, using an object instead of an array is a better way to add and remove a specific item
When asking question on SO, please give as much information as possible, such as including your HTML
Finally some links:
Adding a key value pair to an object
Removing a key value pair from an object
try something like this?
HTML:
<input type="checkbox" class="ordercollected" value="apple" />
<input type="checkbox" class="ordercollected" value="mango" />
JS
$('.ordercollected').change(function() {
var activeaddress = [];
//loop through checkboxes with class .ordercollected
if (this.checked) {
activeaddress.push(this.value);
}
else {
var index = activeaddress.indexOf(this.value);
if (index > -1) {
activeaddress.splice(index, 1);
}
}
console.log('active address: ', activeaddress);
});

How to calculate the total value of a dynamic number of fields using javascript?

My page shows some forms with content loaded from a database. Every row will get his own <input>. The ID of this input is equal for every row, except for the number that is attached to it, to make it unique. To make it more clear; this is how the form looks like when it loads 3 rows from the database:
<form>
<input id="Amount1" value="<?php echo $databaseValue; ?>" >
<input id="Amount2" value="<?php echo $databaseValue; ?>" >
<input id="Amount3" value="<?php echo $databaseValue; ?>" >
<input type="hidden" name="numberOfRows">
<input id="finalResult">
</form>
This is all done with the mysqli_array function. The value of numberOfRows is based on numRows function.
What I'd like to achieve is that javascript calculates the value of each existing input and put the result in finalResult, regardless the number of forms (because this may vary). If I make some changes to one of the values, the finalResult should update real-time.
What I've tried so far:
formnum contains the number of fields.
var a is created at the beginning, starting at 0. Inside it's function I create an ID, matching the fields on the page. All fields are named "Amount" + number. If this number equals the number of fields, the function will stop. This way the script won't be looking for fields that doesn't excist.
Then it gets the value of this field and adds the value to var b. var b is just created to store the value temporary, untill the function's over.
At the end the total is divided to 15. This is something extra I need. Nothing special on this line.
My code:
<script type='text/javascript'>
$(document).ready(function(){
var formnum = $("#numberOfRows").val();
var a;
var b = 0;
var formname = '#Amount';
for (a = 0; a < formnum; a++) {
var complete = formname.concat(a);
var completeContent = $(complete).val();
b = b + completeContent;
};
b = b.toFixed(2);
});
$(document).mousemove(function(event){
var formula_finalResult = b / 15;
var total_finalResult = Math.floor(formula_finalResult);
$("#finalResult").val(total_finalResult);
});
</script>
This doesn't do anything. It doesn't change the value. What's going wrong?
Make it simple:
$(function(){
var sum = 0;
// Selector to select all input whose id starts with Amount
$("input[id*='Amount']").each(function(){
sum += +$(this).val(); // Parsing as int and adding it to sum
});
$("#finalResult").val(Math.floor(sum/15)); // Storing the values
})
Assuming that all of the fields always have Amount at the beginning of their id attribute, you could use jQuery's ID selector to achieve this, without the need for any of the internal counters, etc.
I'm not entirely sure why you need to hook into the mousemove event, since the data should never change on the page (since it's being generated by PHP when the page is first loaded). The following code should achieve what you're looking for:
$(function() {
var total = 0;
$('input[id*="Amount"]').each(function() { total+= parseFloat( $(this).val() ); });
$('#finalResult').val( Math.floor( total / 15 ) );
});
Your code has an error Uncaught ReferenceError: b is not defined
see it in action here: http://jsfiddle.net/ca9vascj/
There's no reason to bring the mousemove event into this, I'm not even sure what that was needed for.
Like the above answers, here's a much simplified version. But instead of a partial ID selection, let's just give the form an ID, and then give all the needed elements inside that form a class that we can select by. We also no longer need to have the numberOfRows form element.
<form id="theForm">
<input class="formAmmount" value="5" />
<input class="formAmmount" value="10" />
<input class="formAmmount" value="27.5" />
<input class="formAmmount" value="4" />
<input class="formAmmount" value="9" />
<hr />
<input id="finalResult" />
</form>
And then our jQuery code can be reduced to this:
$(function(){
var total = 0;
$("#theForm .formAmmount").each(function(){
total += parseFloat(this.value, 10);
});
var final = Math.floor(total.toFixed(2) / 15);
$("#finalResult").val(final);
});
See it in action here: http://jsfiddle.net/ca9vascj/1/
You dont'need jQuery. The simplest way to do this is document.getElementsByTagName:
var inputs = document.getElementById('my-form').getElementsByTagName('input')
That's it. inputs.length will always get an actual count of inputs in your form. That's because getElementsByTagName() returns a NodeList object, containing a live view of the matching elements. This object is mutable; it will change in response to DOM mutations.
So if you need to get sum from all of the inputs:
function sum() {
var result = 0;
[].slice.call(inputs).forEach(function(input){
result += parseFloat(input.value)
});
return result;
}
If you are able to change the generated Html-Source I would suggest to give a new class to your InputElements.
<input id="Amount1" class="ElementToCount" value="<?php echo $databaseValue; ?>" >
Then you can calculate like that
var getSumOfElements = function() {
var Elements = $('.ElementToCount')
var sum=0
if (Elements && Elements.length>0) {
for (var i=0; i<Elements.length; i++) {
sum += Elements[i].val();
}
}
return sum
}
And to update the field you could register to the 'change'-Event
$('.ElementToCount).on('change', function() {
$('#finalResult').val(getSumOfElements());
})

add templated div to page multiple times with different ids

I am using ASP.Net MVC along with Jquery to create a page which contains a contact details section which will allow the user to enter different contact details:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas[0]_Type" name="venue.ContactLink.ContactDatas[0].Type">
<option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas[0]_Data" name="venue.ContactLink.ContactDatas[0].Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact' />
</p>
Pressing the button is supposed to add a templated version of the ContactDetailsEntry classed div to the page. However I also need to ensure that the index of each id is incremented.
I have managed to do this with the following function which is triggered on the click of the button:
function addContactDetails() {
var len = $('#ContactDetails').length;
var content = "<div class='ContactDetailsEntry'>";
content += "<select id='venue_ContactLink_ContactDatas[" + len + "]_Type' name='venue.ContactLink.ContactDatas[" + len + "].Type'><option>Email</option>";
content += "<option>Phone</option>";
content += "<option>Fax</option>";
content += "</select>";
content += "<input id='venue_ContactLink_ContactDatas[" + len + "]_Data' name='venue.ContactLink.ContactDatas[" + len + "].Data' type='text' value='' />";
content += "</div>";
$('#ContactDetails').append(content);
}
This works fine, however if I change the html, I need to change it in two places.
I have considered using clone() to do this but have three problems:
EDIT: I have found answers to questions as shown below:
(is a general problem which I cannot find an answer to) how do I create a selector for the ids which include angled brackets, since jquery uses these for a attribute selector.
EDIT: Answer use \ to escape the brackets i.e. $('#id\\[0\\]')
how do I change the ids within the tree.
EDIT: I have created a function as follows:
function updateAttributes(clone, count) {
var f = clone.find('*').andSelf();
f.each(function (i) {
var s = $(this).attr("id");
if (s != null && s != "") {
s = s.replace(/([^\[]+)\[0\]/, "$1[" + count + "]");
$(this).attr("id", s);
}
});
This appears to work when called with the cloned set and the count of existing versions of that set. It is not ideal as I need to perform the same for name and for attributes. I shall continue to work on this and add an answer when I have one. I'd appreciate any further comments on how I might improve this to be generic for all tags and attributes which asp.net MVC might create.
how do I clone from a template i.e. not from an active fieldset which has data already entered, or return fields to their default values on the cloned set.
You could just name the input field the same for all entries, make the select an input combo and give that a consistent name, so revising your code:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas_Type" name="venue_ContactLink_ContactDatas_Type"><option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas_Data" name="venue_ContactLink_ContactDatas_Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact'/>
</p>
I'd probably use the Javascript to create the first entry on page ready and then there's only 1 place to revise the HTML.
When you submit, you get two arrays name "venue_ContactLink_ContactDatas_Type" and "venue_ContactLink_ContactDatas_Data" with matching indicies for the contact pairs, i.e.
venue_ContactLink_ContactDatas_Type[0], venue_ContactLink_ContactDatas_Data[0]
venue_ContactLink_ContactDatas_Type[1], venue_ContactLink_ContactDatas_Data[1]
...
venue_ContactLink_ContactDatas_Type[*n*], venue_ContactLink_ContactDatas_Data[*n*]
Hope that's clear.
So, I have a solution which works in my case, but would need some adjustment if other element types are included, or if other attributes are set by with an index included.
I'll answer my questions in turn:
To select an element which includes square brackets in it's attributes escape the square brackets using double back slashes as follows: var clone = $("#contactFields\[0\]").clone();
& 3. Changing the ids in the tree I have implemented with the following function, where clone is the variable clone (in 1) and count is the count of cloned statements.
function updateAttributes(clone, count) {
var attribute = ['id', 'for', 'name'];
var f = clone.find('*').andSelf();
f.each(function(i){
var tag = $(this);
$.each(attribute, function(i, val){
var s = tag.attr(val);
if (s!=null&& s!="")
{
s = s.replace(/([^\[]+)\[0\]/, "$1["+count+"]");
tag.attr(val, s);
}
});
if ($(this)[0].nodeName == 'SELECT')
{ $(this).val(0);}
else
{
$(this).val("");
}
});
}
This may not be the most efficient way or the best, but it does work in my cases I have used it in. The attributes array could be extended if required, and further elements would need to be included in the defaulting action at the end, e.g. for checkboxes.

Categories