check value in table row column - javascript

I have a html table - TemplateData. Inside the Tbody I have a column on each row 'data-uid', which may not be unique. I have sorted the table before it is displayed in ascending order. It looks like so:
<tr id="Tr2" data-uid="1" role="row" class="odd"/>
<tr id="Tr2" data-uid="2" role="row" class="even"/>
<tr id="Tr2" data-uid="2" role="row" class="odd"/>
<tr id="Tr2" data-uid="2" role="row" class="even"/>
<tr id="Tr2" data-uid="3" role="row" class="odd"/>
<tr id="Tr2" data-uid="4" role="row" class="odd"/>
NOTE 2 appears three times. Each value may appear more than once
I can get the table by using:
var table = $('#TemplateData').dataTable();
My Question being: if I have a value stored in 'val' how can I check the table to get the row with data-uid=val;
so...something like table.rows[val]
From here check the next row to see if its data-uid is different from val. If so pass back this value. If not continue onto the next row until you find a different value.
So....
val = 2
get table.row[where val = data-uid]
check next row
if table.rows[data-uid = val] continue until it is not the same, when value is different pass back
var newVal = ?
....any help would be appreciated thanks

This is with pure JavaScript, hope it helps.
var elements = document.getElementsByTagName('tr');
var elementsLength = elements.length;
for (var i = 0; i < elements.length; i++) {
var currentElement = elements[i].getAttribute('data-uid');
for (var j = i + 1; j < elements.length; j++) {
var nextElement = elements[j].getAttribute('data-uid');
if(currentElement !== nextElement) {
return elements[j].getAttribute('data-uid');
}
}
}
God luck,
Zorken17

Even if you are not using it, id attribute should be unique.
Then, you can use jquery select syntax to get rows with some characteristics:
function datavalchanged(value) {
..put code to execute at change detection;
}
var group = $('tr[role="row"]');
var desired dataval = group[0].getAttribute('data-uid');
/* additionally put dataval=0 to detect also first data-uid change. */
to get all rows that have role = row and cycle trought them like an array.
for (var i = 0; i < group.length; i++) {
var row = group[i];
var value = row.getAttribute('data-uid');
while (value == dataval) {
continue;
}
datavalchanged(value);
dataval=value;
/*ready for next change detection or force exit if interested in first change*/
}
at the end of while loop the value has the next value u need.
edit:
it looks like that what i wrote it does not work if the html is not complete:
<table>
<tr id="Tr2" data-uid="1" role="row" class="odd" ><td></td></tr>
<tr id="Tr2" data-uid="2" role="row" class="even"><td></td></tr>
<tr id="Tr2" data-uid="2" role="row" class="odd" ><td></td></tr>
<tr id="Tr2" data-uid="2" role="row" class="even"><td></td></tr>
<tr id="Tr2" data-uid="3" role="row" class="odd" ><td></td></tr>
<tr id="Tr2" data-uid="4" role="row" class="odd" ><td></td></tr>
</table>

Related

Javascript nested loop crashes browser

I am creating a web app with Django and I require some Javascript for changing styles of dynamically generated elements. I have simplified the code to just static html and javascript.
Goal:
The code causing problems is acting on detail pages.
There are many detail pages, each representing data from a given database entry.
Each page will have 1 or more table, depending on how many protein names the database entry has.
For each table, I want to change the colour of the entry for the protein name in the table heading as well as the entry for the example_id.
Attempt:
I am using javascript to capture the example_id from the top level heading and the protein names from the table headings.
I am then capturing the nodelist of table rows and iterating through, looking for entries that match either the protein name or the example_id.
Problem:
When iterating over the nodelist of protein names taken from the table headers in a nested loop the page never loads.
HTML:
<html>
<body>
<h1 class="msaIdCatcher">Protein Record #example_id</h1>
<h2>Multiple Sequence Alignment</h2>
<h3 class= "msaProtNameCatcher">Protein_name1</h3>
<p>The following is a multiple sequence alignment (MSA) of all sequences predicted to be Protein_name1 sequences.</p>
<table>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>Protein_name1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id3</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>example_id</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id4</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
</table>
<h3 class="msaProtNameCatcher">Protein_name2</h3>
<p>The following is a multiple sequence alignment (MSA) of all sequences predicted to be Protein_name2 sequences.</p>
<table>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id1</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id2</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id3</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>example_id</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>not_example_id4</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr class=sequenceidrow>
<th class=sequenceid>Protein_name2</th>
<td class="alignsequence">aaaaaaaaaaaaaaaaaaaa</td>
</tr>
</table>
</body>
</html>
var idTitle = document.getElementsByClassName("msaIdCatcher");
id = idTitle[0].innerHTML;
id = id.replace("Protein Record #", "");
//Get protein_names from table headers
proteinnameElements = document.getElementsByClassName("msaProtNameCatcher")
//Get table rows
var sequenceidrowElements = document.getElementsByClassName("sequenceidrow");
//Loop through table rows
for (var i = 0; i < sequenceidrowElements.length; i++) {
//Get sequence id
var sequenceidElement = sequenceidrowElements[i].getElementsByClassName("sequenceid");
idElement = sequenceidElement[0].innerHTML
//Check if ID is ID from page heading
if (idElement == id) {
//Get sequence element and change colour of ID and sequence elemnt
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "#b80090";
alignsequenceElement[0].style.color = "#b80090";
}
//Loop through protein names in table headers and Check if ID in table matches protein name
//Then change colour of ID and sequence
for (var i = 0; i < proteinnameElements.length; i++) {
proteinname = proteinnameElements[i].innerHTML
if (idElement == proteinname) {
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "red";
alignsequenceElement[0].style.color = "red";
}
}
}
However, when using a single protein name by making proteinname equal to the innerHTML of the first element proteinnameElements and taking away the loop nesting as follows, the page loads in a fraction of a second.
var idTitle = document.getElementsByClassName("msaIdCatcher");
id = idTitle[0].innerHTML;
id = id.replace("Protein Record #", "");
//Get protein_names from table headers
proteinnameElements = document.getElementsByClassName("msaProtNameCatcher")
proteinname = proteinnameElements[0].innerHTML
//Get table rows
var sequenceidrowElements = document.getElementsByClassName("sequenceidrow");
//Loop through table rows
for (var i = 0; i < sequenceidrowElements.length; i++) {
//Get sequence id
var sequenceidElement = sequenceidrowElements[i].getElementsByClassName("sequenceid");
idElement = sequenceidElement[0].innerHTML
//Check if ID is ID from page heading
if (idElement == id) {
//Get sequence element and change colour of ID and sequence elemnt
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "#b80090";
alignsequenceElement[0].style.color = "#b80090";
}
//Loop through protein names in table headers and Check if ID in table matches protein name
//Then change colour of ID and sequence
if (idElement == proteinname) {
var alignsequenceElement = sequenceidrowElements[i].getElementsByClassName("alignsequence");
sequenceidElement[0].style.color = "red";
alignsequenceElement[0].style.color = "red";
}
}
Can someone help me understand why nesting loops in this way causes such a large difference in runtime and help me find a way to solve my problem?
Thanks!
Your inner loop begins with var i, because of how scoping works in JavaScript, it will be the same i as the outer loop, and it will be changed everytime the inner loop is run (thereby never increasing the outer loop, making it endless); it's like typing this:
var i;
for (i = 0; i < length; ++i)
{
for (i = 0; i < length2; ++i)
{
//...
}
}
Either use a different variable name for the inner loop (j is a common choice), or use the let keyword (which will ensure the variables are locally scoped), this is the let keyword (note that it's relatively recent):
for (let i = 0; i < length; ++i)
{
//...
}
Hope this helps clear things up.

Access to oldChild by replaceChild with getElementsClassName, Javascript, DOM

How can I get access to the old Node and replace it?
My XHTML has this structure:
<table id="output">
<tr>
<td>Sometext</td>
<td>...</td>
<td>...<td>
</tr>
<tr class="CLASSNAME">
<td class="ElemKat">text</td>
<td class="ELEM">...</td>
<td class="EL">...</td>
</tr>
<tr class="CLASSNAME">
<td class="ElemKat">text2</td>
<td class="ELEM">s</td>
<td class="EL">sss</td>
</tr>
</table>
I have so many classes, because the elements are create dynamically and so the IDs are not a variant.
And the function, in which the error shows up (error as a comment):
var sort=function(cmpFunc) {
var table=document.getElementById("output");
var kat=document.getElementsByClassName("ElemKat");
var elem_kat=new Array();
for(var i=0; i<kat.length; i++) {
elem_kat.push(kat[i]);
}
var elem_kat_old=new Array();
elem_kat_old=elem_kat;
elem_kat.sort(cmpFunc);
for(var j=0; j<elem_kat.length; j++) {
//table=elem_kat_old[j].parentNode; ->No error,but no change in the output
table.replaceChild(elem_kat[j],elem_kat_old[j]); //Node was not found
}
}
Instead of elem_kat_old = elem_kat;, try this:
elem_kat_old = elem_kat.slice(0)
Assigning an array to another array makes it so that whatever you do to one array, happens to the other array. This isn't quite assignment by reference, but I am not 100% sure of the proper Javascript term for it.

jQuery: select tr having all td matching the filter criteria dynamically

Title might be a bit confusing, but this is the best I could come up with.
I need to find all tr elements which contains td elements matching the filter criteria provided.
Here is my sample,
<tr class="row" id="1">
<td class="philips">PHILIPS</td>
<td class="h4">H4</td>
<td class="lamp">Lamp<td>
</tr>
<tr class="row" id="2">
<td class="philips">PHILIPS</td>
<td class="h5">H5</td>
<td class="bulb">Bulb<td>
</tr>
<tr class="row" id="3">
<td class="neglin">NEGLIN</td>
<td class="w5w">W5W</td>
<td class="tube">Tube<td>
</tr>
<tr class="row" id="4">
<td class="philips">PHILIPS</td>
<td class="h4">H4</td>
<td class="bulb">Bulb<td>
</tr>
<tr class="row" id="5">
<td class="osram">OSRAM</td>
<td class="hb3">HB3</td>
<td class="tube">Tube<td>
</tr>
<tr class="row" id="6">
<td class="neglin">NEGLIN</td>
<td class="w5w">W5W</td>
<td class="lamp">Lamp<td>
</tr>
If I pass filter[0] as 'phillips', the result return tr with id
1
2 and
4
Then if I pass second filter; filter[1] as 'h4', the result should be filtered down to
1 and
4
I have tried this question.
Which has this answer.
$('tr')
.has('td:nth-child(1):contains("Audi")')
.has('td:nth-child(2):contains("red")')
.doSomeThing();
But, I want my filters to be applied dynamically. How would I be able to insert a 3rd has function?
I don't want to go the if-else or switch-case way, if this is possible with out them.
You can try this.
<script type="text/javascript">
$(document).ready(function () {
var result = filter([".philips", ".h4"]);
alert(result);
var result_2 = filter([".philips"]);
alert(result_2);
});
function filter(params) {
var select = "tr";
for (var i = 0; i < params.length; i++) {
select += ":has(" + params[i] + ")";
}
return $(select).map(
function () {
return $(this).attr('id');
}
).get();
}
</script>
if you have an array of filters needed, iterate that array and pass the filter string to the has?
var filters = ['PHILIPS', 'H4', 'Bulb']
var result = $('tr');
for(var i = 0; i < filters.length; i++){
var nchild = i+1;
result = result.has('td:nth-child('+nchild+'):contains("+'filters[i]'+")');
}
edit to your needs of course, but this way you can take user input, compile that into the needed array and then iterate whatever is in the array to filter down results.
You should wrap the $.has() into a separate function (I've just used jquery's easy extensions supports) which will expose the usage as a composite function chain via javascript's syntax...
$( document ).ready(function() {
$('tr')
.nthFilter('td:nth-child(1):contains("PHILIPS")')
.nthFilter('td:nth-child(2):contains("H4")')
.nthFilter('td:nth-child(3):contains("Bulb")')
.css("background-color", "red");
});
jQuery.fn.extend({
nthFilter: function(filter) {
return $(this).has(filter);
}
});
I've put together a small jsfiddle for you to fiddle with :)
You can supply your filter as a string:
var filter = ".philips, .h4";
$("tr").has("td").has(filter).map(function() { return this.id; });
// returns ["1", "2", "4"]
and if you want the elements then obviously leave the map off:
$("tr").has("td").has(filter);
// returns array of <tr>
Edit: Just noticed you want recursive filtering so change the filter to use sibling selector ~.
var filter = ".philips ~ .h4";
// returns ["1", "4"]
So if you want a third level then just:
var filter = ".philips ~ .h4 ~ .bulb";
// returns ["4"]

Iterate over cells with incrementing ids

I want to fill a table with values using Javascript/Jquery.
I have a table with incrementing ids (td-1until td-42) and I want to fill this table using JQuery/Javascript.
Currently I am using this script, but I know the error $('#td-'+i) can't work, because the ID used is build wrong: $('#td-'12) is not a valid id.
Has someone a quick fix for this? I am stuck...
for (var i = 1; i < 43; i++) {
if (i < firstDay || i >= (howMany + firstDay)) {
$('#td-'+i).value("");
} else {
$('#td-'+i).value(i-firstDay);
}
}
Use text() and it worked.
var firstDay = 3, howMany = 1;
for (var i = 1; i < 7; i++) {
if (i < firstDay || i >= (howMany + firstDay)) {
$('#td-'+i).text("");
} else {
$('#td-'+i).text(i-firstDay);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td id='td-1'></td>
</tr>
<tr>
<td id='td-2'></td>
</tr>
<tr>
<td id='td-3'></td>
</tr>
<tr>
<td id='td-4'></td>
</tr>
<tr>
<td id='td-5'></td>
</tr>
<tr>
<td id='td-6'></td>
</tr>
</table>
First off, reconsider putting a large amount of IDs on elements for efficiency reasons, but putting that aside:
There's a convenience callback for .each() in jQuery, which accepts incremented (current) index and reference to element.
Depending on the DOM structure, you could do:
$('td', '#mytable').each(function(ix, tdel){
$(tdel).attr('id', 'td-' + ix).text(ix); // or $(this).attr...
});
...and see where it takes you to.

Multiply td values

I have a html table that looks like this...
<table>
<tr>
<th>Date</th>
<th>Pair</th>
<th>Game</th>
<th>Chance</th>
</tr>
<tr>
<td>2014-2-12</td>
<td>Milan-Udinese</td>
<td>1</td>
<td>1.6</td>
</tr>
<tr>
<td>2014-2-13</td>
<td>Juventus-Inter</td>
<td>x</td>
<td>2.5</td>
</tr>
<tr>
<td>2014-2-13</td>
<td>Arsenal-Liverpul</td>
<td>2</td>
<td>2.5</td>
</tr>
</table>
<p>Total number is:MULTIPLICATION OF ALL CHANCE COLUMN TD</p>
all my rows are added dynamically,how do i multiply all chance column td values(numbers)?Do i have to put certain class on chance tds and then get all tds with that class,and loop through and multiply every value then?I'm kinda a newbie so any help would be appreciated.
You can either do something like this:
var tots = 1;
$('tr td:nth-child(4)').each(function(){
tots *= $(this).text();
});
the nth-child(4) is selecting the fourth td in each row, if you want another, just change that number.
or you can give the cells you want to multiple classes, like you said.
example here
If you're using jQuery, the :last-child selector could be helpful.
<p>Total number is: <span id="result"></span></p>
Javascript:
res = 1;
$("tr td:last-child").each(function() {
res *= parseFloat($(this).html());
});
$("#result").html(res);
Have a look to this JSFiddle.
You don't need jQuery to do this. querySelectorAll supports nth-child selector as well.
var derp = document.querySelectorAll("tr td:nth-child(4)");
var total = 1;
var results = [].reduce.call(derp, function (prev, next) {
return prev * ( + next.textContent );
});
Grab the element, and use native Array prototype methods ([]) to iterate the NodeList and return the parsed value of the element, then return the multiplied total.
Here is a fiddle for you.
$(function () {
var chanceTotals = 1;
$("tr td:nth-child(4)").each(function () {
chanceTotals *= parseFloat($(this).html());
});
$("#totals").html("Total number is: " + chanceTotals);
});
Using jQuery, this executes an anonymous function when the document is ready that will do the calculation for you.
You will need to add the id totals to your p element in order for this to work.
Look at this JSFiddle
You really do not need jquery at all to do this. Interacting with the DOM directly may make you write more (browser support), but it can be more efficient than using jQuery (Unnecessary overhead).
As you can see, I restructured your <table>. I could have just grabbed the <tbody> and looped over its children and skipped the whole if <TD> ? check.
DEMO
$(document).ready(function () {
var table = $('#myTable').get(0);
var multiplier = 1;
var col = 3;
for (var row = 0; row < 4; row++) {
var cell = table.rows[row].cells[col];
if (cell.nodeName == 'TD') {
var text = cell.innerText || cell.textContent;
multiplier *= parseFloat(text);
}
}
$('#multiplier').text(multiplier);
});
<table id="myTable">
<thead>
<tr>
<th>Date</th>
<th>Pair</th>
<th>Game</th>
<th>Chance</th>
</tr>
</thead>
<tbody>
<tr>
<td>2014-2-12</td>
<td>Milan-Udinese</td>
<td>1</td>
<td>1.6</td>
</tr>
<tr>
<td>2014-2-13</td>
<td>Juventus-Inter</td>
<td>x</td>
<td>2.5</td>
</tr>
<tr>
<td>2014-2-13</td>
<td>Arsenal-Liverpul</td>
<td>2</td>
<td>2.5</td>
</tr>
</tbody>
</table>
<p>Total number is:
<span id="multiplier">MULTIPLICATION OF ALL CHANCE COLUMN TD</span>
</p>

Categories