On event, call function with arguments

I have a function looping through a list.
This loop adds a function (openTrack) to the onclick event:

function clicktrack(){
  var amounttracks = document.getElementById("tracks").getElementsByTagName("li");

  amounttracks[i].onclick = openTrack(i);


The openTrack function is the following:

function openTrack(x){

var arrayWords = ['site','point', 'test'];

var words = document.getElementById("words");

   return function (e) {
	words.innerHTML = arrayWords[x];

However. Can’t it be made more easy, without returning that nested function(e) ?

Couldn’t your openTrack function have the for loop (maybe pass the amounttracks variable?) and hten just return it once to clicktrack?

Semi JS noob though so I might be off base.

Hmm, no.
I don’t want to return a function again.

I need just a dynamic function getting one variable (i) passed to it.
Can’t this openTrack function not just read that variable immediately without needing to return function(e) ?

It could be done by making arrayWords and words global variables, but that’s a very poor way of programming these days.

JavaScript is a functional language, and nesting functions to enjoy the benefits of what is called closure (which is the nesting of execution environments) is commonplace.

However, yes we can remove the returned function. Here’s how.

arrayWords and the words variable can be made global variables

arrayWords = ['site','point', 'test'];
words = document.getElementById("words");

This puts them at higher risk of being accidentally clobbered, and also allows users on the page to fiddle about with them too.

That leaves us with:

function openTrack(x) {
    words.innerHTML = arrayWords[x];
amounttracks[i].onclick = openTrack(i);

But there’s a problem. If we execute the function right away, we will only have a return value from the function that’s assigned to the onclick event. So, we need to just assign the function to the onclick event instead.

The onclick event cannot pass values to the function, so the function will have to get the number from somewhere else. About the only useful place let at this stage is to store the number on the element that you’re tracking.

function openTrack(evt) {
    var element = this;
    var x = element.openTrackIndex;
    words.innerHTML = arrayWords[x];
for (i = 0; i < amounttracks.length; i += 1) {
  amounttracks[i].openTrackIndex = i;
  amounttracks[i].onclick = openTrack;

This does result in making globally available the index value too, which is at risk of being clobbered or fiddled about with by anyone that happens to be looking.

So yes - it can be done without the nested function, but what you end up with is something that is a whole lot worse.

JavaScript is a functional language. Instead of staying with what you may be used to, it can help to learn more about the features of the language that you’re programming with.

1 Like

That code runs openTrack straight away and adds what is returned as the code to be run when the event handler is triggered. if you just wrapped the openTrack(i) call inside an anonymous function then you can get openTrack to run when the event is triggered instead of straight away but it will run with the value that i has when it is triggered rather than the value it has at the time the event handler is created.

The simplest way to attach the event handler so that the function runs at the time it is triggered using the value of i at the time the handler is assigned is to use ‘bind’ (which changes the value of this within the function but as you are not using it that doesn’t matter but as a side effect also binds the value of i at the time the bind runs rather than at the time opentrack runs).'.

amounttracks[i].onclick = openTrack.bind(this,i);

The more traditional way is to use a closure to capture the value of i at the time of adding the handler but that involves a bit more code to achieve the same result.

Hmm, cool.
Didn’t know about all that.
It’s already a long time ago since I’m doing some little javascript again.

I’m not really up to date about that kind of hacking methods so users can fiddle with these variables. Is there any reference guide on internet or this website where I can find more tricks to secure these gaps?

I put the array (arrayWords) and the reference to the html element (words) inside the function openTrack, so they aren’t global anymore.
Maybe I’ll have to nest the openTrack function inside the clickTrack function, so it’s more secure? Or doesn’t that matter?

It’s actually not for a website that people will want to hack, it’s for one page where some content needs to change by JS, by clicking some links.
(It’s hosting without PHP, otherwise I would include it with php on a more secure way)

Anyway, I’m learning every day, searched the whole intarwebs yesterday for tutorials, nothing suited what I was looking for, until I came to these forums again. This corner should be the first point to visit before browsing the internet any further :wink:
The only thing I think is sad is that I so loved the very very early forum layout from a few years ago. But that’s my nostalgic side.

That isn’t a hacking method - it is rather basic JavaScript (except that using event handlers is somewhat old style as event listeners are far more flexible).

The standard technique is to place your code inside an immediately invoked function expression (iife) which helps to protect the global namespace from your code and helps to result in a tidier situation.

(function () {
    // code in here

Some good info about this can be found in the online book Eloquent JavaScript. A good place to find info about these techniques is in the Modules section.

1 Like

I can understand that returning a function within a function seems weird at first but it’s one of the best features of the Javascript. The other post mentioned about “closure”. In order to master JavaScript, you need to know at least two things.

  1. Closure
  2. Scope of “this”

Without knowing these, it’s a recipe to write spaghetti code. This is my #1 Javascript book
Creator of JQuery wrote the book.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.