Jump to content
Larry Ullman's Book Forums

I Need Your Help


Recommended Posts

Hi,

 

I started reading the chapter about Ajax (JavaScript and XML), but I wanted to learn little more about XML so I am also reading w3schools.com.

 

There are good examples and tutorials, but I don't like some things such as using inline event handlers.

 

Anyway, I wanted to create the following application:

 

 

jq2p03.jpg

 

 

My English is not good, but I'll try to explain how this application should work (there are two very similar examples on w3schools, and this example is a combination of these two. Also, I am not using inline event handlers and JavaScript is in external .js files, not in the HTML file)

 

 

First of all, we have one XML file that looks like this:

<CATALOG>
	<CD>
		<TITLE>Hide your heart</TITLE>
		<ARTIST>Bonnie Tyler</ARTIST>
		<COUNTRY>UK</COUNTRY>
		<COMPANY>CBS Records</COMPANY>
		<PRICE>9.90</PRICE>
		<YEAR>1988</YEAR>
	</CD>
	<CD>
		<TITLE>Greatest Hits</TITLE>
		<ARTIST>Dolly Parton</ARTIST>
		<COUNTRY>USA</COUNTRY>
		<COMPANY>RCA</COMPANY>
		<PRICE>9.90</PRICE>
		<YEAR>1982</YEAR>
	</CD>
	<CD>
		<TITLE>Still got the blues</TITLE>
		<ARTIST>Gary Moore</ARTIST>
		<COUNTRY>UK</COUNTRY>
		<COMPANY>Virgin records</COMPANY>
		<PRICE>10.20</PRICE>
		<YEAR>1990</YEAR>
	</CD>
	<CD>
		<TITLE>One night only</TITLE>
		<ARTIST>Bee Gees</ARTIST>
		<COUNTRY>UK</COUNTRY>
		<COMPANY>Polydor</COMPANY>
		<PRICE>10.90</PRICE>
		<YEAR>1998</YEAR>
	</CD>
</CATALOG>

This is the HTML file:

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>XML Aplikacija - Katalog</title>
	</head>
	<body>
		<div id="showCD"></div>
		<br>
		<input id="previous" type="button" value="<<" />
		<input id="next" type="button" value=">>" />
		<br><br>
		<div id="tabela"></div>
		<script src="js/ajax.js"></script>
		<script src="js/xmlAplikacija.js"></script>
	</body>
</html>

We have two buttons for navigation between the CDs (next and previous). For example, when you click on ">>" (next) - above (inside of <div id="showCD"></div>) will show some information (Artist, Title, Year) about the CD.

 

Also, there is <div id="tabela"></div> - inside this will be displayed a table containing information about Artist and Title for ALL CDs  from XML (see picture above).

 

There is one more thing - when you click on some row in that table - above the buttons, also inside of <div id="showCD"></div> need to show information about the CD (Artist, Title, Year) (same as with buttons, but instead of changing to the Next/Previous CD - you directly choose from a table by clicking on a row).

 

 

 

So, let's see JavaScript:

 

First, we have a standard ajax.js:

function getXMLHttpRequestObject() {
	var ajax = null;
	if (window.XMLHttpRequest) {
		ajax = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		ajax = new ActiveXObject('MSXML2.XMLHTTP.3.0');
	}
	return ajax;
}

Then we have xmlAplikacija.js:

window.onload = function() {
	
	var xmlhttp = getXMLHttpRequestObject();
	var xmlDoc = null;
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4) {
			if ((xmlhttp.status >= 200 && xmlhttp.status < 300) || (xmlhttp.status == 304)) {
				xmlDoc = xmlhttp.responseXML;
				
				x = xmlDoc.getElementsByTagName("CD");
				i = 0;
	
				function displayCD(i) {
					artist = (x[i].getElementsByTagName('ARTIST')[0].childNodes[0].nodeValue);
					title = (x[i].getElementsByTagName('TITLE')[0].childNodes[0].nodeValue);
					year = (x[i].getElementsByTagName('YEAR')[0].childNodes[0].nodeValue);
					txt = "Artist: " + artist + "<br>Title: " + title + "<br>Year: " + year;
					document.getElementById('showCD').innerHTML = txt;
				};
				
				displayCD(i);
				
				document.getElementById('previous').onclick = function() {
					if (i > 0) {
						i--;
						displayCD(i);
					}
				};
				
				document.getElementById('next').onclick = function() {
					if (i < x.length - 1) {
						i++;
						displayCD(i);
					}
				};
				
				var tbl = "<table border='1'>";
				for (var b=0; b < x.length; b++) {
					tbl += "<tr onclick='displayCD(" + b + ")'>";
					tbl += "<td>";
					tbl += x[b].getElementsByTagName("ARTIST")[0].childNodes[0].nodeValue;
					tbl += "</td><td>";
					tbl += x[b].getElementsByTagName('TITLE')[0].childNodes[0].nodeValue;
					tbl += "</td></tr>";
				};
				tbl += "</table>";
				document.getElementById('tabela').innerHTML = tbl;
				
			} else {
				alert('Doslo je do greske');
			}
		}
	};
	xmlhttp.open('GET', 'resources/xmlFajl.xml', true);
	xmlhttp.send(null);	
};

Everything works fine:

 

jq2p03.jpg

 

when I click on the buttons - it changes to the next/previous CD, there is a table with all CD-s.

 

BUT, I don't know how to make it work - to change (show) CD when you click on a row. For example, when you click on "Dolly Parton" in that table - above should show (also inside of <div id="showCD"></div>) information about the CD (Artist, Title, Year) (same as with buttons, but instead of changing to the Next/Previous CD - you directly choose from a table by clicking on a row - as I have already explaine).

 

On w3schools they wre using inline event handlers, and, as you can see in the code above - I've tried that:

				var tbl = "<table border='1'>";
				for (var b=0; b < x.length; b++) {
					tbl += "<tr onclick='displayCD(" + b + ")'>";
					tbl += "<td>";
					tbl += x[b].getElementsByTagName("ARTIST")[0].childNodes[0].nodeValue;
					tbl += "</td><td>";
					tbl += x[b].getElementsByTagName('TITLE')[0].childNodes[0].nodeValue;
					tbl += "</td></tr>";
				};
				tbl += "</table>";
				document.getElementById('tabela').innerHTML = tbl;

but without success, it doesn't work.

 

Do you have any idea how this could work?

 

Thanks in advance!

Link to comment
Share on other sites

I'm tempted to critique your HTML and JS, but aside from that, one thing I would strongly recommend is using JSON instead of XML.

XML does have some advantages over JSON, but nowadays, JSON is pretty much the default standard, especially when you're consuming data on the JS side.

 

To answer your question though, after outputting the table markup to the DOM, I would add an onclick event handler to all of the tr elements in the table. From there, you can determine which tr was clicked on, and display the appropriate CD data accordingly.

  • Upvote 1
Link to comment
Share on other sites

  • 2 weeks later...

I'm tempted to critique your HTML and JS, but aside from that, one thing I would strongly recommend is using JSON instead of XML.

XML does have some advantages over JSON, but nowadays, JSON is pretty much the default standard, especially when you're consuming data on the JS side.

 

To answer your question though, after outputting the table markup to the DOM, I would add an onclick event handler to all of the tr elements in the table. From there, you can determine which tr was clicked on, and display the appropriate CD data accordingly.

 

First of all, I apologize for the delay in my reply. Now I'm trying to make it work, but without success and I give up. Some things work, but - as you noticed - HTML/JS code is very bad. As for the using of JSON instead of XML - now I will start reading/learning JSON :)

 

Thanks!

Link to comment
Share on other sites

QuakeLive, I don't mind offering you more pointed guidance/help/code, but if I do, I feel the need to pretty much rewrite all of your code. if you're okay with that and you still want more help, please let me know.

Thanks.

Thank you HartleySan! I would be grateful if you could help me to "fix" this, but, of course, this isn't urgent - when you have the will and some time :)

Link to comment
Share on other sites

Okay, I will do my best to provide a simple implementation of what you want to do as well as a satisfactory explanation.

 

First off, as we discussed, you shouldn't use XML for your data structure. Certainly, I can understand you wanting to learn how to handle XML, but the truth is, JSON is used for almost every JS data model these days. Once you get more comfortable with JS and JSON, then learning how to handle XML at a later time is trivial.

As such, I'm going to use JSON for my data model.

 

To keep my example simple, I'm going to code for modern browsers (i.e., my code will not work on old IE browsers). However, if you like my code, you can always extend it as you please to fit your requirements. More than anything, I'm providing this code as a learning tool, so I don't want to get caught up in things like handling browser differences, etc.

 

Now, with all of that said, your requirements seem to be as follows:

  1. You have a data set that is a collection of CDs and metadata associated with those CDs. This data set will be in JSON format.
  2. You want to display a table that lists all the CDs and their associated artists.
  3. You want to make it possible to click on a row in the table to display more info about that CD.
  4. You want to have left and right arrows that allow you to move up and down through the table accordingly.
 

To start with, I'd use this HTML:

 



<!DOCTYPE html>

<html lang="en">
  
  <head>
    
    <meta charset="UTF-8">
    
    <title>CDs and their details</title>
    
    <style>
    
    </style>
    
  </head>
  
  <body>
    
    <div id="cd_details">
    
    </div>
    
    <button type="button" id="prev"><<</button>
    
    <button type="button" id="next">>></button>
    
    <div id="cds">
    
    </div>
    
    <script>
    
    </script>
    
  </body>
  
</html>


 

A couple things to note about my HTML vs. your HTML:

  1. I don't use <br> tags. You should never use these to create vertical space between elements. That's what CSS margins and padding are for.
  2. Don't use input elements outside of form elements. Simple button elements will suffice (and button elements are actually easier to consistently style across browsers).
 

Now, for this example, I will put all the JS within the script tags at the bottom of the HTML, but you can just as easily put it in a separate JS file and link to that JS file from your HTML file.

 

To start with, all the JSON data is formatted as follows and in a file called data.json:

 



{
  "cds": [
    {
      "title": "Hide Your Heart",
      "artist": "Bonnie Tyler",
      "country": "UK",
      "company": "CBS Records",
      "price": 9.90,
      "year": 1988
    },
    {
      "title": "Greatest Hits",
      "artist": "Dolly Parton",
      "country": "USA",
      "company": "RCA",
      "price": 9.90,
      "year": 1982
    },
    {
      "title": "Still Got the Blues",
      "artist": "Gary Moore",
      "country": "UK",
      "company": "Virgin records",
      "price": 10.20,
      "year": 1990
    },
    {
      "title": "One Night Only",
      "artist": "Bee Gees",
      "country": "UK",
      "company": "Polydor",
      "price": 10.90,
      "year": 1998
    }
  ]
}


 

As you can see, the format is very similar to the XML file, but less character data is required, and it's (I think) easier to quickly read and comprehend. As a side note, I properly capitalized the album names.

 

Now that we have our data, the first thing we want to do is load it into our JS so it's accessible from there.

To do this, we will use Ajax to load the data.json file data as string data, and then convert it to a JS object as follows:

 



    <script>
      
      var xhr = new XMLHttpRequest();
      
      xhr.open('get', 'data.json');
      
      xhr.onreadystatechange = function () {
        
        if (xhr.readyState === 4) {
          
          var data = JSON.parse(xhr.responseText);
          
          console.log('data', data);
          
        }
        
      };
      
      xhr.send(null);
      
    </script>


 

Here, we are create a new Ajax object, then using the GET method to open data.json. When the readyState property of the Ajax object is 4 (we don't need to worry about the status property for opening local files), then we take the string data stored in xhr.responseText (which is equivalent to all the data in the data.json file), and convert that JSON string into a JS object by running JSON.parse on it.

 

At this point, all of our JSON data is accessible as a JS object in the data variable. I am console-logging the data object so that you can easily view the data structure and confirm that everything is there from your browser console.

 

Once we have the data, we want to use it to render the table of CD metadata. We'll do this by calling a function called render, which we are defining as shown below:

 



    <script>
      
      var xhr = new XMLHttpRequest();
      
      xhr.open('get', 'data.json');
      
      xhr.onreadystatechange = function () {
        
        if (xhr.readyState === 4) {
          
          var data = JSON.parse(xhr.responseText);
          
          console.log('data', data);
          
          render(data);
          
        }
        
      };
      
      xhr.send(null);
      
      function render(data) {
        
        var html = '<table><tbody>',
          i,
          len,
          cds = data.cds;
        
        for (i = 0, len = cds.length; i < len; i += 1) {
          
          html += '<tr id="row_' + i + '"><td>' + cds[i].artist + '</td><td>' + cds[i].title + '</td></tr>';
          
        }
        
        html += '</tbody></table>';
        
        document.getElementById('cds').innerHTML = html;
        
      }
      
    </script>


 

The render function simply creates all the markup needed for the table, and then uses the inenrHTML property to spit it out to the screen.

One thing worth noting is the ID assigned to the tr elements. This will allow us to quickly find the corresponding data in our data object when a table row is clicked.

 

Next, we want to set up our three types of events (left arrow click, right arrow click and table row click). We can do this as follows:

 



    <script>
      
      var xhr = new XMLHttpRequest(),
        currentCd = 0;
      
      xhr.open('get', 'data.json');
      
      xhr.onreadystatechange = function () {
        
        if (xhr.readyState === 4) {
          
          var data = JSON.parse(xhr.responseText);
          
          console.log('data', data);
          
          render(data);
          
          setEvts(data);
          
        }
        
      };
      
      xhr.send(null);
      
      function render(data) {
        
        var html = '<table><tbody>',
          i,
          len,
          cds = data.cds;
        
        for (i = 0, len = cds.length; i < len; i += 1) {
          
          html += '<tr id="row_' + i + '"><td>' + cds[i].artist + '</td><td>' + cds[i].title + '</td></tr>';
          
        }
        
        html += '</tbody></table>';
        
        document.getElementById('cds').innerHTML = html;
        
      }
      
      function setEvts(data) {
        
        var cds = data.cds,
          numCds = cds.length,
          html,
          trs = document.getElementsByTagName('tr'),
          i,
          len;
        
        document.getElementById('prev').onclick = function () {
          
          currentCd = (currentCd - 1 + numCds) % numCds;
          
          html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].years + '</li></ul>';
          
          document.getElementById('cd_details').innerHTML = html;
          
        };
        
        document.getElementById('next').onclick = function () {
          
          currentCd = (currentCd + 1 + numCds) % numCds;
          
          html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].years + '</li></ul>';
          
          document.getElementById('cd_details').innerHTML = html;
          
        };
        
        for (i = 0, len = trs.length; i < len; i += 1) {
          
          trs[i].onclick = function () {
            
            currentCd = parseInt(this.id.split('_')[1], 10);
            
            html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].years + '</li></ul>';
            
            document.getElementById('cd_details').innerHTML = html;
            
          };
          
        }
        
      }
      
    </script>


 

The setEvts function sets up the three types of onclick events we can have. The prev and next button handlers are very similar, with the only difference being the fact that we're subtracting 1 from the globally accessible currentCd variable as opposed to adding 1.

While perhaps somewhat confusing, the expression (currentCd +/- 1 + numCds) % numCds is an easy way to increment/decrement a value and cause it to loop around when you try to subtract 1 from the lowest limit or add 1 to the highest limit. I recommend trying a few examples in your head to confirm that this does indeed work.

 

Once we have the currentCd number, we create another string of HTML markup for the details area, and then output that string to the corresponding div via the innerHTML property again.

 

For the tr elements in the table, the only added complexity beyond the arrows is the fact that there are likely more than one tr element, meaning that we have to use getElementsByTagName and loop through each tr element, setting up an onclick event handler for each one.

 

The logic for the tr event handlers is very similar to the prev/next buttons though in that we are getting the current CD number, and rendering from there.

In the case of the tr elements though, we want to parse the id attribute by splitting the value on the underscore, and then taking the string number that comes after the underscore and turning it into an actual integer.

 

Anyway, that should get you what you want.

One thing I want to make very clear is that my JS above is far from ideal. However, I wrote it that way to keep it as simple as possible for the sake of highlighting how to solve the problem at hand.

It actually would be a good JS challenge to go back and try to make my code better.

 

Well, I hope that answers your questions.

Please play around with the code and let me know if you have any other questions.

Thanks.

  • Upvote 2
Link to comment
Share on other sites

Thank you very much HartleySan!!!
 
 
 
I tested your code and it works perfectly!
 
Right now, I'm making version with external .js files. After that, I'll try to make some CSS, for example - row for the current CD will have a different color... : )
 
I must say that I knew that code from my post is bad - but I didn't know why exactly... After seeing your code and explanations, it's clear now.
 
There are a few interesting things regarding your code:
 

currentCd = (currentCd - 1 + numCds) % numCds;

I must say that I never would have thought to do it this way. Very clever : )
 
The best way to understand this is to do a few examples, for example:
 
Lets say that the number of CDs are 5, and that the currently selected CD is third (currentCd  = 2):
 

numCds = 5

currentCd  = 2

 

To get the previous CD:
 

(2 - 1 + 5) % 5  ---> 6 % 5 = 1 // which is the second CD

 

If the current CD is 0:
 

(0 - 1 + 5) % 5 --->4 % 5 = 4 // which is the fifth CD

 
 
There is one small mistake when typing, instead of cds[currentCd].years it should be cds[currentCd].year:
 

html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].year + '</li></ul>';
          

 
 
:)
 
 
This is also very interesting:
 

	for (i = 0, len = trs.length; i < len; i++) {
		trs[i].onclick = function() {
			currentCd = parseInt(this.id.split('_')[1], 10);
			html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].year + '</li></ul>';
			document.getElementById('cd_details').innerHTML = html;
		};
	}	

 
First of all, I was thinking to do it in a completely different (*stupid) way... This way is elegant and short.
 
As for this line:
 

currentCd = parseInt(this.id.split('_')[1], 10);

 
this.id - this is the value of id attribute of a row trs - but I'm not sure if I understood well this. "this" refers to an element on which onclick event happened, right? Why does not work this way:
 

currentCd = parseInt(trs.id.split('_')[1], 10);

 
?
 
Again, thank you very much HartleySan!!!

Link to comment
Share on other sites

You're welcome.

Also, thanks for spotting my years/year error.

 

To answer your question about "this", yes, "this" refers to the element that was clicked on.

"this" provides a convenient way to refer to a particular element when the same event handler is set up for multiple elements at once.

I would definitely get used to using "this", as it's very useful.

One warning though is that the meaning (i.e., the value) of "this" can sometimes change on you unexpectedly as contexts change. This can lead to seemingly illogical things happening, so be careful.

 

As for why trs doesn't work within the anonymous function assigned to the tr onclick event handlers, you've stumbled upon the classic gotcha in JavaScript: closures.

 

JavaScript works a lot differently than most classical (in the sense that they have classes) OOP languages like C++ and Java.

Unlike those languages, in JS, you can define functions within functions. What's more, a function within another function can inherit the scope of the outer function, which means that the inner function can access all the variables declared in the outer function. (A bit confusing at first, I know.)

 

Anyway, in the code above, the anonymous function being assigned to the tr.onclick event handlers is within the setEvts function, meaning that the anonymous function has access to all of the variables within the setEvts function, including trs and i.

Normally, after the setEvts function ends, the trs and i variables are deleted from memory. However, if you use them within your anonymous function assigned to the onclick event handler, then the JS engine is required to retain those variables in memory even after the setEvts function ends. It has to do this because any time a table row is clicked on, the JS engine has to be able to reference the values stored in trs and i for the onclick event handler.

 

Now, the tricky part has to do with the value of i. You would think that the value of i within the anonymous function would be equal to the value of i at the time the anonymous function is assigned to the onclick event handler. However, it's not.

After the for loop is executed, the value of i is equal to the length of the trs array. For example, if there are five elements in trs, then i is equal to 5. This is the value that is retained in i when a tr element is clicked on. This happens because the anonymous function assigned to the onclick event handler is not called when the page is first loaded and the script is executed, but asynchronously at a later time when a tr element is clicked on; and at that later time, i is equal to the length of the trs array, as defined by our for loop logic.

As such, if you use trs within the onclick event handler function, then you're really saying trs[5], which doesn't actually exist, thus causing an error.

 

There are ways to get around this seemingly illogical behavior in JS (I assure you though, there is logic to why JS does this), but generally, just using "this" is a better solution.

If you're curious though, one thing you can do is turn your anonymous function into a self-invoking function, which retains scope at a particular point in time, and then return a function reference from the self-invoking function. This is a bit tricky, but the following code would work:

trs[i].onclick = (function (i) {
  
  return function () {
    
    currentCd = parseInt(trs[i].id.split('_')[1], 10);
    
    html = '<ul><li>Artist: ' + cds[currentCd].artist + '</li><li>Title: ' + cds[currentCd].title + '</li><li>Year: ' + cds[currentCd].years + '</li></ul>';
    
    document.getElementById('cd_details').innerHTML = html;
    
  };
  
}(i));
  • Upvote 1
Link to comment
Share on other sites

Now, the tricky part has to do with the value of i. You would think that the value of i within the anonymous function would be equal to the value of i at the time the anonymous function is assigned to the onclick event handler. However, it's not.

After the for loop is executed, the value of i is equal to the length of the trs array. For example, if there are five elements in trs, then i is equal to 5. This is the value that is retained in i when a tr element is clicked on. This happens because the anonymous function assigned to the onclick event handler is not called when the page is first loaded and the script is executed, but asynchronously at a later time when a tr element is clicked on; and at that later time, i is equal to the length of the trs array, as defined by our for loop logic.

As such, if you use trs within the onclick event handler function, then you're really saying trs[5], which doesn't actually exist, thus causing an error.

 

This explains it! I have to think more, I have no concentration! :) Thank you so much Hartley!

Link to comment
Share on other sites

Don't be too hard on yourself. The gotcha you stumbled across has fooled many people, many times.

If you already understand it though, that's great.

 

I think the problem is not to understand, but to apply knowledge. In many cases, when I read this JS book or some JS tutorial - I can understand but when I want to apply knowledge and create something new and original - I just stuck, block... Of course, the key is to practice and gain experience. There are those who argue that programming should be learned "only through hundreds of examples and exercises, not through reading "fat books"... they claim that reading those books is a waste of time... But I personally do not believe in such stories, or I just don't have the capacity to learn in that way.

Link to comment
Share on other sites

Yes, I agree that the hardest step in programming is to go from copying examples in books to actually applying that knowledge.

I remember that that took a while for me as well. Once you get there though, it's very satisfying and worthwhile.

All I can really say is that if you keep at it, you'll get there. Certainly, it can be grueling at times, but that's the way it is with anything, I think.

 

As for practicing with lots of examples vs. reading books, I think I'm in the middle, with perhaps more of an emphasis on doing rather than reading. Certainly though, everyone has their own way of learning.

Just personally, when I approach something new, I like to read just a little bit to get me started, and after that, I like to run with it for a while, trying different things, and then once I have the basics down, I like to go back and read a lot more to better educate myself and learn the details.

  • Upvote 1
Link to comment
Share on other sites

Yes, I agree that the hardest step in programming is to go from copying examples in books to actually applying that knowledge.

I remember that that took a while for me as well. Once you get there though, it's very satisfying and worthwhile.

All I can really say is that if you keep at it, you'll get there. Certainly, it can be grueling at times, but that's the way it is with anything, I think.

 

As for practicing with lots of examples vs. reading books, I think I'm in the middle, with perhaps more of an emphasis on doing rather than reading. Certainly though, everyone has their own way of learning.

Just personally, when I approach something new, I like to read just a little bit to get me started, and after that, I like to run with it for a while, trying different things, and then once I have the basics down, I like to go back and read a lot more to better educate myself and learn the details.

 

I am learning very slowly, I have a feeling it will take me 100...00 years  to read the books, to practice, to do the examples... Just now (today), I found this interesting video

 

 

:)

Link to comment
Share on other sites

  • 2 months later...

 

Now, the tricky part has to do with the value of i. You would think that the value of i within the anonymous function would be equal to the value of i at the time the anonymous function is assigned to the onclick event handler. However, it's not.

After the for loop is executed, the value of i is equal to the length of the trs array. For example, if there are five elements in trs, then i is equal to 5. This is the value that is retained in i when a tr element is clicked on. This happens because the anonymous function assigned to the onclick event handler is not called when the page is first loaded and the script is executed, but asynchronously at a later time when a tr element is clicked on; and at that later time, i is equal to the length of the trs array, as defined by our for loop logic.

As such, if you use trs within the onclick event handler function, then you're really saying trs[5], which doesn't actually exist, thus causing an error.

This explains it! I have to think more, I have no concentration!  Thank you so much Hartley!

Now I'm reading the chapter about Closures which is at the end of the book, where this is also explained :)

Link to comment
Share on other sites

 Share

×
×
  • Create New...