.on('click') in for loop to multiple elements? - javascript

I'm having trouble with my function. I need a for loop to attach a click event to my elements. Now it sadly only adds the click event to the last element.
I did it like this right now:
var $texte = $('.text-bg');
$texte = $texte.children();
for(i=0;i<$texte.length;i++){
switch($($texte[i]).attr('class')){
case 'text-top-left':
console.log($texte[i]);
$($texte[i]).on('click', function(){
$($texte[i]).toggle(
function(){$($texte[i]).animate({'left':'0'})},
function(){$($texte[i]).animate({'left':'-100px'})}
);
});
break;
}
}
But somehow the click event doesnt save. So when it goes into the second loop in the for function, the first click event is being overwritten. How to prevent this?

You can use this inside the event handler to refer to the current element
$($clicker[i]).on('click', function () {
$(this).animate({
'left': '0'
});
});
Why is your solution not working
JavaScript closure inside loops – simple practical example
Creating closures in loops: A common mistake
The given code can be changed as(there is no need to has a switch statement here)
var $texte = $('.text-bg');
$texte.children('.text-top-left').click(function () {
var $this = $(this),
flag = $this.data('animToggle');
$this.data('animToggle', !flag);
$this.animate({
'left': flag ? '0' : '-100px'
})
})
Demo: Fiddle

You need to use this, In event handler it refers to element which executed the event.
Use
$($clicker[i]).on('click', function(){
$(this).animate({'left':'0'}); //Used this here
});
Your code can be simplified as However .toggle(function, function, ... ) removed in jQuery 1.9
$('.text-bg > .text-top-left').on('click', function() {
var toggle = $(this).data('toggle');
$(this).data('toggle', !toggle);
$(this).animate({
'left': toggle ? '-100px' : '0'
});
});

You should be able to attach the handler to all jQuery result elements at once:
$clicker.on('click', function(){
$(this).animate({'left':'0'}); //Used this here
});
With your updated code, you should use the selection facilities already provided by jQuery:
$('.text-bg > .text-top-left').on('click', function() {
$(this).toggle(
function() {
$(this).animate( {'left':'0'})},
function() {
$(this).animate({'left':'-100px'})
});
});
});
To add a second case (for another class) just 'double' the code with the alternative behavior.

You can use
$($texte[i]).on('click', function(){
$(this).animate({'left':'0'});
});
OR simply assign the loop variable to a local variable INSIDE the loop:
var j = i;
$($texte[j]).on('click', function(){
$($texte[j]).animate({'left':'0'});
});

Related

Is there a way to call jquery functions on another object after finishing the first?

I want to fade out object 1 and after fade out remove a class and add one. After that on another object the object 2 should fadein and then i assign it a class. The problem that i encountered is that if i fire my event faster than the fadein/fadeout the object stays active.
$('.menuA').on("click", function () {
$('.menuA').removeClass("blue accent-3 z-depth-2", 100);
let clicked = $(this);
$('.menuA').promise().done(function () {
clicked.addClass("blue accent-3 z-depth-2", 100);
})
animatePanes($(this).attr("con"));
})
function animatePanes(pane) {
let paneOld = $('.pane-active');
paneOld.fadeOut(250).removeClass("pane-active").addClass("pane-inactive").promise().done(function () {
$('.' + pane).fadeIn(250).removeClass("pane-inactive").addClass("pane-active");
});
};
Thats my event with the function. The problem is that if i click to fast and trigger the event on menuA the paneOld doesnt get the class pane-inactive.
I already tried to do a global variable that checks if the event is running but it didnt worked (probably because i thinked wrong).
Is there a way to disable the event listener until the event is completly finished?
Or is there a better way?
You can surely do it with a global variable - as you've already said. Maybe you just put in in the wrong place.
I'd recommend something like isAnimating=false and 'disable' the click event listener if it's value is true. This way you can reset isAnimating to false as soon as all your animations are completed.
var isAnimating = false;
$('.menuA').on("click", function() {
if (!isAnimating) {
$('.menuA').removeClass("blue accent-3 z-depth-2", 100);
let clicked = $(this);
$('.menuA').promise().done(function() {
clicked.addClass("blue accent-3 z-depth-2", 100);
})
animatePanes($(this).attr("con"));
isAnimating = true;
}
})
function animatePanes(pane) {
let paneOld = $('.pane-active');
paneOld.fadeOut(250).removeClass("pane-active").addClass("pane-inactive").promise().done(function() {
$('.' + pane).fadeIn(250).removeClass("pane-inactive").addClass("pane-active").promise().done(function() {
isAnimating = false;
});
});
}

Registering jQuery click, first and second click

Is there a way to run two functions similar to this:
$('.myClass').click(
function() {
// First click
},
function() {
// Second click
}
);
I want to use a basic toggle event, but .toggle() has been deprecated.
Try this:
$('.myClass').click(function() {
var clicks = $(this).data('clicks');
if (clicks) {
// odd clicks
} else {
// even clicks
}
$(this).data("clicks", !clicks);
});
This is based on an already answered question: Alternative to jQuery's .toggle() method that supports eventData?
Or this :
var clicks = 0;
$('.myClass').click(function() {
if (clicks == 0){
// first click
} else{
// second click
}
++clicks;
});
this I worked for my menu
var SubMenuH = $('.subBoxHederMenu').height();
var clicks = 0;
$('.btn-menu').click(function(){
if(clicks == 0){
$('.headerMenu').animate({height:SubMenuH});
clicks++;
console.log("abierto");
}else{
$('.headerMenu').animate({height:"55px"});
clicks--;
console.log("cerrado");
}
console.log(clicks);
});
i don't know what you are tryin to do but we can get basic toggle by
$('.myClass').click({
var $this=$(this);
if($this.is(':hidden'))
{
$this.show('slow');
}else{
$this.hide('slow');
}
})
note: this works for endless click event for that element .. not just for two clicks (if that is what you want)
OR you can use css class to hide/show the div and use jquery.toggleClass()
In the method mentioned below We are passing an array of functions to our custom .toggleClick() function. And We are using data-* attribute of HTML5 to store index of the function that will be executed in next iteration of click event handling process. This value, stored in data-index property, is updated in each iteration so that we can track the index of function to be executed in next iteration.
All of these functions will be executed one by one in each iteration of click event. For example in first iteration function at index[0] will be executed, in 2nd iteration function stored at index[1] will be executed and so on.
You can pass only 2 functions to this array in your case. But this method is not limited to only 2 functions. You can pass 3, 4, 5 or more functions in this array and they will be executed without making any changes in code.
Example in the snippet below is handling four functions. You can pass functions according to your own needs.
$.fn.toggleClick = function(funcArray) {
return this.click(function() {
var elem = $(this);
var index = elem.data('index') || 0;
funcArray[index]();
elem.data('index', (index + 1) % funcArray.length);
});
};
$('.btn').toggleClick([
function() {
alert('From Function 1');
}, function() {
alert('From Function 2');
}, function() {
alert('From Function 3');
}, function() {
alert('From Function 4');
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button type="button" class="btn">Click Me</button>
<button type="button" class="btn">Click Me</button>
If you literally only want the first and second click:
$('.myClass').one( 'click', function() {
// First click
$('.myClass').one( 'click', function() {
// Second click
});
);
var click_s=0;
$('#show_pass').click(function(){
if(click_s % 2 == 0){
$('#pwd').attr('type','text');
$(this).html('Hide');
}
else{
$('#pwd').attr('type','password');
$(this).html('Show');
}
click_s++;
});
When You click the selector it automatically triggers second and waiting for another click event.
$(selector).click(function(e){
e.preventDefault(); // prevent from Posting or page loading
//do your stuff for first click;
$(this).click(function(e){
e.preventDefault();// prevent from Posting or page loading
// do your stuff for second click;
});
});
I hope this was helpful to you..
I reach here looking for some answers, and thanks to you guys I´ve solved this in great manner I would like to share mi solution.
I only use addClass, removeClass and hasClass JQuery commands.
This is how I´ve done it and it works great:
$('.toggle').click(function() {
if($('.categ').hasClass("open")){
$('.categ').removeClass('open');
}
else{
$('.categ').addClass('open');
}
});
This way a class .open is added to the Html when you first clikc.
Second click checks if the class exists. If exists it removes it.

How Store and Disable Event of another element Temporary

I am looking for a way to manage the events. I have a hover function for element A, and click function for element B. I want to disable A`s hover function temporary while the second click of B.
I am looking for a way that not necessary to rewrite the hole function of A inside of B. Something very simply just like "Store and Disable Event, Call Stored Function"
I found some technique like .data('events') and console.log. I tired but failed, or maybe I wrote them in a wrong way.
Please help and advice!
$(A).hover();
$(b).click(
if($.hasData($(A)[0])){ // if A has event,
//STORE all the event A has, and disable
}else{
//ENABLE the stored event for A
}
);
Try this
var hoverme = function() {
alert('Hover Event Fired');
};
$('.A').hover(hoverme);
var i = 0;
$('.B').on('click', function(){
if(i%2 === 0){
// Unbind event
$('.A').off('hover');
}
else{
// Else bind the event
$('.A').hover(hoverme);
}
i++;
});
Check Fiddle
I think that what you want to do is something like this (example for JQuery 1.7.2):
$("#a").hover(function(){alert("test")});
$("#a")[0].active=true;
$("#b").click(function(){
if($("#a")[0].active){
$("#a")[0].storedEvents = [];
var hoverEvents = $("#a").data("events").mouseover;
jQuery.each(hoverEvents , function(key,handlerObj) {
$("#a")[0].storedEvents.push(handlerObj.handler);
});
$("#a").off('hover');
}else{
for(var i=0;i<$("#a")[0].storedEvents.length;i++){
$("#a").hover($("#a")[0].storedEvents[i]);
}
}
$("#a")[0].active = ($("#a")[0].active)==false;
});​
JSFiddle Example
But there are a couple of things that you must have in consideration:
This will only work if you add the events with JQuery, because JQuery keeps an internal track of the event handlers that have been added.
Each version of JQuery handles data("events") differently, that means that this code may not work with other version of JQuery.
I hope that this helps.
EDIT:
data("events") was an internal undocumented data structure used in JQuery 1.6 and JQUery 1.7, but it has been removed in JQuery 1.8. So in JQuery 1.8 the only way to access the events data is through: $._data(element, "events"). But keep in mind the advice from the JQuery documentation: this is not a supported public interface; the actual data structures may change incompatibly from version to version.
You could try having a variable that is outside the scope of functions a and b, and use that variable to trigger the action to take in function b on function a.
var state;
var a = function() {
if(!state) {
state = true;
// Add hover action and other prep. I'd create a third function to handle this.
console.log(state);
};
var b = function() {
if(state) {
state = false;
// Do unbinding of hover code with third function.
} else {
state = true;
// Do whatever else you needed to do
}
}
Without knowing more about what you're trying to do, I'd try something similar to this.
It sounds like you want to disable the click hover event for A if B is clicked.
$("body").on("hover", "#a", function(){
alert("hovering");
});
$("#b").click( function(){
$("body").off("hover", "#a", function() {
alert("removed hovering");
});
});
You can use the jQuery off method, have a look at this fiddle. http://jsfiddle.net/nKLwK/1/
Define a function to assign to hover on A element, so in b click, call unbind('hover') for A element and in second click on b element define again a function to hover, like this:
function aHover(eventObject) {
// Todo when the mouse enter object. You can use $(this) here
}
function aHoverOut(eventObject) {
// Todo when the mouse leave the object. You can use $(this) here
}
$(A).hover(aHover, aHoverOut);
// ...
$(b).click(function(eventObject) {
if($.hasData($(A)[0])){ // if A has event,
$(A).unbind('mouseenter mouseleave'); // This is because not a event hover, jQuery convert the element.hover(hoverIn, hoverOut) in element.bind('mouseenter', hoverIn) and element.bind('mouseleave', hoverOut)
}else{
$(A).hover(aHover, aHoverOut);
}
});
There are provably better ways to do it, but this works fine, on document ready do this:
$("#a")[0].active=false;
$("#b").click(function(){
$("#a")[0].active = ($("#a")[0].active)==false;
if($("#a")[0].active){
$("#a").hover(function(){alert("test")});
}else{
$("#a").off('hover');
}
});
JSFiddle example
You can use .off function from jQuery to unbind the hover on your "a" element.
function hoverA() {
alert('I\'m on hover');
}
$('#a').hover( hoverA );
var active = true;
$('#b').on('click', function(){
if(active){
$('#a').off('hover');
active = false;
} else{
$('#a').hover(hoverA);
active = true;
}
});
Live demo available here : http://codepen.io/joe/pen/wblpC

Combining jquery functions - on() hover/mouseenter/mouseleave

I have a series of elements (lets call them '.my-elements') - some load on document ready, while others are loaded later via a pagination script.
I would like to set a variable according to whether or not the mouse is over these elements. The code below works, but I suspect there is a better way... Can I do this so I only have to reference the DOM once?
$(document).on('mouseenter','.my-elements', function(){
mouse_is_inside = true;
});
$(document).on('mouseleave','.my-elements', function(){
mouse_is_inside = false;
});
Thanks!
You can bind to both together and check the event.type:
$(document).on('mouseenter mouseleave', '.my-elements', function (ev) {
mouse_is_inside = ev.type === 'mouseenter';
});
Or, if you want to keep them separate, .on has another syntax that takes an event map:
$(document).on({
mouseenter: function () {
mouse_is_inside = true;
},
mouseleave: function () {
mouse_is_inside = false;
}
}, '.my-elements');
Check out jQuery hover which is the same as:
$(selector).mouseenter(handlerIn).mouseleave(handlerOut);
UPDATE: I just realized you need to persist the events via the on() method. In that case, you can use an event map like so:
.on({
mouseenter: function() {
console.log('enter');
},
mouseleave: function() {
console.log('bye!');
}
})
Almost all jQuery methods return objects, so you can chain them together:
$(document).on('mouseenter','.my-elements', function(){
mouse_is_inside = true;
}).on('mouseleave','.my-elements', function(){
mouse_is_inside = false;
});
You could also try:
$(".my-elements").hover(function(eIn) {
// do work for mouse over
},
function(eOut) {
// do work for mouse out
});
update and correction
realized you need more dynamic lock in which case Jonathan Lonowski's or Derek Hunziker's is perfect
For starters, you can select for your elements instead of document.
$('.my-elements').on('mouseenter', function(){
mouse_is_inside = true;
});
You could try a shortcut notation like this...
$('.my-elements').on('mouseenter mouseleave', function(){
mouse_is_inside = !mouse_is_inside;
});
This will negate the value every time the mouse goes in or out, which should keep the mouse_is_inside variable set to the right value.
$('.my-elements').on('mouseenter mouseleave', function(event){
mouse_is_inside = event.type === 'mouseenter';
});
but its generally not a good idea to have a global variable incidating a event state

Why does my function get called twice in jQuery?

I have the following jQuery
$('img[title*=\"Show\"]').click(function() {
//$e.preventDefault();
var position = $('img[title*=\"Show\"]').parent().position();
$('#popover').css('top', position.top + $('img[title*=\"Show\"]').parent().height() + 150);
console.log(position);
$('#popover').fadeToggle('fast');
if ($('img[title*=\"Show\"]').hasClass('active')) {
$(this).removeClass('active');
} else {
$('img[title*=\"Show\"]').addClass('active');
}
});
I have two images with the title "Show Options." For some reason whenever I click on any of these images, it gets printed TWICE. When I only have 1 image, it only gets printed once. Why is this?
instead of $('img[title*=\"Show\"]') inside click function use $(this)
if doesn't works use:
$('img[title*=\"Show\"]').click(function(e) {
e.stopImmediatePropagation();
//other code
});
Use the following code
$('img[title*="Show"]').click(function (evt) {
$('#popover').hide();
$('img[title*="Show"]').removeClass("active");
$(this).addClass("active");
var p = $(this).parent();
$('#popover').css('top', p.position().top + p.height() + 150).fadeToggle('fast');
});
You can use event.stopPropogation so that event is not bubbled further. Maybe your function is being triggered from two different events and other one also get triggered while bubbling.

Categories