views:

1136

answers:

2

My goal is to be able to call functions that are inside my JQuery plugin.

What is the correct syntax?

For example, this does not work:

<a href="#" id="click_me">Click Me</a>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;
<script>
(function($) { 
    $.fn.foo = function(options) {
     do_stuff = function(){
      console.log("hello world!"); // works
         do_other_stuff = function(){
      alert("who are you?");
      }
     } // function
    } // function
})(jQuery);

$("body").foo();

$("#click_me").click(function(){
$.fn.foo.do_stuff.do_other_stuff(); // doesn't work
});

</script>
+4  A: 

when you assign functions to variables without the var keyword they either overwrite the local variable of that name or the are added to the global namespace. (so your do_stuff is a global function, which is not what you want)

one way to do what you want is to explicitly give where you want your function to reside.

(function($) { 
    $.fn.foo = function(options) {
        // whatever $().foo() should do
    };

    $.fn.foo.do_stuff = function() {
        console.log("hello world!");
    };

    $.fn.foo.do_stuff.do_other_stuff = function(){
        alert("who are you?");
    };
})(jQuery);

Edit:

This works because all functions in javascript are objects, which means you can assign values to any arbitrary property.

If you want to access the variables of other functions you can move the definitions inside of the other ones like:

$.fn.foo.do_stuff = function() {
    console.log("hello world!");
    $.fn.foo.do_stuff.do_other_stuff = function(){
        alert("who are you?");
    };
};

but this will mean the function is only defined once you run the other function, and that each time you run the function it will overwrite the last definition.

Possibly a more ideal solution would be to have each function return an object containing the nested function like so:

(function($) { 
    $.fn.foo = function(options) {
        // whatever $().foo() should do

        var do_stuff = function(do_stuff_args) {
            console.log("hello world!");
            // do stuff with options and do_stuff_args

            var do_other_stuff = function(other_args) {
                alert("who are you?");
                // here you have access to options, do_stuff_args, and other_args
            };

            return {
                do_other_stuff: do_other_stuff
            };
        };

        return {
            do_stuff: do_stuff
        }
    };
})(jQuery);

and call it using

foo().do_stuff(some_options).do_other_stuff(other_options);

or

var a = foo(stuff).do_stuff(some_options);
a.do_other_stuff(foo);
a.do_other_stuff(bar);
cobbal
I really don't get why this works. I thought $.fn.foo could be either a function or an object with the property do_stuff, but in your example it is both. This is possible in JavaScript? Could you give me a pointer to read about this feature? Or do I get something wrong here?
Tim Büthe
Thanks for the example, it works. My plugin is already done. Your example doesn't match the structure of my plugin. In my plugin, "do_stuff" is inside "foo" and "do_other_stuff" is inside "do_stuff". How can I access "do other stuff" using that nested structure? Or, how can I use your example, but let do_stuff access variables from foo (and let do_other_stuff access variables from do_stuff)?
Thanks Cobbal, I figured out how to use your example with my function structure. Works great! I just had to use $.fn.foo.[function_name] for all nested functions, regardless of their level.
A: 

If you want it to work, you need to write : (edit: Sorry, it won't work like that..)

<a href="#" id="click_me">Click Me</a>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;
<script>
(function($) { 
    $.fn.foo = function(options) {
        return do_stuff = function(){
                console.log("hello world!"); // works
            return do_other_stuff = function(){
                alert("who are you?");
                }
        } // function
    } // function
})(jQuery);

$("body").foo();

$("#click_me").click(function(){
$.fn.foo().do_stuff().do_other_stuff(); // doesn't work
});

</script>
Fabien Ménager
When I try the above code and click the link, I get the error: "$.fn.foo().do_stuff is not a function"
Yes, that's why I edited my message to tell you that my solution was not valid :)
Fabien Ménager