Function calls inside jQuery plugin - javascript

I've nearly this code for defining the plugin instance:
$.fn.someplugin = function(opts) {
$(document).on('click', '.option-1', function() {
alert(1);
});
};
I use some code like this one to make my plugin work:
$('.selector-1').someplugin();
So jQuery in this way binds likely one click event listener to the document.
The question is, when I use my plugin multiple times, does it mean that jQuery binds 10 click events to the document?
$('.selector-1').someplugin();
$('.selector-2').someplugin();
$('.selector-3').someplugin();
$('.selector-4').someplugin();
$('.selector-5').someplugin();
$('.selector-6').someplugin();
$('.selector-7').someplugin();
$('.selector-8').someplugin();
$('.selector-9').someplugin();
$('.selector-10').someplugin();
In this way it binds 10 click listeners - because fn.someplugin is called 10 times, or just one?

Yes, it binds 10 click listeners to the $(document) object.
Every time you call someplugin() it will bind a new listener.
JSFIDDLE
If you want to add a single click handler to the document (inside of your plugin) you can do this:
(function ($) {
$.fn.someplugin = function(opts) {
alert("Another someplugin call.");
};
$(document).on('click', '.option-1', function() {
alert(1);
});
})($);
JSFIDDLE

You can do this to bind only one time :
(function ($) {
$.fn.someplugin = function (opts) {
return $(this).each(function (index, value) {
$(document)
.off('click', '.option-1')
.on('click', '.option-1', function (event) {
event.preventDefault();
alert(1);
});
});
};
})(jQuery);
$(document).ready(function () {
$('.selector-1, .selector-2').someplugin();
});
$(this).each allows you to bind multiple selectors.
.off() unbinds the event if it exists.
jsfiddle : http://jsfiddle.net/rWYS4/

Related

jquery mouseenter and mouseleve is not working on newly injected dom elements

I have the following code. It works fine but when i add new elements into the dom it does't show or hide it.
jQuery("div.cat-icon").on({
mouseenter: function () {
jQuery(this).find('.catselect').show();
},
mouseleave: function () {
jQuery(this).find('.catselect').hide();
}
});
Please advice.
Dynamically added elements require delegated event handlers :
jQuery(document).on({
mouseenter: function () {
jQuery(this).find('.catselect').show();
},
mouseleave: function () {
jQuery(this).find('.catselect').hide();
}
}, "div.cat-icon");
You need to use event delegation for dynamically added elements, for which the syntax is
jQuery(document).on({
mouseenter: function () {
jQuery(this).find('.catselect').show();
},
mouseleave: function () {
jQuery(this).find('.catselect').hide();
}
}, "div.cat-icon");
In event delegation model, you need to bind the handler to an already existing element and then pass the target element selector as the second argument to on

Binding a function that is already bound to another element

I have a bunch of elements that get three different classes: neutral, markedV and markedX. When a user clicks one of these elements, the classes toggle once: neutral -> markedV -> markedX -> neutral. Every click will switch the class and execute a function.
$(document).ready(function(){
$(".neutral").click(function markV(event) {
alert("Good!");
$(this).addClass("markedV").removeClass("neutral");
$(this).unbind("click");
$(this).click(markX(event));
});
$(".markedV").click(function markX(event) {
alert("Bad!");
$(this).addClass("markedX").removeClass("markedV");
$(this).unbind("click");
$(this).click(neutral(event));
});
$(".markedX").click(function neutral(event) {
alert("Ok!");
$(this).addClass("neutral").removeClass("markedX");
$(this).unbind("click");
$(this).click(markV(event));
});
});
But obviously this doesn't work. I think I have three obstacles:
How to properly bind the changing element to the already defined function, sometimes before it's actually defined?
How to make sure to pass the event to the newly bound function [I guess it's NOT accomplished by sending 'event' to the function like in markX(event)]
The whole thing looks repetitive, the only thing that's changing is the alert action (Though each function will act differently, not necessarily alert). Is there a more elegant solution to this?
There's no need to constantly bind and unbind the event handler.
You should have one handler for all these options:
$(document).ready(function() {
var classes = ['neutral', 'markedV', 'markedX'],
methods = {
neutral: function (e) { alert('Good!') },
markedV: function (e) { alert('Bad!') },
markedX: function (e) { alert('Ok!') },
};
$( '.' + classes.join(',.') ).click(function (e) {
var $this = $(this);
$.each(classes, function (i, v) {
if ( $this.hasClass(v) ) {
methods[v].call(this, e);
$this.removeClass(v).addClass( classes[i + 1] || classes[0] );
return false;
}
});
});
});
Here's the fiddle: http://jsfiddle.net/m3CyX/
For such cases you need to attach the event to a higher parent and Delegate the event .
Remember that events are attached to the Elements and not to the classes.
Try this approach
$(document).ready(function () {
$(document).on('click', function (e) {
var $target = e.target;
if ($target.hasClass('markedV')) {
alert("Good!");
$target.addClass("markedV").removeClass("neutral");
} else if ($target.hasClass('markedV')) {
alert("Bad!");
$target.addClass("markedX").removeClass("markedV");
} else if ($target.hasClass('markedX')) {
alert("Ok!");
$target.addClass("neutral").removeClass("markedX");
}
});
});
OR as #Bergi Suggested
$(document).ready(function () {
$(document).on('click', 'markedV',function (e) {
alert("Good!");
$(this).addClass("markedV").removeClass("neutral");
});
$(document).on('click', 'markedX',function (e) {
alert("Bad!");
$(this).addClass("markedX").removeClass("markedV");
});
$(document).on('click', 'neutral',function (e) {
alert("Ok!");
$(this).addClass("neutral").removeClass("markedX");
});
});
Here document can be replaced with any static parent container..
How to properly bind the changing element to the already defined function, sometimes before it's actually defined?
You don't bind elements to functions, you bind handler functions to events on elements. You can't use a function before it is defined (yet you might use a function above the location in the code where it was declared - called "hoisting").
How to make sure to pass the event to the newly bound function [I guess it's NOT accomplished by sending 'event' to the function like in markX(event)]
That is what happens implicitly when the handler is called. You only need to pass the function - do not call it! Yet your problem is that you cannot access the named function expressions from outside.
The whole thing looks repetitive, the only thing that's changing is the alert action (Though each function will act differently, not necessarily alert). Is there a more elegant solution to this?
Yes. Use only one handler, and decide dynamically what to do in the current state. Do not steadily bind and unbind handlers. Or use event delegation.

Toggling Classes Voids the Event function?

I thought this would work, but whenever I click on the element with the class name of one and it changes to the class named two, I can't get the second event to work. What am I missing here?
//first event
$('.one').on('click', function () {
$('.one').attr('class', 'two');
});
//second event
$('.two').on('click', function () {
$('.two').attr('class', 'one');
});
You need to delegate the event to a static parent..
The problem is , because you seem to dynamically change the class you need to bind the event every single time you change the class.. So delegating it should remove this problem..
Also You can write this as a Single event..
$('body').on('click','.one' , '.two', function() {
if( $(this).hasClass('one'){
function1();
}
else if( $(this).hasClass('two'){
function2();
}
$(this).toggleClass('one two');
});
Why not more simple :) http://jsfiddle.net/XZeNE/1/ or this http://jsfiddle.net/4mJJe/
use API - toggleClass
Further HTML CHange Dmeo http://jsfiddle.net/vuLQK/1/
code
$('.one').on('click', function() {
$(this).toggleClass('two');
});​
HTML change
$('.one').on('click', function() {
$(this).toggleClass(function(){
if($(this).hasClass('two'))
$(this).html('NOw its class two HTML HULK');
else
$(this).html('CLASS ONE HTML IRONMAN' );
return "two";
})
});
​
You should use .on to attach to one of the ancestors of the 2 elements and then use the selector argument to match the event target. The selectors won't match elements that aren't present when the handlers are bound.
$(function () {
$("#container").delegate(".one", "click", function () {
$(this).attr('class', 'two');
});
$("#container").delegate(".two", "click", function () {
$(this).attr('class', 'one');
});
})

run function at ready and keyup event

Is there another in jquery to run a function at page load and at a keyup event instead of the way I'm doing it?
$(function() {
totalQty();
$("#main input").keyup(function() {
totalQty();
});
});
Disregarding live or delegate optimizations, you can trigger an event like this:
$(function() {
$("#main input").keyup(function() {
totalQty();
}).filter(":first").keyup(); //Run it once
});
No need for the filter if it's not on multiple elements, just leave it out in that case.
You can use $(document).ready event to run functions on load:
$(document).ready(function(){
/* your code here */
});
Here's what I would do (jQuery 1.4+ )
$(document).ready(function() {
totalQty();
$("#main").delegate("input","keyup",function() {
totalQty();
});
});
You could use $.live(), which does event delegation, which is MUCH more efficient than created an event listener for every single input tag...and then missing any dynamically created ones. Try the following:
$(document).ready(function() {
totalQty();
$('#main input').live('keyup', function() {
totalQty();
});
});

How to write onshow event using JavaScript/jQuery?

I have an anchor tag on my page, I want an event attached to it, which will fire when the display of this element change.
How can I write this event, and catch whenever the display of this element changes?
This is my way of doing on onShow, as a jQuery plugin. It may or may not perform exactly what you are doing, however.
(function($){
$.fn.extend({
onShow: function(callback, unbind){
return this.each(function(){
var _this = this;
var bindopt = (unbind==undefined)?true:unbind;
if($.isFunction(callback)){
if($(_this).is(':hidden')){
var checkVis = function(){
if($(_this).is(':visible')){
callback.call(_this);
if(bindopt){
$('body').unbind('click keyup keydown', checkVis);
}
}
}
$('body').bind('click keyup keydown', checkVis);
}
else{
callback.call(_this);
}
}
});
}
});
})(jQuery);
You can call this inside the $(document).ready() function and use a callback to fire when the element is shown, as so.
$(document).ready(function(){
$('#myelement').onShow(function(){
alert('this element is now shown');
});
});
It works by binding a click, keyup, and keydown event to the body to check if the element is shown, because these events are most likely to cause an element to be shown and are very frequently performed by the user. This may not be extremely elegant but gets the job done. Also, once the element is shown, these events are unbinded from the body as to not keep firing and slowing down performance.
You can't get an onshow event directly in JavaScript. Do remember that the following methods are non-standard.
IN IE you can use
onpropertychange event
Fires after the property of an element
changes
and for Mozilla
you can use
watch
Watches for a property to be assigned
a value and runs a function when that
occurs.
You could also override jQuery's default show method:
var orgShow = $.fn.show;
$.fn.show = function()
{
$(this).trigger( 'myOnShowEvent' );
orgShow.apply( this, arguments );
return this;
}
Now just bind your code to the event:
$('#foo').bind( "myOnShowEvent", function()
{
console.log( "SHOWN!" )
});
The code from this link worked for me: http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
$('#foo').on('show', function() {
console.log('#foo is now visible');
});
$('#foo').on('hide', function() {
console.log('#foo is hidden');
});
However the callback function gets called first and then the element is shown/hidden. So if you have some operation related to the same selector and it needs to be done after being shown or hidden, the temporary fix is to add a timeout for few milliseconds.

Categories