JavaScript Events and Scopes


Jordi Boggiano   @seldaek

http://nelm.io/

Events

Listening

ECMAScript in all modern browsers

node.addEventListener("click", function () {
    alert("clicked ECMA");
}, false);
            

IE < 9 Only

node.attachEvent("onclick", function () {
    alert("clicked IE");
});
            

jQuery

$(node).click(function (e) {
    alert("clicked jQuery");
});
$(node).bind("custom", {optional: "dataobj"}, function(){});
            

Namespacing

$(node).bind("click.namespace", function () { alert('clicked'); });

// unbind with e.g.:
$(node).unbind("click.namespace");
// stackable like css classes
$(node).unbind(".stacked.namespaces");
            

Dispatching

Plain JS createEvent

var e = document.createEvent('MouseEvents');
e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

if (node.dispatchEvent(e)) {
    alert("not canceled");
    alert(e.type);
}
            

jQuery

$(node).keyup(function (e, data) {
    alert(e.type);
    alert(data);
});
$(node).keyup();
$(node).trigger("keyup", ['foo']);
$(node).triggerHandler("keyup", ['bar']);
            

Event Phases

Capture

Note: The propagation stops at the event target

Bubbling

Event Delegation

Bubbling Events

Device events: key*, mouse*, click


Non-Bubbling Events

focus, blur, change, submit, ..



Capture them! Fails in IE < 9 though.

Proprietary events (focusin/focusout/..?) that are bubbling are an alternative.

Handling

Receiving the event object

function clickHandler(e) {
    // e = event object
}
            

Stopping the event

$('.red .green', slide).click(function (e) {
    // stops the bubbling process to red*
    e.stopPropagation();
    alert('green');
});

$('.red .yellow', slide).click(function (e) {
    alert('yellow');
});

$('.red', slide).click(function (e) {
    // blocks propagation to red2
    e.stopImmediatePropagation();
    alert('red1');
});
$('.red', slide).click(function (e) {
    alert('red2');
});
            
RED
GREEN
YELLOW

Preventing the default behavior

function clickHandler(e) {
    alert('clicked: '+e.data);
    return false;
}
function clickHandler2(e) {
    alert('clicked: '+e.data);
}
$('a', slide).bind('click', 'link', clickHandler);
$('input', slide).bind('click', 'button', clickHandler2);
$(slide).bind('click', 'slide', clickHandler);
            

Test link

Preventing the default behavior

function clickHandler(e) {
    e.preventDefault();
    alert('blocked: '+e.data);
}
$('a', slide).bind('click', 'link', clickHandler);
$(slide).bind('click', 'slide', clickHandler);
            

Test link

return false;

What is this?

function clickHandler(e) {
    // e.target = node that triggered the event
    alert('target: '+$(e.target).attr('class'));
    // e.currentTarget = node we're listening to
    alert('currentTarget: ' + $(e.currentTarget).attr('class'));
    // this = e.currentTarget
    alert('this: '+$(this).attr('class'));
}
$('.red', slide).click(clickHandler);
            
RED
GREEN

Another approach: Pub/Sub

$.subscribe('new-message', my.ui.showMessage);
$.publish('new-message', ['Hello', 'Lorem ipsum']);
            

Find the plugin on github.

Scoping

Scoping: Basic Closures

var test = 'foo';
function foo() {
    test = 'bar';
    alert(test);
}
foo();
alert(test);
            
var test = 'foo';
function foo() {
    var test = 'bar';
    alert(test);
}
foo();
alert(test);
            

Variable hoisting: scoping issues

var test = 'foo';
function foo() {
    alert(test);
    test = 'bar';
    alert(test);
}
foo();
            
var test = 'foo';
function foo() {
    alert(test);
    var test = 'bar';
    alert(test);
}
foo();
            

Variable hoisting: scoping issues

var test = 'foo';
function foo() {
    alert(test);
    var test = 'bar';
    alert(test);
}
foo();
            

What JS sees:

var test = 'foo';
function foo() {
    var test;
    alert(test);
    test = 'bar';
    alert(test);
}
foo();
            

Variable hoisting: functions

function foo() {
    return 'foo';
}
var foo = 'bar';
alert(foo);
alert(foo());
            

Variable hoisting: functions

function foo() {
    return 'foo';
}
var foo = 'bar';
alert(foo);
alert(foo());
            

What JS sees:

var foo;
foo = function () {
    return 'foo';
}
foo = 'bar';
alert(foo);
alert(foo());
            

Scoping: Adv. Closures (= Lexical Scoping)

var adder = (function () {
    var total, innerFunction;
    total = 0;
    innerFunction = function (number) {
        total += number;
        return total;
    }
    return innerFunction;
}());

alert(adder(2));
alert(adder(2));
alert(total);
            

Closures are great but don't abuse them

var data = 3,
func = function () {
    var subfunction = function () {
        var subfunction = function () {
            alert(data);
        }
        subfunction();
    }
    subfunction();
};
func();
            

Globals are as evil as always, parent lookups are expensives.

References & Links

Thank you.

Questions?

Slides up at slides.seld.be

Feedback please on
http://joind.in/2898