Álvaro González
Álvaro González

Reputation: 146390

Use jQuery method as callback parameter

I have this little jQuery plugin:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"><!--
(function($){
    $.fn.foo = function(options){
        var options = $.extend({
            text: "Foo!",
            }, options
        );

        this.prepend(
            $("<span></span>").text(options.text)
        ).css({color: "white", backgroundColor: "black"});

        return this;
    };
})(jQuery);


$(function(){
    $("div").foo().foo({text: "Bar!"}).css({border: "1px solid red"});
});
//--></script>
</head>
<body>

<div>One</div>
<div>Two</div>
<div>Three</div>

</body>
</html>

Now I want to improve it so you are able to control where the text gets inserted by means of providing a callback function:

$(function(){
    var optionsFoo = {
        text: "Foo!",
        insertionCallback: $.append
    }
    var optionsBar = {
        text: "Bar!",
        insertionCallback: $.prepend
    }
    $("div").foo(optionsFoo).foo(optionsBar).css({border: "1px solid red"});
});

(Please remember this is just sample code. I want to learn a technique rather than fix an issue.)

Can I pass a jQuery method as an argument and use it inside the plugin in the middle of a chain? If so, what's the syntax? If not, what's the recommended alternative?

Update: myprogress so far

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"><!--
(function($){
    $.fn.foo = function(options){
        var options = $.extend({
            text: "Foo!",
            insertionCallback: $.append
            }, options
        );

        options.insertionCallback.call(this, // options.insertionCallback is undefined
            $("<span></span>").text(options.text)
        ).css({color: "white", backgroundColor: "black"});

        return this;
    };
})(jQuery);


$(function(){
    var optionsFoo = {
        text: "Foo!",
        insertionCallback: $.append
    }
    var optionsBar = {
        text: "Bar!",
        insertionCallback: $.prepend
    }
    $("div").foo(optionsFoo).foo(optionsBar).css({border: "1px solid red"});
});
//--></script>
</head>
<body>

<div>One</div>
<div>Two</div>
<div>Three</div>

</body>
</html>

Upvotes: 2

Views: 384

Answers (4)

yfeldblum
yfeldblum

Reputation: 65435

Not an answer to your question, but the recommended style is:

<script type="text/javascript">

  //this
  jQuery(function($) {
    //... stuff using the jQuery lib, using the $
  });

  //not this
  $(function() {
    //...
  });

  //or this
  (function($) {
    //...
  })(jQuery);

</script>

Upvotes: 0

Nick Craver
Nick Craver

Reputation: 630379

You can also do this string based to keep it simple, like this:

(function($){
  $.fn.foo = function(options){
    var options = $.extend({
        text: "Foo!",
        insertionCallback: "append"
        }, options
    );
    return this[options.insertionCallback]($("<span></span>").text(options.text))
               .css({color: "white", backgroundColor: "black"});
  };
})(jQuery);

Then your call looks like this:

$(function(){
  var optionsFoo = {
    text: "Foo!",
    insertionCallback: "append"
  }
  var optionsBar = {
    text: "Bar!",
    insertionCallback: "prepend"
  }
  $("div").foo(optionsFoo).foo(optionsBar).css({border: "1px solid red"});
});​

You can test it here, this would allow you to use append, prepend, html and text, giving you a few options to set the content. In this case we're just taking advantage of JavaScript being a dynamic language, where this.prepend(something) is equal to this["prepend"](something).

Upvotes: 1

Luca Matteis
Luca Matteis

Reputation: 29267

Sure you can, JavaScript is really dynamic:

    this.prepend(
        $("<span></span>").text(options.text)
    ).css({color: "white", backgroundColor: "black"});

You can replace the native call to this.prepend() with the jQuery function you pass in the options object as a parameter.

Since most jQuery methods behave on a current set of elements (the this object in your plugin) you need to use apply or call to make it work. This way you can call the options.insertionCallback function with the current this object as its context.

Something like:

    options.insertionCallback.call(this, // pass the current context to the jQuery function
        $("<span></span>").text(options.text)
    ).css({color: "white", backgroundColor: "black"});

Edit

However you can't access jQuery methods directly from the $ namespace, you need a constructed jQuery object to access its methods, or simply use $.fn.functionName as Nick Craver pointed out.

alert($.prepend); // won't alert the function

alert($.fn.prepend); // will alert the function

Upvotes: 1

jAndy
jAndy

Reputation: 235972

extend it like so:

(function($){
    $.fn.foo = function(options){
        var options = $.extend({
            text: "Foo!",
            cb: null
            }, options
        );

        if($.isFunction(options.cb)){
           // optimal also pass parameters for that callback
           options.cb.apply(this, []);
        }

        this.prepend(
            $("<span></span>").text(options.text)
        ).css({color: "white", backgroundColor: "black"});

        return this;
    };
})(jQuery);

I don't really understand what you mean with

Can I pass a jQuery method as an argument and use it inside the plugin in the middle of a chain?

Why would you want to pass a jQuery method ? it's already in there so you can just call it on any jQuery object.

Upvotes: 1

Related Questions