jQuery, closures, objects, instances, suicide

CPR

Do you have a fantastic grasp of jQuery and closures and would like to help me out?

I’m stumped on how to keep a settings array alive through the life-cycle of a jQuery plugin I’m working on, and I can’t find any answers on the Google or the Internet.

Want to help me? Please reply to this entry. I’ll continue slitting my wrists with the dull edge that is javascript until you do…

Update
After a couple of suggestions on plugin architecture, I’m still no further ahead. I’ve put together a summary of my problem. Check out the following code:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-ca">
<head>
    <title>test</title>
    <script src="/garden/js/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
<!--

(function($) {
    var opts;

    $.fn.identify = function(options) {
        opts = $.extend({}, $.fn.identify.settings, options);
           
        this.click(function() {
            $.fn.identify.speak();
            return false;
        });
           
        return this;
    }
       
    $.fn.identify.speak = function() {
        alert(opts.parameter);
    }

    $.fn.identify.settings = { parameter: 'default' };

})(jQuery);

jQuery(document).ready(function($) {
   $('a:first').identify({parameter:'first'});
   $('a:last').identify({parameter:'last'});
});


// -->
</script>
<body>
<a href="http://localhost/garden/test.php">http://localhost/garden/test.php</a>
<br /><br /><br />
<a href="http://localhost/garden/test.php">http://localhost/garden/test.php</a>
</body>
</html>

If you create this example and then click the first link, your popup will say “last” even though the parameter that was passed to the anchor was “first”. Simply put: I need it to say “first”.

If I change my javascript slightly, I can make it say first like so:

(function($) {
    $.fn.identify = function(options) {
        var opts = $.extend({}, $.fn.identify.settings, options);
      
        this.click(function() {
            alert(opts.parameter);
            return false;
        });
          
        return this;
    }

    $.fn.identify.settings = { parameter: 'default' };
})(jQuery);

jQuery(document).ready(function($) {
   $('a:first').identify({parameter:'first'});
   $('a:last').identify({parameter:'last'});
});

But the whole problem is that I need to be able to call a *different* function (like the “speak” one above) within the plugin and access the correct parameter. The only way that I have been able to do this successfully is by doing something like this:

(function($) {
    $.fn.identify = function(options) {
        var opts = $.extend({}, $.fn.identify.settings, options);
       
        this.click(function() {
            $.fn.identify.speak(opts);
            return false;
        });
           
        return this;
    }
       
    $.fn.identify.speak = function(opts) {
        alert(opts.parameter);
    }

    $.fn.identify.settings = { parameter: 'default' };
})(jQuery);

jQuery(document).ready(function($) {
   $('a:first').identify({parameter:'first'});
   $('a:last').identify({parameter:'last'});
});

This doesn’t really work for me because I can’t guarantee that opts will be able to get passed into my function if, say, I’m using a callback function that can’t take any parameters.

So, the bottom line: How can I save the parameters specific to the correct instance so that they are properly accessible from an outside function?

Any ideas?

Update #2

Dinoboff suggested that I use jQuery’s data() method to store and retrieve the settings. However, his code didn’t work for me. To get it to work, I had to do this:

(function($) {
    $.fn.identify = function(options) {
        this.data('identify_settings', $.extend({}, $.fn.identify.settings, options));
		
        this.click(function(e) {
            $.fn.identify.speak(e);
            return false;
        });
		
        return this;
    }

    $.fn.identify.speak = function(e) {
        var settings = $.extend({}, $.fn.identify.settings, jQuery.data(e.target, 'identify_settings'));
        alert(settings.parameter);
    }

    $.fn.identify.settings = { parameter: 'default' };

})(jQuery);

Which basically tells me that the source of the problem is that there is no way for the outside function to know what sent it unless you pass in a reference. The click event on the affected element knows what was sent via “this” and/or event arguments.

Unless someone comes up with something different, I’m left thinking that there is no way to do this.

Update #3

Thanks to everyone for their input. In the end I decided to go about it by passing in my settings wherever necessary. I also wanted to be able to programmatically call my identify method, so in the end I went with this type of thing:

(function($) {
    $.identify = function(options) {
        var settings = $.extend({}, $.identify.settings, options);
        $.identify.speak(settings);
    }

    $.fn.identify = function(options) {
        var settings = $.extend({}, $.identify.settings, options);
		
        this.click(function() {
            $.identify.speak(settings);
            return false;
        });
		
        return this;
    }
	
    $.identify.speak = function(settings) {
        alert(settings.parameter);
    }

    $.identify.settings = { parameter: 'default' };
})(jQuery);

jQuery(document).ready(function($) {
    jQuery.identify({parameter:'programmatically set'});
    $('a:first').identify({parameter:'first'});
    $('a:last').identify({parameter:'last'});
});

The page loads and alerts “programmatically set”. Clicking the first link alerts “first”, and clicking the last link alerts “last”.