Joining Duplicate Items and Adding Quantity - javascript

I am working with two bits of text contained in <div> tags. One contains the items, the other contains quantity. However, sometimes I have multiple items that are the same with different quantities, therefore I cannot just count the occurrences of a string (I started by using this method and discovered that it only works if quantity is 1).
This is the code I am working with:
var joinArr = $('#rechighlight').html(); //get the recieved items
var qtyArr = $('#qtyArray').html(); //get the recieved qty
var createArr = joinArr.trim().split('<br>'); //split by br tag
var createArrQty = qtyArr.trim().split('<br>'); //split by br tag
var resultingArr = [createArr, createArrQty] //creates array in correct order
.reduce((r, a) => (a.forEach((a, i) => (r[i] = r[i] || []).push(a)), r), [])
.reduce((a, b) => a.concat(b));
var stringArr = JSON.stringify(resultingArr); //stringify results
document.getElementById("finArray").innerHTML = stringArr; //add results into new div
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>
Items
</td>
<td>
QTY
</td>
</tr>
<tr>
<td>
<div id="orderhighlight">AAA <br> BBB<br>CCC<br></div>
</td>
<td>
<div>5<br>3<br>2<br></div>
</td>
</tr>
<tr>
<td>
Recieved Items
</td>
<td>
Recieved QTY
</td>
</tr>
<tr>
<td>
<div id="rechighlight">AAA<br>BBB<br>AAA<br>CCC<br>CCC<br></div>
</td>
<td>
<div id="qtyArray">3<br>3<br>2<br>1<br>1<br></div>
</td>
</tr>
<tr>
<td>
MY OUTPUT
</td>
</tr>
<tr>
<td>
<div id="finArray"></div>
</td>
</tr>
<tr>
<td>
EXPECTED OUTPUT
</td>
</tr>
<tr>
<td>
<div>["AAA","5","BBB","3","CCC","2","",""]</div>
</td>
</tr>
</table>
What I've Tried:
I found a way to merge duplicated values on the item side by using the following code.
var occurrences = resultingArr.reduce(function(obj, item) {
obj[item] = (obj[item] || 0) + 1;
return obj;
}, {});
But of course, the issue there is that the quantity is seen as a string to merge.
In summary, how do I merge duplicate string in an array and their quantity (as reflected in the expected output on HTML line 52).

Your reduce function just needs to be constructed in the following way:
var occurrences = createArr.reduce(function(obj, item, index) {
obj[item] = Number(obj[item] || 0) + Number(createArrQty[index]);
return obj;
}, {});
reduce the first array with the keys, and sum the array with the quantities.
Although you need to remove the last item from each array since it is an empty value from your .split function.
Just do a pop() in both of them.
Code below.
var joinArr = $('#rechighlight').html(); //get the recieved items
var qtyArr = $('#qtyArray').html(); //get the recieved qty
var createArr = joinArr.trim().split('<br>'); //split by br tag
var createArrQty = qtyArr.trim().split('<br>'); //split by br tag
createArr.pop();
createArrQty.pop();
var occurrences = createArr.reduce(function(obj, item, index) {
obj[item] = Number(obj[item] || 0) + Number(createArrQty[index]);
return obj;
}, {});
var stringArr = JSON.stringify(occurrences); //stringify results
document.getElementById("finArray").innerHTML = stringArr; //add results into new div
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>
Items
</td>
<td>
QTY
</td>
</tr>
<tr>
<td>
<div id="orderhighlight">AAA <br> BBB<br>CCC<br></div>
</td>
<td>
<div>5<br>3<br>2<br></div>
</td>
</tr>
<tr>
<td>
Recieved Items
</td>
<td>
Recieved QTY
</td>
</tr>
<tr>
<td>
<div id="rechighlight">AAA<br>BBB<br>AAA<br>CCC<br>CCC<br></div>
</td>
<td>
<div id="qtyArray">3<br>3<br>2<br>1<br>1<br></div>
</td>
</tr>
<tr>
<td>
MY OUTPUT
</td>
</tr>
<tr>
<td>
<div id="finArray"></div>
</td>
</tr>
<tr>
<td>
EXPECTED OUTPUT
</td>
</tr>
<tr>
<td>
<div>["AAA","5","BBB","3","CCC","2","",""]</div>
</td>
</tr>
</table>

Related

How to hide a table row or result if checkbox is checked AND if 0 result/count

I have this counter for word occurrence in the textarea. The problem is, I have a lot of items in the table, and so it can be distracting to include the zero results.
So what I'm hoping to achieve is, if the user checks the checkbox, it will not show the zero results anymore (preferably the whole row)..
Please see the code so far:
let textarea = $('#textarea3');
textarea.on('keyup', _ => counting());
function counting() {
var searchText = $('#textarea3').val();
let words = [];
words['1 sample'] = '#one';
words['2 sample'] = '#two';
words['3 sample'] = '#three';
words['4 sample'] = '#four';
words['5 sample'] = '#five';
words['6 sample'] = '#six';
for (const word in words) {
var outputDiv = $(words[word]);
outputDiv.empty();
let count = searchText.split(word).length - 1;
searchText = searchText.replaceAll(word,'');
outputDiv.append('<a>' + count + '</a>');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox">
<label> Don't show zero results</label><br>
<button onclick="counting();">Count</button>
<table>
<thead>
<tr>
<th scope="col">Items</th>
<th scope="col">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 sample</td>
<td><a id="one"></a></td>
</tr>
<tr>
<td>2 sample</td>
<td><a id="two"></a></td>
</tr>
<tr>
<td>3 sample</td>
<td><a id="three"></a></td>
</tr>
<tr>
<td>4 sample</td>
<td><a id="four"></a></td>
</tr>
<tr>
<td>5 sample</td>
<td><a id="five"></a></td>
</tr>
<tr>
<td>6 sample</td>
<td><a id="six"></a></td>
</tr>
</tbody>
</table>
<textarea id="textarea3" rows="5">
1 sample
2 sample
3 sample
5 sample
</textarea>
If the checkbox isn't checked, it should function as is and still show all results.
I've seen this post but I'm not really sure how to implement it to my own project. Show or hide table row if checkbox is checked
Thank you in advance for any help.
Consider the following.
$(function() {
var textarea = $('#textarea3');
var words = [];
$("table tbody tr").each(function(i, row) {
words.push({
term: $("td:eq(0)", row).text().trim(),
rel: "#" + $("a", row).attr("id"),
count: 0
});
});
function count() {
var searchText = textarea.val();
$.each(words, function(i, word) {
if (searchText.indexOf(word.term) >= 0) {
var re = new RegExp('(' + word.term + ')', 'gi');
word.count = searchText.match(re).length;
$(word.rel).html(word.count);
} else {
word.count = 0;
if (!$("#noShowZero").is(":checked")) {
$(word.rel).html(word.count);
} else {
$(word.rel).html("");
}
}
});
}
textarea.keyup(count);
$("#count-btn, #noShowZero").click(count);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="noShowZero" type="checkbox">
<label> Don't show zero results</label><br>
<button id="count-btn">Count</button>
<table>
<thead>
<tr>
<th scope="col">Items</th>
<th scope="col">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 sample</td>
<td>
<a id="one"></a>
</td>
</tr>
<tr>
<td>2 sample</td>
<td>
<a id="two"></a>
</td>
</tr>
<tr>
<td>3 sample</td>
<td>
<a id="three"></a>
</td>
</tr>
<tr>
<td>4 sample</td>
<td>
<a id="four"></a>
</td>
</tr>
<tr>
<td>5 sample</td>
<td>
<a id="five"></a>
</td>
</tr>
<tr>
<td>6 sample</td>
<td>
<a id="six"></a>
</td>
</tr>
</tbody>
</table>
<textarea id="textarea3" rows="5">
1 sample
2 sample
3 sample
5 sample
</textarea>
When the User:
Enters text in the textbox
Clicks the checkbox
Clicks the Button
then count function is executed.
Count will review all the words and look for specific keywords. A count of them is also retained, as well as element relationship to show that count.
Using Regular Expressions, we can search for the words in the text and count them using .match(). It returns an Array of the matches. You could also use .replace(), to remove them.

Convert HTML table to javascript array using class names

How do you convert an HTML table to a javascript array using the tags's class names as the array values?
Say we have the following HTML code:
<table class="grid">
<tr>
<td class="available"></td>
<td class="busy"></td>
<td class="busy"></td>
<td class="available"></td>
</tr>
<tr>
<td class="busy"></td>
<td class="available"></td>
<td class="busy"></td>
<td class="available"></td>
</tr>
</table>
I want the array to look like: [["available","busy","busy","available"],["busy","available","busy","available"]]
I have tried the following:
var myTableArray = [];
$("table#grid tr").each(function() {
var arrayOfThisRow = [];
var tableData = $(this).find('td');
if (tableData.length > 0) {
tableData.each(function() { arrayOfThisRow.push($(this).text()); });
myTableArray.push(arrayOfThisRow);
}
});
console.log(myTableArray);
but it is printing an empty array as the td tags contain no text. I then tried replacing
$(this).text()
with
$(this).className()
but that did not work. Any suggestions?
map is the way to go.
jQuery's $.map is a little weird in that it seems to think it's ok to flatten mapped arrays without asking and we're not going to fix it so you have to couch the mapped array in an array.
// Cache the rows
const rows = $('.grid tr');
// `map` over each row...
const arr = $.map(rows, row => {
// Find the row cells...
const cells = $(row).find('td');
// ...and return an array of each cell's text
return [$.map(cells, cell => $(cell).text())];
});
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="grid">
<tr>
<td class="available">available</td>
<td class="busy">busy</td>
<td class="busy">busy</td>
<td class="available">available</td>
</tr>
<tr>
<td class="busy">busy</td>
<td class="available">available</td>
<td class="busy">busy</td>
<td class="available">available</td>
</tr>
</table>
Alternatively, if you wanted a vanilla JS solution, you can just pick up the rows with querySelectorAll, and then iterate over them with map, then return the text from the cell (assuming that you fix the HTML).
(Note: [...nodelist] is shorthand for creating an array from a nodelist so that map can work. You could also use Array.from(nodelist)).
// Cache the rows
const rows = document.querySelectorAll('.grid tr');
// `map` over each row...
const arr = [...rows].map(row => {
// Find the row cells...
const cells = row.querySelectorAll('td');
// ...and return an array of each cell's text
return [...cells].map(cell => cell.textContent);
});
console.log(arr);
<table class="grid">
<tr>
<td class="available">available</td>
<td class="busy">busy</td>
<td class="busy">busy</td>
<td class="available">available</td>
</tr>
<tr>
<td class="busy">busy</td>
<td class="available">available</td>
<td class="busy">busy</td>
<td class="available">available</td>
</tr>
</table>
Vanilla JS Solution
Get and Make array with <tr>
Map every <tr> and make array with <td> elements
Map only class names from every <td>
The example will return ARRAY from CLASS element names.
Example:
var res = [...document.querySelectorAll('.grid tr')] // 1. Get and Make array with <tr>
.map((el) => [...el.children] // 2. Map every <tr> and make array with <td> elements
.map(e => e.getAttribute('class'))); // 3. Map only class names from every <td>
console.log(res);
<table class="grid">
<tr>
<td class="available"></td>
<td class="busy"></td>
<td class="busy"></td>
<td class="available"></td>
</tr>
<tr>
<td class="busy"></td>
<td class="available"></td>
<td class="busy"></td>
<td class="available"></td>
</tr>
</table>
This example will make ARRAY from the text content of the table.
Example:
var res = [...document.querySelectorAll('.grid tr')] // 1. Get and Make array with <tr>
.map((el) => [...el.children] // 2. Map every <tr> and make array with <td> elements
.map(e => e.innerText)); // 3. Map only text content from every <td>
console.log(res);
<table class="grid">
<tr>
<td>available</td>
<td>busy</td>
<td>busy</td>
<td>available</td>
</tr>
<tr>
<td>busy</td>
<td>available</td>
<td>busy</td>
<td>available</td>
</tr>
</table>

Print array in the table td

I am new in Javascript, I have an array, and want to print it in the table td.
This is my array:
array = [100, 200, 300];
This is my table:
<table>
<th> Result</th>
<tbody>
<tr>
<td> My result 1</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 2</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 3</td>
<td class='result'></td>
</tr>
</tbody>
</table>
I want to print my array in the td with class name 'result'
You can use querySelectorAll() and Node.textContent:
const array = [100, 200, 300];
const elements = [...document.querySelectorAll('.result')];
for(let i = 0; i < array.length; i++) {
elements[i].textContent = array[i];
}
<table>
<th> Result</th>
<tbody>
<tr>
<td> My result 1</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 2</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 3</td>
<td class='result'></td>
</tr>
</tbody>
</table>
Just iterate over the array and use the current index for the HTML element as well.
Possible ES5-only solution:
var array = [100, 200, 300];
for (var i = 0; i < array.length; i++){
document.getElementsByClassName("result")[i].innerHTML = array[i];
}
<table>
<th> Result</th>
<tbody>
<tr>
<td> My result 1</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 2</td>
<td class='result'></td>
</tr>
<tr>
<td> My result 3</td>
<td class='result'></td>
</tr>
</tbody>
</table>
Note: You need an equal amount of array elements and elements with the .result class.
Assign an id attribute to the table tag, id = "tab". Then add the below javascript code
pointer=0
arr=[100,200,300];
// selecting all the tags having result as class name
var nodes=document.getElementById("tab").getElementsByClassName("result");
arr.forEach((ele)=>{nodes[pointer].innerHTML=ele;pointer+=1});
Look at this example:
I use querySelectorAll
It considers the case if the array elements and the quantity of rows are diffrerent.
Also added '.myTable' to prevent target other '.result' nodes out of the selected table.
Hope it helps.
<table class="myTable">
<th> Result</th>
<tbody>
<tr><td> My result 1</td><td class='result'></td></tr>
<tr><td> My result 2</td><td class='result'></td></tr>
<tr><td> My result 3</td><td class='result'></td></tr>
<tr><td> My result 4</td><td class='result'></td></tr>
</tbody>
</table>
<script>
const array = [100, 200, 300];
const rows = document.querySelectorAll('.myTable .result') // <-- I added '.myTable' to prevent target other '.result' nodes out of the selected table
rows.forEach((row, i) => {
if (array[i]) row.innerHTML = array[i] // <-- I replace the innerHTML if the array has content at that index
});
</script>
You can do this,
var result = document.getElementsByClassName("result")
var array = [100,200,300]
for (var i=0;i<result.length;i++){
result[i].innerHTML = array[i];
}
Demo
Hope this helps you... No need to update table according to array data....
Table code:
<table>
<th colspan="2" >Result</th>
<tbody id="myTableBody"></tbody>
</table>
JavaScript code:
<script>
var tableRef = document.getElementById('myTableBody');
var array = [100, 200, 300];
for (var i = 0; i < array.length; i++){
tableChild = document.createElement('tr');
tableChild.innerHTML = "<td> My result "+(i+1)+"</td><td class='result'>"+array[i]+"</td>";
tableRef.appendChild(tableChild);
}
</script>
Example: https://codepen.io/Nishanth_V/pen/rEZmxN
var el = document.getElementsByClassName('result');
var array = [100, 200, 300];
for(var i =0 ; i < el.length && i < array.length; ++i) {
el[i].innerHTML = array[i];
}
You have to replace ' by " and add numbers to your class , after that your code with look like this:-
<table>
<th> Result</th>
<tbody>
<tr>
<td> My result 1</td>
<td class="result1"></td>
</tr>
<tr>
<td> My result 2</td>
<td class="result2"></td>
</tr>
<tr>
<td> My result 3</td>
<td class="result3"></td>
</tr>
</tbody>
</table>
Your JavaScript code will look like this:-
<script>
var array = [100, 200, 300];
array.foreach(function (item, index){
var resultNum = index + 1;
document.getElementByClassName("result" + resultNum).innerHTML = item;
});
</script>

filter table rows not working

I've have a html table where I'm trying to filter by keeping the rows that match on the text written. But whatever I write in my textbox the first row is always removed..
JS:
$("#searchInput").keyup(function () {
//split the current value of searchInput
var data = this.value.split(" ");
//create a jquery object of the rows
var jo = $("#fbody").find("tr");
if (this.value == "") {
jo.show();
return;
}
//hide all the rows
jo.hide();
//Recusively filter the jquery object to get results.
jo.filter(function (i, v) {
var $t = $(this);
for (var d = 0; d < data.length; ++d) {
if ($t.is(":contains('" + data[d] + "')")) {
return true;
}
}
return false;
})
//show the rows that match.
.show();
}).focus(function () {
this.value = "";
$(this).css({
"color": "black"
});
$(this).unbind('focus');
}).css({
"color": "#C0C0C0"
});
Table:
<input id="searchInput" value="Type To Filter">
<br/>
<table class="mGrid" id="table">
<tr>
<th>
COLUMN1
</th>
<th>
COLUMN2
</th>
<th>
COLUMN3
</th>
</tr>
<tbody ID="fbody">
<tr>
<td>
NAME1
</td>
<td>
3
</td>
<td>
HOUSE
</td>
</tr>
<tr>
<td>
NAME2
</td>
<td>
5
</td>
<td>
LAKE
</td>
</tr>
<tr>
<td>
NAME3
</td>
<td>
7
</td>
<td>
DOG
</td>
</tr>
<tr>
<td>
NAME555
</td>
<td>
1337
</td>
<td>
CAT
</td>
</tr>
</tbody>
</table>
http://jsfiddle.net/ukW2C/1350/
Problem was with the HTML. I had multiple IDs. Query is now updated and working

Search the table by cell content with jquery and relative referencing

Having such table
<table>
<thead> ... </thead>
<tbody>
<tr class="TableOdd">
<td class="TableCol0"> 1 </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> x </td>
<td class="TableCol3"> # </td>
</tr>
<tr class="TableEven">
<td>....</td>
</tr>
</tbody>
E.g. each cell has own class indicating it's column number TableCol0,1,2..N
In each row, needed compare the content of the cells in column 1 and 2 and write the result into colum3.
Managed the following script,
$(document).ready(function() {
var toterr = 0;
$('tbody tr.TableEven,tbody tr.TableOdd').each(function() {
var wanted = $(this).find('.TableCol1' ).html();
var actual = $(this).find('.TableCol2' ).html();
//console.log('wanted='+wanted+'=actual='+actual+'=');
if ( wanted == actual ) {
$(this).find('.TableCol3').text('ok');
} else {
$(this).find('.TableCol3').text('ERROR');
toterr++;
}
});
$('#totalerror').text(toterr);
});
It is probably not optimal, but works.
Now have a bit different scenario: Need compare two cells what are before a cell with a specified content (:CMP:), e.g:
<table>
<thead> ... </thead>
<tbody>
<tr class="TableOdd">
<td class="TableCol0"> x </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> :CMP: </td>
<td class="TableCol3"> etc </td>
</tr>
<tr class="TableEven">
<td class="TableCol0"> N </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> y </td>
<td class="TableCol3"> :CMP: </td>
</tr>
</tbody>
For each row, need compare cells what are before :CMP:, and replace the :CMP: with the result. e.g.
in the 1st row need compare the x and x and write ok in the cell .TableCol2
in the 2nd row need compare the x and y and write ERROR in the cell .TableCol3
I haven't idea how to modify the above script.
Can easily get the index of the cell that contains ':CMP:' and use the index to reference the previous cells. Or use traverses like prev() or use eq() once index is found.
$('tbody tr').each(function () {
var $cells = $(this).children(),
$cmp = $cells.filter(':contains(":CMP:")'),
cmpIndex = $cells.index($cmp);
// array of values of previous cells
var values = $.map($cells.slice(cmpIndex - 2, cmpIndex), function (el) {
return $.trim($(el).text());
});
// make sure we have 2 cells with values and compare
var cmpText = values.length === 2 && values[0] === values[1] ? 'OK' : 'ERROR';
$cmp.text(cmpText);
});
DEMO

Categories