Passing an jQuery element cache to a method for modification

379 views Asked by At

Problem Fiddle:

Click To View (Attempt #1, using Delegated Events)

Click To View (Attempt #2, brute force approach as below)

Click To View (Attempt #3, refactored, has problem I am trying to solve)

On a project I'm working with, I'm exploring a rather dynamic form. In addition to some static elements, there are various interactive elements, which can be cloned from a hidden 'template' markup set and added at various points in the business process.

Because of the dynamic nature, my tried-and-true method of setting up a jQuery element cache and event handlers on-load, then letting the user do whatever isn't working out, because of this dynamic nature; I was finding that my dynamically-added elements had no click events.

To solve this problem, I manually set up a rebind method for each scripted element in question. The rebind process involves A) re-acquiring the set of elements for a given descriptive selector, B) dropping any existing events on that cache, as those events apply to an incomplete element set, and C) calling a bind method to apply the new events to the entire set.

The brute-force, working way that I got, had this going on:

var $elementCache = $('.some-class');

function rebindSomeLink() {
    // Re-acquire the element cache...
    $elementCache = $('.some-class');

    // Drop all existing events on the cache...
    $elementCache.unbind();

    // Call a bind function to establish new events.
    bindSomeLink();
}

function bindSomeLink() {
    $elementCache.click(function (e) {
        // ...Behavior...
    });
}

// There are four other links with a similar rebind/bind function relationship set up.

Naturally, I seized on the rebind being repeated so often with nearly the exact same code - ripe for a refactor. We have a common library namespace, where I added a rebindEvents function...

var MyCommon = function () {
    var pub = {};

    pub.rebindEvents = function($elementCache, selector, bindFunction) {
        $elementCache = $(selector);
        $elementCache.unbind();
        bindFunction();
    };

    return pub;
}();

Upon trying to call that, and run the site, I immediately stubbed my toe on an UncaughtTypeError: method click cannot be called on object undefined.

As it turns out, it seems when I call the following:

MyCommon.rebindEvents($elementCache, '.some-class', bindSomeLink);

The $elementCache is not being passed to the rebindEvents method; when I step to it in my debugger, $elementCache inside of rebindEvents is undefined.

Some handy StackOverflow research revealed to me that JavaScript does not have referential-passing, at least in the C/C++/C# sense that I am familiar with, which leads me to my two Questions:

A) Is it even possible for me to refactor this rebind functionality with a cache reference pass of some sort?

B) If it's possible for me to refactor my rebind function to my common namespace, how would I go about doing it?

1

There are 1 answers

4
Geoff On BEST ANSWER

Use Jquery On to bind events at an element high-up in the DOM that is always present. http://api.jquery.com/on/

This is the simplest way to handle event binding to dynamically created elements.

here is a jsfiddle that shows an example.

$('#temp').on('click', 'button', function(){
   alert('clicked'); 
});

$('#temp').append('<button>OK</button>');

The event is bound to a div, which later has a button dynamically added. Because the button has no click event, the event "bubbles" up the DOM tree to its parent element which does have a click event for a button, so it handles it and the event "bubbles" no further.