2

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>

4 Answers 4

1

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
Sign up to request clarification or add additional context in comments.

4 Comments

Could you please elaborate your example a little more? I cannot grasp the exact syntax. I get options.insertionCallback is undefined no matter what I do.
@Álvaro G. Vicario: That's because $.prepend (or $.append) is undefined. I elaborated a bit more in the answer.
You can access the methods directly, $.fn.prepend ;)
That did the trick in my sample code: use $.fn.prepend to set and options.insertionCallback.call(this,...) to call. I understand the callback execution must normally start the method chain if previous methods change the element selection but it's a reasonable drawback. Nick's string trick is also neat.
1

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.

1 Comment

What I mean is being able to do this inside the plugin: this.insertionCallback($("<span></span>").text(options.text) ).css({color: "white", backgroundColor: "black"});
1

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).

Comments

0

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>

2 Comments

The last one is the "Custom Alias in plugin code" described at docs.jquery.com/Plugins/Authoring#Custom_Alias but I take note of the alias in page code, which I was not aware of.
Right, this is for page code. Plugin code should always use the last style example instead of the first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.