Ok this is my first stab at creating a jQuery plugin so I am going off tutorials currently.
This far I have
(function($)
{
$.tippedOff = function(selector, settings)
{
var config = {
'top':0,
'left':0,
'wait':3000
};
if(settings){$.extend(config, settings);}
var $elem = $(selector);
if($elem.length > 0)
{
$elem.each(function()
{
$(this).css({"color":"#F00"});
})
}
return this;
};
})(jQuery);
Which works for changing the text color of the provided elements. However. I want to add functionality to elements that the plugin takes effect on. Such as a hover or click event. But I can't wrap my head around that idea at the moment, seeing as the selector can be anything. So its not like I can hardcode something in per say thats specific like I would through normal jQuery methods.
So, with that, how do I go about adding that type of functionality to things after its been rendered?
When creating plugins, it is very easy to over-complicate things, so try to keep things nice and simple.
I have provided you with TWO examples of the tippedOff plugin. Here is also a jsfiddle demo of both plugins.
The first uses your original code as is (NO SIGNIFICANT CHANGES MADE):
$.tippedOff = function(selector, settings)
{
var config = {
'top':0,
'left':0,
'wait':3000
};
if(settings){$.extend(config, settings);}
var $elem = $(selector);
if($elem.length > 0)
{
$elem.each(function()
{
//bind mouseenter, mouseleave, click event
$(this).css({"color":"#F00"})
.mouseenter(function(){
$(this).css({"color":"green"});
})
.mouseleave(function(){
$(this).css({"color":"#F00"});
})
.click(function(){
$(this).html('clicked');
});
})
}
return this;
};
This one, however, is based on your original code. Basically, I have reconstructed your original code using these tips. This is how I would personally go about it. I have also provided you with a breakdown below of changes made. (SIGNIFICANT CHANGES MADE):
$.fn.tippedOff = function(settings) {
var config = $.extend( {
'top':0,
'left':0,
'wait':3000,
'color': 'orange',
'hoverColor': 'blue'
}, settings);
return this.each(function() {
$this = $(this);
$this.css({ 'color': config.color})
.mouseenter(function(){
$this.css({ 'color': config.hoverColor });
})
.mouseleave(function(){
$this.css({ 'color': config.color });
})
.click(function(){
$this.html('clicked');
});
});
}
----------------------------------------
Breakdown:
Original Code:
$.tippedOff = function(selector, settings) {
Changed:
$.fn.tippedOff = function( settings ) {
Comments:
The difference between $.tippedOff and $.fn.tippedOff is huge! Adding your plugin to the $.fn namespace rather than the $ namespace will prevent you from having to provide a selector and makes life simplier.
I personally like this answer, in which #Chad states:
My rule of thumb I follow is: use $. when it is not DOM related (like ajax), and use $.fn. when it operates on elements grabbed with a selector (like DOM/XML elements).
Original Code:
if(settings){$.extend(config, settings);}
Changed:
var config = $.extend( {
'top':0,
'left':0,
'wait':3000
}, settings);
Comments:
Having an if statement is redundant. .extend() does all the work for you.
Original Code:
var $elem = $(selector);
if($elem.length > 0)
{
$elem.each(function()
{
$(this).css({"color":"#F00"});
})
}
return this;
Changed:
return this.each(function() {
$this = $(this);
$this.css({ 'color': config.color});
});
Comments:
Using return this.each(function(){}) is good practice and maintains chainability. Not only that, you will no longer need to worry about the selector's length.
*NOTE: If you want to add additional events, then use different methods within your plugin: jQuery Doc Reference - Authoring Plugins.
I hope this helps and please let me know if you have any questions!
I have not enough reputation points to comment and fully agree with Dom, who is very knowledgeable. I only would like to add that within the changed code it would be better to create a local variable by using the var keyword:
var $this = $(this);
This will make the plugin better and allows you to apply the plugin to multiple elements one the page as for example:
$('#testX').tippedOff2();
$('#testY').tippedOff2();
$('#testZ').tippedOff2();
Related
I am new to writing JQuery Plugins...and have a question regarding returning the selector used to bind the plugin to.
Lets say we attach a jQuery plugin to an element like this...
$(".someClass").viEdit();
And this is the Plugin ...
(function ($) {
$.fn.viEdit = function () {
var myTarget = "????"; // See Below
};
}(jQuery));
Now...How can I retrieve the target that was used to bind the jQuery?
I don't mean $(this), I'm looking for .someClass in this case.
As a second example, if it was set like this...
$("#myElement").viEdit();
I would be looking for...
#myElement
Any help would be greatly appreciated!
You can use this.selector:
http://jsfiddle.net/3NAwD/
(function ($) {
$.fn.viEdit = function () {
console.log(this.selector);
};
}(jQuery));
Note that something like $(document.getElementById('someId')).viEdit(); will give you a blank selector.
There were a .selector property, which is deprecated in newer versions.
The advised method now is to pass it as a option like
(function ($) {
$.fn.viEdit = function (options) {
var myTarget = options.target;
};
}(jQuery));
$("#myElement").viEdit({
target: '#myElement'
});
i was trying to organize my jquery code so i created an object literal, but now the focusTextArea is not working and my textarea value is not updating.
Thanks for your help.
html
<textarea id="test"></textarea>
javascript
(function($,window,document,undefined){
var TEX = {
inputField: $("textarea#test"),
/* Init all functions */
init: function()
{
this.focusTextArea();
},
/* Function update textarea */
focusTextArea: function()
{
this.inputField.text('test');
},
}
$(document).ready(function(){
TEX.init();
});
})(jQuery,window,document);
jsfiddle
http://jsfiddle.net/vBvZ8/1/
First of all, you haven't included jQuery correctly in the fiddle. Also, I think you mean to place the code in the head of the document (because of the document.ready handler).
More importantly perhaps the selector $("textarea#test") is run before the document is ready and therefore won't actually find the element correctly. I would recommend assigning inputField in TEX.init:
(function($,window,document,undefined){
var TEX = {
/* Init all functions */
init: function()
{
this.inputField = $("#test");
this.focusTextArea();
},
/* Function update textarea */
focusTextArea: function()
{
this.inputField.text('test');
},
}
$(document).ready(function(){
TEX.init();
});
})(jQuery,window,document);
Updated example: http://jsfiddle.net/xntA2/1/
As a side note, textarea#test should be changed to just #test. The textarea bit is superfluous since there should be only one element on the page with id=test.
Alternative syntax to avoid looking for an element before it exists is to return the element from a function:
(function($,window,document,undefined){
var TEX = {
/* function won't look for element until called*/
inputField:function(){
return $("textarea#test")
},
init: function()
{
this.focusTextArea();
},
focusTextArea: function()
{
this.inputField().text('test');
},
}
$(document).ready(function(){
TEX.init();
});
})(jQuery,window,document);
DEMO: http://jsfiddle.net/vBvZ8/5/
I realize this is a simplified example...but you are also very close to creating a jQuery plugin and that may also be of benefit. Following provides same functionality as example:
(function($, window, document, undefined) {
$.fn.focusTextArea = function() {
return this.each(function(){
$(this).text('test');
})
};
})(jQuery, window, document);
$(function() {
$('textarea').focusTextArea()
});
DEMO: http://jsfiddle.net/vBvZ8/8/
I just started writing Plugins for jQuery. I found a good tutorial how to start with it, but one point I missed. I want register a independent plugin-object for each element and I need them events.
Here the code I got atm:
(function($){
var MyPlugin = function(pElement, pOptions)
{
var element = $(pElement);
var object = pElement;
var settings = $.extend({
param: 'defaultValue'
}, pOptions || {});
this.onfocus = function() {
element.val('Focus');
};
this.onblur = function() {
element.val('Blur');
}
// DO I NEED THIS?
object.onfocus = this.onfocus;
object.onblur = this.onblur;
};
$.fn.myplugin = function(options)
{
return this.each(function()
{
var element = $(this);
if (element.data('myplugin')) { return };
var myplugin = new MyPlugin(this, options);
element.data('myplugin', myplugin);
});
};
})(jQuery);
Do I need to copy my public methods "onfocus" and "onblur" from "this" to "object"? Is there a better way?
The best guide for writing jQuery plugins is probably jQuery's own.
jQuery's event system is the best way of handling events for your plugin. If you're using jQuery 1.7+ (which I recommend, if it's possible), .on() and .off() are your workhorses. Not only can you bind browser events like focus and blur, you can create completely custom events like 'iamasuperstar' and trigger them manually with this.trigger( 'iamasuperstar' ).
So you'd do something like this for your plugin:
element.on( 'focus', function() {} )
element.on( 'blur', function() {} )
...and whatever else you need.
Why not:
object.onfocus = function() {
element.val('Focus');
};
object.onblur = function() {
element.val('Blur');
}
Im making a drag and drop system with mootools drag.move class, but i need all the draggable and droppable elements to have some extra variables and maybe add in a function or two. Ive researched on how to do this using .implement but Ive got no idea how to fit that into my code:
window.addEvent('domready', function(){
$$('#draggables DIV').makeDraggable({
droppables: $$('#droppables DIV'),
onEnter: function(draggable, droppable){
droppable.setStyle('background', 'orange');
droppable.setStyle('opacity', '0.4');
snap_left = droppable.getStyle('left');
snap_top = droppable.getStyle('top');
document.getElementById("slot").innerHTML=droppable.id;
},
onLeave: function(draggable, droppable){
droppable.setStyle('background', null);
},
onDrop: function(draggable, droppable){
if (droppable){
droppable.setStyle('background', '');
draggable.setStyle('left', snap_left );
draggable.setStyle('top', snap_top );
} else {
draggable.setStyle('left', snap_left );
draggable.setStyle('top', snap_top );
}
}
});
});
Is what I want posible using .implement?
Can I add these things to all draggable and droppable elements?
ty in advance!
-Thaiscorpion
edit:
Ive tried adding options directly to the main class in the mootools library and tried accesing them from the onEnter event like this:
onEnter: function(draggable, droppable){
if (droppable.occupied){ //here is where im tryin to acces it, the default option is set to occupied: true
droppable.setStyle('background', 'red');
droppable.setStyle('opacity', '0.4');
document.getElementById("slot").innerHTML=droppable.id;
} else {
droppable.setStyle('background', 'orange');
droppable.setStyle('opacity', '0.4');
snap_left = droppable.getStyle('left');
snap_top = droppable.getStyle('top');
document.getElementById("slot").innerHTML=droppable.id;
}
},
but not getting anything to work.
you can use element storage.
draggable.store("occupied", true);
....
if (draggable.retrieve("occupied") === true) {
}
.... functions or anything can be stored per element
element.store("somekey", function() {
element.toggleClass("foo");
});
element.retrieve("somekey").call(element);
and so forth.
to use Implement:
Element.implement({
dragfoo: function() {
this.set("drag", { });
return this;
}
});
// allows you:
$("someid").dragfoo();
though if you need storage, use storage and dont store properties on the actual element. mootools storage really uses an object hash table that's behind a closure. having proprietary element attributes/properties in IE can slow things down considerably in element access.
I have already implemented some AJAX pagination in my Rails app by using the example code for the will_paginate plugin--which is apparently using Prototype.
But if I wanted to switch to using jQuery for future additions, I really don't want to have the Prototype stuff sitting around too (yes, I know it's possible). I haven't written a lick of JavaScript in years, let alone looked into Prototype and jQuery... so I could use some help converting this bit into jQuery-compatible syntax:
document.observe("dom:loaded", function() {
// the element in which we will observe all clicks and capture
// ones originating from pagination links
var container = $(document.body)
if (container) {
var img = new Image
img.src = '/images/spinner.gif'
function createSpinner() {
return new Element('img', { src: img.src, 'class': 'spinner' })
}
container.observe('click', function(e) {
var el = e.element()
if (el.match('.pagination a')) {
el.up('.pagination').insert(createSpinner())
new Ajax.Request(el.href, { method: 'get' })
e.stop()
}
})
}
})
Thanks in advance!
Edit: Nick Craver's answer got me 90% of the way there, so I just had to pick up enough jQuery to make the HTML element substitution. In place of the line where Nick had $.get($(this).attr("href"));, put this line:
$.get(this.href, null, function(data){ $(this).html(data); }, 'html');
You can shorten this down a bit in jQuery to:
$(function() {
$('.pagination a').live('click', function(e) {
$(this).parent('.pagination')
.append("<img src='/images/spinner.gif' class='spinner' />");
$.get($(this).attr("href"));
return false;
});
});
I'm not entirely sure about new Ajax.Request(el.href, { method: 'get' }) though, is this a script being requested? It looks like nothing's being done with the content after return.