1

I am trying to create a Jquery plugin that maintains chainability and has public methods as specified in Jquery Plugins/Authoring . The complexity is that it is trying to maintain certain vars that I want the public methods to use.

This is my jsfiddle : http://jsfiddle.net/badmash69/9cqcj/2/

javascript code :

(function($){

  var methods = {
    init : function( options ) {
      this.options = options;
    }
  , add_that: function (elem) {

      $(this).append(elem);
      return (this);
    }
  , show_parent: function(){
      // this is a simple test to see if the plugin vars are accessible
      alert("parent id=" + $(this).parentId)
    }              
  , add_this: function (elem) {
      return methods.add_that.apply(this,elem);
    }
  };

  $.fn.test = function (method) { 
        var args = method;
        var argss = Array.prototype.slice.call(args, 1);      


      return this.each(function(){

          var $this = $(this);
          if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' + method + ' does not exist on jQuery.test' );
    }          


          var element = $(this);
          var parentId= element.parent().attr("id")

      });       


  };

})(jQuery);

$('#test').test('add_this',$('<div>Hello World d</div>'));

$('#test').test('show_parent');
​

Html Code

<div id="holder">
<div id="test"></div>
</div>  

I cant figure out what I am doping wrong here . How can I make it work ? I would deeply appreciate any help .

4

2 回答 2

1

the way that I do this is using the $.data, you can have specific object local vars, "public"/"private" methods, etc. here goes an small example in how I will do it

(function($){
      var myTestMethods = function() {
          // local variables
          var last_added;

          // local "private" methods 
          var init=function(options) {
              this.options = options;
              last_added = null;
              return this;
          };

          var add_that=function(elem) {
              last_added = elem;
              this.append(elem);
              return this;
          };

          var show_parent=function() {
              alert("parent id=" + this.parent().attr('id'));
          }

          return { // this are your obj "public" methods
                 // notice we are not listing add_that method, therefore this method will be a "private" method
            init : init,
            show_parent: show_parent, // you can publish a private method
            get_last_added: function(){
              return last_added; // you can access local variables
            }, 
            add_this: function (elem) {
              return add_that.apply(this, elem);  // you can also run local methods
            }
          }
      };

      $.fn.test = function (method) {
          var obj_data = this.data('myTestData');
        if (typeof(obj_data) != "undefined") {
          if ( obj_data[method] ) {
            return obj_data[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
          }else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.test' );
          }
        } else {
          if (typeof(method) === 'object' || ! method) {
            obj_data = myTestMethods();
            this.data('myTestData', obj_data);
            return obj_data.init.apply(this, arguments);
          }
        }
      };

    })(jQuery);

    $('#test').test(); //init

    $('#test').test('add_this',$('<div>Hello World d</div>'));
    $('#test').test('show_parent');

this code has small tests so there may be small bugs, but this will show you the basic idea in how to do what you want.

于 2012-11-21T22:12:07.403 回答
0

Take a look at this demo: http://jsfiddle.net/9cqcj/11/

As they suggest, to keep data you should better use .data:

      return this.each(function(){          
          var $this = $(this);
          $this.data("parentId",$this.parent().attr("id"));
....

(assuming that you need parentId of each element in set)

Also, you have a problem with calling your methods:

 return this.each(function(){

          var $this = $(this);
          if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));

Last line, arguments - arguments of function passed to .each is used. In order to get original arguments save them into variable before calling a method:

$.fn.test = function (method) { 
        var args = arguments;      
      return this.each(function(){          
          var $this = $(this);
          $this.data("parentId",$this.parent().attr("id"));
          if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( args , 1 ));

See arguments replaced with args in last line.

Also, when you are using .apply, second parameter should be an array:

return methods.add_that.apply(this, [elem]);

In case like this:

return methods.add_that.apply(this, elem);

You can get unexpected problems. For instance, try to replace elem with simple string "test" and see what you will get in console. Or if you will pass jQuery object, you will get DOM object in called method

于 2012-11-21T22:15:20.897 回答