Trying to learn jQuery plugin development - javascript

So I'm trying to learn how to implement method collection for a plugin based on this example: http://docs.jquery.com/Plugins/Authoring
What I cannot understand is how options that are extended with defaults for the plugin get sent to the individual methods.
I'm pretty sure any original options get sent to the method here:
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
So how can you extend these arguments with defaults? The example doesn't really define how to do this...
var methods = {
init : function( options ) {
return this.each(function(){
$(window).bind('resize.tooltip', methods.reposition);
});
}
}
Also, here is the code from the example plugin authoring page:
(function( $ ){
var methods = {
init : function( options ) {
return this.each(function(){
$(window).bind('resize.tooltip', methods.reposition);
});
},
destroy : function( ) {
return this.each(function(){
$(window).unbind('.tooltip');
})
},
reposition : function( ) { // ... },
show : function( ) { // ... },
hide : function( ) { // ... },
update : function( content ) { // ...}
};
$.fn.tooltip = function( method ) {
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.tooltip' );
}
};
})( jQuery );

Looks like my previous answer was closer to the mark than I previously thought.
Yes, this line is passing on the arguments:
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
Using .apply(), you can call a method, change its context (this value), and give it a collection of arguments instead of individual ones. Handy if you don't know how may arguments need to be passed on.
So you can break the above line down like this:
// reference the arguments passed to the plugin
var args = arguments;
// eliminate the first one, since we know that's just the name of the method
args = Array.prototype.slice.call( arguments, 1 )
// call the method that was passed,
// passing along the Array of the arguments (minus the first one),
return methods[method].apply( this, args);
// Note that it is being called from the context of "this" which is the jQuery object
So if the plugin was called like this:
$('.someElem').tooltip('destroy', 'someArg', 'anotherArg' );
The code will locate the "destroy" method, slice "destroy" off of the Arguments object, and call "destroy" passing along the Array of remaining arguments.

you use $.extend(existingObject || {} (new object), oneObject, secondObject, nthObject)
var mydefaults = { myDefaultArg : "foo" }
var inputOptions = { myDefaultArg : "Somethin else" }
var options = $.extend({}, mydefaults, inputOptions);
options.myDefaultArg == "Somethin else";
To access data, or to save them,you can use the data method
so if you are in the plugin, "this" is the jquery element element, you can now save data into it.
$(this).data("pluginname.somedataname", data);
and retriev it
var data = $(this).data("pluginname.somedataname");

Related

Difference between .queue() and jquery.queue()

Might be a silly question, but I am confused between .queue() used with .dequeue() and $.queue() OR jquery.queue().
Are they the same, if so why jquery provided them in 2 separate documentations? Can, someone explain their ussage differences along with appropriate examples ?
https://api.jquery.com/queue/
http://api.jquery.com/jquery.queue/
.queue() is used as a method of the jQuery element.
It has only one parameter "queueName"
$("div:first").queue("fx")
Whereas jquery.queue() is a standalone function that will accept DOM element as it's first parameter and second for name of the queue.
jQuery.queue($("div:first")[0], "fx" );
Both works same, just the approach is different.
As said at http://api.jquery.com/jquery.queue/
Note: This is a low-level method, you should probably use .queue() instead.
Internally $(selector).queue() and $(selector).dequeue() use $.queue() and $.dequeue() respectively.
This is the code for $(selector).queue() and $(selector).dequeue() jQuery 2.1.3:
jQuery.fn.extend({
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
if ( arguments.length < setter ) {
return jQuery.queue( this[0], type );
}
return data === undefined ?
this :
this.each(function() {
var queue = jQuery.queue( this, type, data ); // <-- HERE!
// Ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type ); // <-- HERE!
}
});
},
dequeue: function( type ) {
return this.each(function() {
jQuery.dequeue( this, type ); // <-- HERE!
});
},
....

jquery plugin that returns a new object

I'm creating my first jQuery plugin and want to create the jQuery object, but want to be able to control the object that was just created...
I'm building my plugin following the format recommended here: http://docs.jquery.com/Plugins/Authoring
Here is my test code:
(function($){
var $this = $(this);
var methods = {
init : function( options ) {
// methods.createDiv();
$this = $('<div>TEST CONTENT</div>')
.attr({ 'id':'test' })
.css({'color':'white','backgroundColor': 'red'})
.appendTo("body");
setTimeout(function(){
methods.green();
},
3000
);
return $this;
},
green : function( ) {
$this.css({'backgroundColor': 'green'});
},
blue : function( ) {
$this.css({'backgroundColor': 'blue'});
}
};
$.fn.myPlugin = function( method ) {
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.tooltip' );
}
};
})( jQuery );
$(document).ready(function () {
var myTest = $.fn.myPlugin();
myTest.blue();
});
Ultimately, I want to be able to control the newly created div using the myTest variable, but it's not working. I'm sure there are obvious pieces I'm missing and mistakes I'm making, but that's why I'm posting here. It's my first plugin, so if anyone could help me get this test code up and running I'd appreciate it. Currently, firebug report: "TypeError: myTest.blue is not a function"
Invoke your method as:
myTest.myPlugin("blue");
Here is a demo: http://jsfiddle.net/5p2Ba/
blue is not a method of the jQuery object here. You are only binding the methods object into a module using a closure.

Method for jQuery plugin

I'm trying to make a jQuery plugin for custom checkboxes and radio buttons.
(function($)
{
$.fn.checkboxRadio = function(options)
{
var defaults = some;
...
return this.each(function()
{
var button = $(this);
...
});
}
})(jQuery);
It can be used now by $('input').checkboxRadio(options);
How do I add a method check without changing current scope, to make a possible usage of something like $('input').checkboxRadio('check')?
How to handle a custom method and get its name inside my plugin?
Here is the official jquery plugin guide.
The part about wrapping functions is found here ("Plugin Methods") (the example is a would-be tooltip plugin) :
(function( $ ){
var methods = {
init : function(options) { ... },
show : function() { ... },
hide : function() { ... },
update : function(content) { ... }
};
$.fn.tooltip = function( method ) {
// Method calling logic
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.tooltip' );
}
};
})(jQuery);
[update] explaining the methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )) line in the guide :
If you call $(selector).tooltip('update', 'hello') from your javascript code, you want to end up calling the update method, passing 'hello' as the content argument, with this set to $(selector) for the duration of the call.
That is what this line takes care of :
if method == 'update', methods[method] is the update method,
arguments will be equal to ['update', 'hello'], you have to drop the first element to get the arguments you want to pass to your method ; this is exactly what Array.prototype.slice.call(arguments, 1) does,
myFunc.apply(obj, argsArray) calls the function myFunc, passing argsArray as the arguments, and setting this to obj for the duration of the call.
So inside your methods, you can call this.each(...) to iterate over all of the selector's items, e.g. :
update: function(content) {
this.each(function(){ $(this).data('tooltip.content', content); });
return this;
}
You can connect plugin methods like this:
(function($) {
$.fn.checkboxRadio = function(options) {
var defaults = {
check: 'check'
}
return this.each(function() {
var o = options;
var _this = $(this);
if( o.check === 'check' ) {
_this.attr('checked','checked');
}else if ( o.check === 'uncheck' ) {
_this.removeAttr('checked');
}
});
}
})(jQuery);
and user document should be like what you want: $('input').checkboxRadio({check:'check'});

Passing jQuery element data between methods?

I'm trying to create my first jQuery plugin, reading jQuery plugin authoring and one of the things it really emphasizes is to use methods instead of namespaces. I'm also trying to use the data from that guide to bounce variables between methods but it's not working. I need to create some data, pass it to another method to update it and send it somewhere else.
(function($) {
var methods = {
init : function(settings) {
return this.each(function(){
var x = 3;
var object = $(this);
// Bind variables to object
$.data(object, 'x', x);
$(object).bbslider('infoParse');
var y = $.data(object,'y');
alert(y);
}); // End object loop
}, // End init
infoParse : function() {
var object = $(this);
var x = $.data(object,'x');
alert(x);
var y = 10;
$.data(object,'y',y);
}, // End infoParse
}; // End method
$.fn.bbslider = function(method) {
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.bbslider' );
}
}; // End slider
})(jQuery);
Here's a jsFiddle to show what I mean: http://jsfiddle.net/wRxsX/3/
How do I pass variables between methods?
see if this http://jsfiddle.net/wRxsX/6/ is ok ?
element.data(k,v)
$.data should use on element
http://api.jquery.com/data/
Store arbitrary data associated with the matched elements or return the value at the named data store for the first element in the set of matched elements.

jQuery .data() and plugins

I am trying to use jQuery's .data() tool in a jQuery plugin but I'm getting some odd results.
Here is a cut down version of my plugin with the relevant code:
(function( $ ){
var methods = {
init : function( options ) {
// Do some stuff
this.data('name', 'New Component');
return this;
},
getStateData : function () {
// Function returns all data for save
var state = new Object;
state.name = this.data('name');
// snip ... Add some other bits to state
// ...
return state;
},
setStateData: function (args) {
var key = args[0];
var value = args[1];
// snip
this.data(key, value);
}
};
$.fn.component7Segment = function(method) {
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.designComponent' );
}
};
})( jQuery );
If I call $(instance-of-plugin).component7Segment('getStateData'); the plugin returns the correct 'name' however if I call setStateData to change the name it has not changed the 'name' value when I next call getStateData.
Doing console.log(this); in each function looks slightly different so I started trying:
$.data($('#object-id'), 'name', value);
This still doesn't have the desired effect.
Can anybody see what I am missing?
Assuming you're calling setStateData like this:
$(instance).component7Segment("setStateData", "name", "Foo");
the setStateData function should be changed to look like this:
setStateData: function () {
var key = arguments[0];
var value = arguments[1];
// snip
this.data(key, value);
}
Note the removal of the args parameter and the use of the special arguments array-like object instead.
Example: http://jsfiddle.net/andrewwhitaker/ShFHC/
Your original problem was most likely that you were calling setStateData with parameters name and "foo". args[0] and args[1] was actually accessing the characters in name at that position instead of the arguments passed to the function.

Categories