Programming Concept onEvent

This is a sample that I wrote. I am curious about how and why it works
Sample Partial TicTacToe

I expect the onEvent to be called only when it is written outside a function. In the sample provided, the onEvent is embedded in a function checkIfTaken() that is called. Does this mean the event handler is registered and ready to accept events as long as the program is running once the function is called? I think this is incorrect program code.

var player = "O";
checkIfTaken("b11");
checkIfTaken("b12");
checkIfTaken("b13");
checkIfTaken("b21");
checkIfTaken("b22");
checkIfTaken("b23");
checkIfTaken("b31");
checkIfTaken("b32");
checkIfTaken("b33");

// WHY DOES THIS WORK
function checkIfTaken(choice){
  onEvent(choice, "click", function(event) {
    console.log(choice + " is clicked!");
    if(player == "X")
      setProperty(choice, "image","icon://fa-times");
    else
      setProperty(choice, "image","icon://fa-circle-thin");
    checkWin(player);
  });
}

Hello Maya,

Here are two forum threads that have discussions about onEvents and how they work. Hope this helps.


There is no reason why you can’t do this. The simple answer to your question “Does this mean the event handler is registered and ready to accept events as long as the program is running once the function is called?” is yes.

If the 9 squares in the game are represented by buttons and given the ids b11, b12, etc. then what you have done is added an event handler to each button without duplicating the code 9 times. The event handler is straight forward in that it sets the button to be an x or an o. This is a clever way to avoid all the repeated code, but there is a better way. But first, let me answer your second question “WHY DOES THIS WORK”.

The way it works is called a closure. The function checkIfTaken is a function and as such has its own environment in which choice is declared and assigned a value of “b11”, or “b12”, etc. When the statement onEvent is called it creates an unnamed function in that environment. That function uses the variable choice whose value is the id of one of the 9 buttons. That unnamed function then becomes the callback function for the button with id equal to the value of choice. When clicked that function is called.

The closure part is that since the callback function was defined inside an environment where choice was declared and given a value equal to the button’s id it will continue to have that value. setProperty(choice, "image","icon://fa-times"); will set the image property of the button that is pressed because the callback function uses the environment created for checkIfTaken and in that environment choice is set to the button id that is the button whose callback this function is. This is an advanced Javascript topic not covered by CSP.

This is also not covered in CS A because Java doesn’t have closures. Javascript is based on the language Scheme which is based on the language LISP which does have closures.

So how could you do this without creating closures? Use the button id from the event object. The callback function is given an object as a parameter. That object is called an event and has all kinds of information including the id of the button that was pressed. You just need to understand that onEvent needs a function for the callback and you don’t have to create a fresh function every time. Hence:

var player = "O";
onEvent("b11", "click", squareChosen);
onEvent("b12", "click", squareChosen);
onEvent("b13", "click", squareChosen);
onEvent("b21", "click", squareChosen);
onEvent("b22", "click", squareChosen);
onEvent("b23", "click", squareChosen);
onEvent("b31", "click", squareChosen);
onEvent("b32", "click", squareChosen);
onEvent("b33", "click", squareChosen);

function squareChosen(event){
  var choice = event.currentTargetId;
  console.log(choice + " is clicked!");
  if(player == "X")
    setProperty(choice, "image","icon://fa-times");
  else
    setProperty(choice, "image","icon://fa-circle-thin");
  checkWin(player);
}

will also work without duplicating the callback function code 9 times.

1 Like

@bhatnagars Thank you for the links. Now I have to figure how to discourage my hackers from using this code pattern. To them if it is not causing a warning or error, it works! :crazy_face: :smile:

Thank you for your explanation. Your example was proof enough on the right way to use/write the callback function. I was able to share the correct approach with my students.