Why isn't querySelectorAll working with my ID values? - javascript

I use this piece of code for a live searching and for calculate the "Total" :
$('#search').keyup(function () {
var x = [];
var y = [];
var $total = 0;
var inputString = $("#search").val();
var act = document.getElementById("labdb").value;
$('td:first-child').parent().show();
$('td:first-child').parent().addClass("notHide");
$('td:first-child').parent().removeClass("toHide");
$var = $('td:first-child').parent('tr:not(:icontains(' + inputString + ')):not(:contains("Total"))');
$var.hide();
$var.addClass('toHide');
$var.removeClass('notHide')
for (var price of document.querySelectorAll('tr.notHide td.price')) {
x.push(parseFloat(price.innerText));
}
for (var cantidad of document.querySelectorAll('tr.notHide td.quantity')) {
y.push(parseFloat(cantidad.innerText));
}
for(var i = 0; i <= x.length-1; i++){
$total += x[i] * y[i];
}
document.getElementById("total"+act).innerText = $total.toFixed(2);
});
I have various tables, with differents ID's, first is id='0', second is id='1', etc.
I use collapse ('show') or ('hide') for show the selected table with a selector.
So, the problems comes when I try to calculate the "Total", It's calculated with the value of the class "notHide" and "price/quantity".
And all the tables get this Class, so the price got crazy if there is more than 1 table with "Total"
I KNOW, that I need to specify the ID of the table to work around, but I cant.
I have tested with:
var act = document.getElementById("labdb").value;
var actHTML = document.getElementById("labdb");
It get the ID from the selected table, and then, in this part of code include it:
for (var price of actHTML.document.querySelectorAll('tr.notHide td.price')) {
x.push(parseFloat(price.innerText));
}
for (var cantidad of actHTML.document.querySelectorAll('tr.notHide td.quantity')) {
y.push(parseFloat(cantidad.innerText));
}
But that, dont work, Im all the time thinking about other solutions and trying it, but I cant.
Its the final part of that page. Only need to specify the ID of the "Total" calculator.
I had tried to with:
for (var price of document.querySelectorAll('#'+act+' tr.notHide td.price')) {
x.push(parseFloat(price.innerText));
}
for (var cantidad of document.querySelectorAll('#'+act+' tr.notHide td.quantity')) {
y.push(parseFloat(cantidad.innerText));
}
For be more specific, I need that document.querySelectorAll('tr.notHide td.quantity') comes from a specific ID. For the rest, works perfectly, inclusive deleting the others tables with the parameter Total
EDIT_0:
I have do that:
let myTable = document.querySelector("#"+act);
let all = myTable.querySelectorAll('tr.notHide td.price');
for (var price of all) {
x.push(parseFloat(price.innerText));
}
for (var cantidad of all) {
y.push(parseFloat(cantidad.innerText));
}
for (var i = 0; i <= x.length - 1; i++) {
$total += x[i] * y[i];
}
from here: LINK
And that is the console error:
scripts.js:57 Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#0' is not a valid selector.
at changePrice (https://neutrino.ugr.es/js/scripts.js:57:28)
at HTMLSelectElement. (https://neutrino.ugr.es/js/scripts.js:15:5)
at HTMLSelectElement.dispatch (https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js:2:43336)
at y.handle (https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js:2:41320)

Well I found the error. The method document.querySelectorAll('') doesn't work if the ID starts with a digit. Like said in an article on the subject:
The spec defines identifiers using a token diagram. They may contain
the symbols from a to z, from A to Z, from 0 to 9, underscores (_),
hyphens -, non-ASCII symbols or escape sequences for any symbol.
They cannot start with a digit, or a hyphen (-) followed by a digit. Identifiers require at least one symbol (i.e. the empty
string is not a valid identifier).
This is the final code:
$('#search').keyup(function () {
var inputString = $("#search").val();
$('td:first-child').parent().show();
$('td:first-child').parent().addClass("notHide");
$('td:first-child').parent().removeClass("toHide");
$var = $('td:first-child').parent('tr:not(:icontains(' + inputString + ')):not(:contains("Total"))');
$var.hide();
$var.addClass('toHide');
$var.removeClass('notHide')
changePrice();
});
function changePrice() {
var x = [];
var y = [];
var $total = 0;
var act = document.getElementById("labdb").value;
actt="t"+act+act;
//alert(act);
var myTable = document.querySelector("#"+actt);
var allx = myTable.querySelectorAll('tr.notHide td.price');
var ally = myTable.querySelectorAll('tr.notHide td.quantity');
//alert(all)
for (var price of allx) {
x.push(parseFloat(price.innerText));
}
for (var cantidad of ally) {
y.push(parseFloat(cantidad.innerText));
}
for (var i = 0; i <= x.length - 1; i++) {
$total += x[i] * y[i];
}
//alert(x.length)
document.getElementById("total" + act).innerText = $total.toFixed(2);
}
I changed the ID to start with a t: actt="t"+act+act;
(act+act is because id is 00, not 0)

Related

Looping through a table rows with comparisons using VUgen

I have a table I need to compare each of the values within to an existing parameter.
I have this Xpath here: //*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[1]/td[4]/div/span
and would like to insert an increment variable from the loop to go through the /tr/ in the table only.
Here is what i have so far:
var i;
var max = 10;
var xpathleft = `*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[`;
var xpathright = `]/td[4]/div/span`;
for (i = 1; i < max, i++)
{
var currentXpath = string.concat(xpathleft, i, xpathright);
}
if (currentXpath.innerHTML == PartnerIDs)
{
lr_log_message("Match Found!");
}
This is currently sitting in an Evaluate Javascript step in TruClient/VUgen and is giving me Syntax Error: Unexpected Token )
The element here doesn't have any ID I can reference and looks like this: Partner ID
and has been difficult to pull the needed Partner ID text within code.
Some of your JavaScript syntax is incorrect.
Try this:
var i;
var max = 10;
var xpathleft = `*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[`;
var xpathright = `]/td[4]/div/span`;
for (i = 1; i < max; i++){
var currentXpath = `${xpathleft}${i}${xpathright}`;
if (currentXpath.innerHTML == PartnerIDs) {
lr_log_message("Match Found!");
}
}

How can I count these words, using script in google sheets?

I'd like to count an occurrence number of one word in a string, but Google Sheets is giving me an error, that it can't deal with the expression:
finalScores.push(preOutputTxt.match(nameArr[x])).length);
because there is null somewhere. How can I fix this?
Full code:
/**
*
*
*
* #customFunction
*/
function scoreCounting(scores, names){
//---variables---//
var scoresArr = [];
var preOutputTxt = "";
var finalScores = [];
var nameArr = [];
//---------------//
//---creating an array from names and scores (scores are in string type)---//
for(var w = 0; w < scores.length; w ++){
scoresArr.push(scores[w]);
}
for(var z = 0; z < names.length; z++){
nameArr.push(names[z]);
}
//---------------------------------------//
//---make one big string with names---//
for(var y = 0; y < scoresArr.length; y++){
preOutputTxt += scoresArr[y];
}
//----------------------------------------------//
//---counting how many times score (a name) occur, basing on name given by nameArr[]---//
for(var x = 0; x < nameArr.length; x++){
finalScores.push(preOutputTxt.match(nameArr[x])).length);
}
return finalScores;
}
As Tedinoz mentioned, it would be easier to offer specific help if you could share a spreadsheet.
But in the meantime, here are two snippets help explain how to get the count of a word in a longer string.
Example 1: If you use match() with the name as the input, you will get just the first match.
[This is because the method expects a regular expression. And passing a string (or a variable set to a string) is similar to a regex with no modifier.]
function example1() {
var preOutputTxt = 'abcabcabc';
var name = 'abc';
var output = preOutputTxt.match(name);
Logger.log('Output is %s. Length is %s.', output, output.length);
}
// Output is [abc]. Length is 1.0.
Example 2: But if you use a regular expression with a global modifier, you will get all the matches.
function example2() {
var preOutputTxt = 'abcabcabc';
var name = 'abc';
var re = new RegExp(name, 'g');
Logger.log('Regular expression is %s', re);
var output = preOutputTxt.match(re);
Logger.log('Output is %s. Length is %s.', output, output.length);
}
// Regular expression is /abc/g
// Output is [abc, abc, abc]. Length is 3.0.

get all variations of a string javascript

I want to get all the variations of a certain string. This string will be broken up by dashes. And the letters can only vary within those dashes.
For instance, let's say I pass DFI3-334-FG12 then I want to get all variations of that string for instance:
FI3-334-G12
FI3-334-F12
FI3-334-FG2
FI3-334-FG1
DI3-334-G12
DI3-334-F12
DI3-334-FG2
DI3-334-FG1
DF3-334-G12
DF3-334-F12
DF3-334-FG2
DF3-334-FG1
DFI-334-G12
DFI-334-F12
DFI-334-FG2
DFI-334-FG1
Can anyone assist with this? I have attempted loops but I only get as far as breaking it up and getting different parts of it:
FI3,DI3,DF3,DFI
334
G12,F12,FG2,FG1
This is my code:
$('#filter').on('click',function() {
var input = $('#code').val();
var parts = input.split("-");
var fixed = Array();
for(var i=0;i<parts.length; i++) {
if(parts[i].length != 3) {
k = 0;
fixed[i] = new Array();
for(var c=0;c<parts[i].length;c++) {
fixed[i][k] = parts[i].replace(parts[i].charAt(c),"");
k++;
}
} else {
fixed[i] = parts[i];
}
}
var final = Array();
$.each(fixed,function(i) {
$('#code_result').append(fixed[i] + "<br>");
})
});
If you know how many segments there are (3 in this case), you can use loops to get every possible combination.
See my example here:
http://jsfiddle.net/a6647m9e/1/
for(var i=0; i<parts[0].length; ++i) {
for(var j=0; j<parts[1].length; ++j) {
for(var k=0; k<parts[2].length; ++k) {
strings.push(parts[0][i]+'-'+parts[1][j]+'-'+parts[2][k]);
}
}
}
And just so you know, you're looking at (2^parts[0].length - 1) * (2^parts[1].length - 1) * (2^parts[2].length - 1) combinations (1575 in this case), taking out the blank combinations.
Note: this is all dependent on what your definition of "all possible combinations" is.
var string= 'DFI3-334-FG12';
var parts = string.split('-');
for(var i=0;i<parts[0].length;i++)
for(var j=0;j<parts[2].length;j++){
p1 = parts[0].substring(0,i)+parts[0].substring(i+1,parts[0].length);
p2 = parts[2].substring(0,j)+parts[2].substring(j+1,parts[2].length);
console.log(p1+'-'+parts[1]+'-'+p2);
}

Get the value for each control from a list of elements?

I'm struggling to get the input value from a control in JavaScript, and I think it may have something to do with the collection of controls I'm looping through.
My page consists of many input controls with decimals in them. I'm only interested in controls starting with the name 'txtinput', and I need to tally up the values in each one. However, when I do this with the code below, all I seem to be getting out is a JSON looking string for each element.
function TallyPoints() {
var eles = [];
var inputs = document.getElementsByTagName("input");
var total = 0;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name.indexOf('txtpoints') == 0) {
total += document.getElementsByName(inputs[i].name)[0].value;
}
}
alert('Total: ' + total.toString());
};
What I end up with is a value that looks like this:
Total: 0{"enabled":false,"emptyMessage":"","validationText":"333.33","valueAsString":"333.33","minValue":-70368744177664,"maxValue":70368744177664,"lastSetTextBoxValue":"333.33"}{"enabled":false,"emptyMessage":"","validationText":"5.66","valueAsString":"5.66","minValue":-70368744177664,"maxValue":70368744177664,"lastSetTextBoxValue":"5.66"}
Any ideas?
You probably want parseFloat() so your addition works properly (fiddle):
var inputs = document.querySelectorAll("input[name^=txtpoints]");
var total = [].reduce.call(inputs, function (p, c) {
return p + (parseFloat(c.value) || 0);
}, 0);
See also parseInt(), isNaN(), and Array.prototype.reduce()
Try this:
function TallyPoints() {
var inputs = document.getElementsByTagName("input");
var total = 0;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name.indexOf('txtpoints') == 0) {
var val = parseFloat(inputs[i].value);
if (!isNaN(val)) {
total += val;
}
}
}
alert('Total: ' + total);
};
parseFloat is needed to convert the input from a string to a number, so that + will do addition rather than concatenation. There's no need to use getElementsByName, since you already have the element in inputs[i]. There's no need to use total.toString(); concatenating a number to a string converts it automatically.
The if (!isNan(val)) test skips over the inputs that don't contain numbers.
You could also use document.querySelectorAll('input[name^=txtpoints]') to find the relevant input elements in one step.

JavaScript getElementById null values error and how to avoid it

I have created a form where user inputs the minimum and maximum number of textareas that can be added to a page. It generates the code below in order to pick it up with JScript:
$minimum .= '<div id="K'.$i.'">'.$min[$i].'</div>';
$maximum .= '<div id="H'.$i.'">'.$max[$i].'</div>';
In JScript, I defined a loop that will catch the above div tags and theirs innerHTMLs as numbers and put it in an array.
var mincount = [];
var maxcount = [];
for(var k=1; k<101; k++) {
mincount[k] = parseInt(document.getElementById("K"+k).innerHTML, 10);
maxcount[k] = parseInt(document.getElementById("H"+k).innerHTML, 10);
}
The k is defined to be up to 100. So, I know this is the problem, because then if there are less then 100 textareas, the getElementById is having null values.
So, it gives error:
Uncaught TypeError: Cannot read property 'innerHTML' of null
But it must be defined to be up to 100. So, is there any option that can work something like this:
if(mincount[k] == null) {mincount[k] = ""} // in order to avoid null values.
This isn't working. It still get an error.
The easier solution would be to give those elements the same class, and then just select all elements with that class. I don't see a reason why every element must have their own ID.
$minimum .= '<div class="K">'.$min[$i].'</div>';
$maximum .= '<div class="H">'.$max[$i].'</div>';
Then you do in JavaScript:
var mincount = [];
var minelements = document.querySelectorAll('.K');
for (var i = 0, l = minelements.length; i < l; i++) {
mincount.push(parseInt(minelement[i].innerHTML, 10));
// if the content is purely numeric, unary plus is simpler:
// mincount.push(+minelement[i].innerHTML);
}
Same of maxcount.
Or as #adeneo suggested, if your JavaScript code is also served through PHP and you have access to the $min array, just do
var mincount = <?php echo json_encode($min); ?>;
Then you don't even how to touch the DOM.
The simplest way to test for null values is a simple equality check.
...
...
for(var k=1; k<101; k++) {
var K_el = document.getElementById("K"+k);
var H_el = document.getElementById("H"+k);
if ( K_el != null && H_el != null ) {
mincount[k] = parseInt(K_el.innerHTML, 10);
maxcount[k] = parseInt(H_el.innerHTML, 10);
}
}
Unless these values can be modified by the user, it would be easier to calculate the min's and max's in PHP.
A preferred solution is to just put a common class on each element of a given type and query the elements that actually exist:
$minimum .= '<div class="K" id="K'.$i.'">'.$min[$i].'</div>';
$maximum .= '<div class="H" id="H'.$i.'">'.$max[$i].'</div>';
var mincount = [];
var maxcount = [];
var kItems = document.querySelectorAll(".K");
var hItems = document.querySelectorAll(".H");
for (var i = 0, len = Math.min(kItems.length, hItems.length); i < len; i++) {
mincount[i] = parseInt(kItems[i].innerHTML, 10);
maxcount[i] = parseInt(hItems[i].innerHTML, 10);
}
Without changing the HTML and keeping with your current code approach, you can just check to see if an element exists before trying to use it.:
var mincount = [];
var maxcount = [];
var objK, objH;
for(var k=1; k<101; k++) {
objK = document.getElementById("K"+k);
objH = document.getElementById("H"+k);
if (objK) {
mincount[k] = parseInt(objK.innerHTML, 10);
}
if (objH) {
maxcount[k] = parseInt(objH.innerHTML, 10);
}
}
Or, if you know that as soon as one object doesn't exist, you should break out of the for loop, you can do this:
var mincount = [];
var maxcount = [];
var objK, objH;
for(var k=1; k<101; k++) {
objK = document.getElementById("K"+k);
objH = document.getElementById("H"+k);
if (!objK || !objH) {
break;
}
mincount[k] = parseInt(objK.innerHTML, 10);
maxcount[k] = parseInt(objH.innerHTML, 10);
}

Categories

Resources