Reputation: 43
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!
Upvotes: 1
Views: 196
Reputation: 183
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.
Upvotes: 1