Sunday, February 10, 2019

5.6 Binding Events

The one really nice thing about classes is that they are a nice way of grouping data with the code that manipulates that data. This leads to a very common situation in programming where you want to do something with the data when an event happens. Event-driven programming is where the behavior of a program is structured around events instead of sequences and is the way you typicality approach user-interface related tasks. Combing objects with events seems like a no-brainer but this is where JavaScript starts showing some strangeness. To understand lets write a simple event.

// General function for printing to the web page so results can be seen
// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s

}

// The timeout method uses a callback which gets called asyncronously
function tickTest(){
printTestLine("Tick Test was called!")
}
setTimeout(tickTest, 1500);

Timing events in JavaScript can be controlled by using a timeout. SetTimeout simply takes a function and a duration in milliseconds which are thousandths of a second. After the duration has expired it will call the function. Note that the timer is not precise and that the delay can be more than the specified amount bur for general usage timeouts are adequate. Running the above would result in a second-and-a-half delay before something was printed.

Now lets write a simple class that will store a value and when a function is called will display that value back.

// A simple class that stores a value and can display the currently stored value when asked to.function Demo() {
this.setValue = function(n) {
this.storedValue = n;
}

this.displayValue = function() {
printTestLine("Stored value is " + this.storedValue);
}

this.displayWithMessage = function(s) {
var str = "NO MESSAGE PROVIDED ";
if (s !== undefined)
str = s;
printTestLine(str + this.storedValue);
}
}

// as this shows, the class works as expected
var demo = new Demo();
demo.setValue(42);
demo.displayValue();
demo.displayWithMessage("Custom message before value ");

This works just fine so using it as part of an event seems trivial but lets try that.

// however, the value does not seem to exist if used as a callback.
setTimeout(demo.displayValue, 2000);
\end{lstlisting}
}

After a couple of seconds delay we get a rather interesting result. This is a byproduct of the way JavaScript calls methods within a function and is something that we will discuss in detail next fortnight. Obviously, this means that we can't use events with classes. But, as this is an obvious necessity, there is a bind function that browsers provide to solve this problem. By simply adding the bind function to the end of the function you are calling you will be able to specify which class the event is for. The function takes the instance of a class to use as it's parameter and does not need to be the calling instance but I can't think of any situation where I wouldn't want to use the same instance.

// this is where binding comes in
setTimeout(demo.displayValue.bind(demo), 2500);

// Binding also helps with parameters.
setTimeout(demo.displayWithMessage.bind(demo), 3000);
setTimeout(demo.displayWithMessage.bind(demo, "Message added in Binding "), 3000);

As can be seen from the demo code, binding can also be used to add additional parameters to a callback function. When dealing with situations such as having multiple buttons being handled by the same logic, this is an incredibly convenient feature of the bind function. But what exactly is the bind function doing? Tune in next fortnight to find out!

No comments: