jQuery toggle multiple elements - javascript

I can not make this piece of code work:
$("a.expand_all").on("click",function(){
$(this).text('Hide');
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
}, function () {
$(this).text('Expand');
$('.answer').each(function () {
$(this).slideUp(150, function () {
$(this).hide();
});
});
});
I'm trying to collapse expend multiple divs, but nothing happens on click event. I 'm using latest jQuery 1.10.1

It looks to me like you're using jQuery's .on method incorrectly. That method has some overloads, but none of them (sensibly) takes two functions.
If I understand what you're trying to do correctly, you just want to toggle some answer elements when a <a> tag is clicked. What you really need to do is have some way of determining if your answers are expanded or not. There are multiple ways to do that, but I've chosen to use a data element:
<a class="expand_all" href="#" data-collapsed="true">expand</a>
<p class="answer">I'm an answer!</a>
<p class="answer">Another answer</a>
Then your JavaScript can be simplified thusly:
$('a.expand_all').on("click",function(){
if( $(this).data('collapsed') ) {
$(this).text('hide').data('collapsed','');
$('.answer').slideDown(150);
} else {
$(this).text('expand').data('collapsed','true');
$('.answer').slideUp(150);
}
});
I simplified some of your constructs as well. In particular, in your code:
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
The .each is unnecessary. Just applying a jQuery method is essentially equivalent to calling .each. You rarely need to use .each. So that simplifies to this:
$('.answer').slideDown(150, function () {
$(this).show();
});
Then, .slideDown shows the element before it starts, so there's no need to call .show a second time. So we can get rid of the callback, simplifying all of this to:
$('.answer').slideDown(150);
You can see all of this in action here:
http://jsfiddle.net/Jammerwoch/sRnkw/5/
Lastly, the reason I asked whether any of your elements are dynamically added is because if they are, the way you are attaching them won't work. That is, the jQuery selectors run once, and then don't get re-run when you add new elements. So you have to be more clever. That's described in the jsfiddle above. Let me know if you need more clarification on that point.

That doesn't look like valid event binding to me, having the two functions there.
HTML - I added a div wrapper for event delegation
<div class="expando_content">
<a class="expand_all" href="#">Expand</a>
<p class="answer">I'm an answer!</a>
<p class="answer">Another answer</a>
<p>Dynamically added "expand more" goes below...it won't work :(</p>
<div id="thing"></div>
</p>
</p>
</div>
JS - moved the toggling functionality inside one function.
$(".expando_content").on("click", ".expand_all", function () {
if (!$('.answer').is(':visible')) {
$(this).text('Hide');
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
} else {
$(this).text('Expand');
$('.answer').each(function () {
$(this).slideUp(150, function () {
$(this).hide();
});
});
}
});
$('<a class="expand_all" href="#">expand more</a>').appendTo($('#thing'));
jsFiddle

Related

Fire jQuery on dynamically inserted textstring

I'm trying to remove a text string and bind it to a click event but I can't figure this one out. I want to remove all non-numerical characters inside my em element:
<div class="cart">
<dl>
<dt>
<span class="cartspan">
<em class="minicart"></em>
<em id="headercartqty">8 items</em>
</span>
</dt>
</dl>
</div>
I use this script to remove it on page load:
$('em#headercartqty').text(function(_,xText){
return xText.replace(/[^\d]/g, '');
})
My problem is that when I click on a button with the class .actionbutton it dynamically updates the string and it then shows the word items again.
How do I bind the script to the button? I understand I should use .on somehow? This is what I've got so far:
$(document).ready(function () {
$(document).on('click', ".actionbutton", function () {
$('em#headercartqty').text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
});
});
DOMSubtreeModified will detect a change to the content, which you can then make your change:-
$('em#headercartqty').bind("DOMSubtreeModified",function(){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
});
UPDATE
As #abl advised in the comments below:-
Be very careful with this event it is easy to cause an infinite loop
if you decide to change the DOM inside the event handler.
Maybe try:-
function updateQuantity(){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
$('em#headercartqty').one("DOMSubtreeModified", updateQuantity);
}
$('em#headercartqty').one("DOMSubtreeModified", updateQuantity);
Or
$('em#headercartqty').bind("DOMSubtreeModified",function(){
if(/[^\d]/g.test($(this).text())){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
}
});
Though the first update calls the function twice, where the second calls it 3 times.
Your current $(document).on('click', ".actionbutton", function () seems to work properly, so I guess the problem is: it works too early.
In other words, when the .actionbutton is clicked the two events (the original one which updates content and the yours) are fired, then the yours finishes it work before the other one.
So you might try using setTimeout to make your own event to delay its work, like this:
$(document).ready(function () {
$(document).on('click', ".actionbutton", function () {
setTimeout(function() {
$('em#headercartqty').text(function(_, xText){
return xText.replace(/[^\d]/g, '');
});
},
100); // <-- make different tries to adjust delay to the minimum
});
});
$(function(){
$('.actionbutton').on('click',function(e){
e.preventDefault();
var el= $('em#headercartqty');
el.text(el.text().replace(/[^\d]/g, ''));
});
})

toggleClass for different functions

I guess this code does not work, because at DOM load jQuery caches its objects and bind the functions to them?
$('span.button.slide_out').on('click', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideDown();
});
$('span.button.slide_in').on('click', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideUp();
});
I know I could write this easily with slideToggle or something else, but I have to fire different actions on every first and every second click. How can I achieve this using the same selector (instead of creating two different selectors)?
JS FIDDLE
The binding is indeed done on DOM creation, but that doesn't have to be a problem in this case, it also means that the button is still clicked if it no longer has the slide_out class. Therefore you can reuse the same click event and check the current state to choose whether to slide up or down. For example:
$('.slide_out').on('click', function () {
if($(this).toggleClass('slide_out slide_in').hasClass('slide_in'))
$('#testbox').slideDown();
else
$('#testbox').slideUp();
});
Fiddle
You could use the solution from Event binding on dynamically created elements?, as suggested by https://stackoverflow.com/users/502381/juhana:
HTML:
<span class="button_container"><span class="button slide_out">Click me</span></span>
<div id="testbox">Whohoohoooo, I am slidiiing!<br><br><small>Hey… wait! Why I am not sliding up again?</small></div>
JS:
$('.button_container').on('click', '.slide_out', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideDown();
});
$('.button_container').on('click', '.slide_in', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideUp();
});
http://jsfiddle.net/ag3cpcfb/
But, in my opinion it would be better to make your code simpler by using slideToggle() and adjust your css classes:
HTML:
<span class="button">Click me</span>
<div id="testbox">Whohoohoooo, I am slidiiing!<br><br><small>Hey… wait! Why I am not sliding up again?</small></div>
JS:
$('.button').on('click', function () {
var $testbox = $('#testbox');
if ($testbox.is(':visible')) {
console.log('Click 1');
} else {
console.log('Click 2');
}
$(this).toggleClass('slide_in');
$testbox.slideToggle();
});
http://jsfiddle.net/k77ferjh/
But this fires "Click 1" all of the time if you repeatedly click on the button. If this is not an issue, fine, if it is, you can also use a number to keep track of your clicks:
JS:
var clicks = 0;
$('.button').on('click', function () {
clicks++;
if (clicks % 2 == 0) {
console.log('Slide out');
} else {
console.log('Slide in');
}
$(this).toggleClass('slide_in');
$('#testbox').slideToggle();
});
http://jsfiddle.net/k77ferjh/1/

I'm trying to attach events using on() based on changing selectors

I have a button that can be in 2 different states (lets say Lock and Unlock). When I click on the button, I update the class on the button to reflect the binary opposite state. Each class has a different event attachment function using on(string, callback). For some reason the event being triggered remains the first callback assigned based on the original class.
HTML:
<button class="lock">Lock</button>
<button class="unlock">Unlock</button>
JavaScript:
$(document).ready(function() {
$('.lock').on('click', function() {
// Perform some magic here
console.log('Lock!');
$(this).removeClass('lock')
.addClass('unlock')
.html('Unlock');
});
$('.unlock').on('click', function() {
// Perform some magic here
console.log('Unlock!');
$(this).removeClass('unlock')
.addClass('lock')
.html('Lock');
});
});
https://jsfiddle.net/c283uaog/ for testing.
Expected console output when clicking on the same button repeatedly:
Lock!
Unlock!
Lock!
Actual console output:
Lock!
Lock!
Lock!
Any assistance would be greatly desired
use event Delegation
$(document).on('click','.lock', function() {
$(document).on('click','.unlock', function() {
updated Demo
Or use in single function with toggleClass
$(document).on('click', '.lock,.unlock', function () {
$('#output').html($(this).attr('class'));
$(this).toggleClass('lock unlock').text($(this).attr('class'));
});
ToggleClass demo
I'd do it this way, attaching only one event: http://jsfiddle.net/jozu47tv/
$(".lock").on('click', function(e) {
e.preventDefault();
if($(this).hasClass("lock")) {
$(this).removeClass("lock").addClass("unlock");
console.log("lock -> unlock");
} else {
$(this).removeClass("unlock").addClass("lock");
console.log("unlock -> lock");
}
})
Use Event Delegation method, Try this updated fiddle,
$(document).ready(function() {
$(document).on('click', '.lock', function() {
$('#output').html('Lock!');
$(this).removeClass('lock')
.addClass('unlock')
.html('Unlock');
});
$(document).on('click', '.unlock', function() {
$('#output').html('Unlock!');
$(this).removeClass('unlock')
.addClass('lock')
.html('Lock');
});
});
Probably, this question could answer you in a better way:
jQuery .on function for future elements, as .live is deprecated
$(document).on(event, selector, handler)
Change your html to this:
<button class="locker lock" >Lock</button>
<button class="locker unlock"">Unlock</button>
<div id="output">Output</div>
and your Js to this:
$(document).ready(function() {
$('.locker').on('click', function() {
if($(this).hasClass("lock")){
$(this).removeClass("lock");
$(this).addClass("unlock");
$(this).html("unlock");
}
else if($(this).hasClass("unlock")){
$(this).removeClass("unlock");
$(this).addClass("lock");
$(this).html("lock");
}
});
});

jQuery Simple text change on image hover

I'm trying to create a script for changing text on image hover. This is the HTML in simple version:
<section id="#first">
<div class="img-1"></div>
<div class="img-2"></div>
</section>
<section id="#second">
<div class="text-1"></div>
<div class="text-2"></div>
</section>
Javascript
jQuery(document).ready(function($){
$('.img-1').hover(
function(){ $('.text-1').addClass('text-1-active') },
function(){ $('.img-1').addClass('img-1-active') },
function(){ $('.text-2').removeClass('text-2-active') },
function(){ $('.img-2').removeClass('img-2-active') }
)
$('.img-2').hover(
function(){ $('.text-2').addClass('text-2-active') },
function(){ $('.img-2').addClass('img-2-active') },
function(){ $('.img-1').removeClass('img-1-active') },
function(){ $('.text-1').removeClass('text-1-active') }
)
});
Can't change the HTML structure. The classes do get added but don't get removed.
FIDDLE
:) actually this is all you need: DEMO
$("#first [class^=img-]").hover(function() {
$('#second .text-'+ this.className.replace(/\D/g,'')).toggle();
});
If you want to toggle classes? Nothing simpler: DEMO
$("#first [class^=img-]").hover(function() {
$(this).toggleClass("wow");
$('#second .text-'+ this.className.replace(/\D/g,'')).toggleClass("wow");
});
To explain the above, you just need to find out the number of the hovered element and reference-by number the needed .text-N element.
Also this <section id="#first">, that #first is not the way to set an ID to an HTML element.
Use simply <section id="first">
You are attempting to pass four separate callback functions, rather than a single callback that executes all the necessary code.
Here is what you want:
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active');
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
}
)
$('.img-2').hover(
function(){
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active');
$('.img-1').removeClass('img-1-active');
$('.text-1').removeClass('text-1-active');
}
)
});
http://jsfiddle.net/w4mLtec8/5/
first, you use the .hover function wrongly, it should only accept 2 arguments which is for mouseenter and mouseleave. You should be using it like this
$("selector").hover(
function(){
// mouseenter function
},
function(){
// mouseleave function
}
});
and second you don't need to use too long class name to to decide it's active or not, hence you can use it to diferentiate it like this text-1 active and text-2 active, so you can write it like this in jQuery
jQuery(document).ready(function($){
$('.img-1').hover(
function(){ $('.text-1').addClass('active') },
function(){ $('.text-1, .text-2').removeClass('active') }
)
$('.img-2').hover(
function(){ $('.text-2').addClass('active') },
function(){ $('.text-1, .text-2').removeClass('active') }
)
});
and CSS
.text-1,
.text-2{
display:none;
}
.text-1.active,
.text-2.active{
display:block;
}
here's the Updated Fiddle with the optimized way to use it.
I'm making an assumption of what you're looking for...but try this jQuery code:
jQuery(document).ready(function ($) {
$('.img-1').mouseover(function () {
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active')
}).mouseout(function () {
$('.text-1').removeClass('text-1-active');
$('.img-1').removeClass('img-1-active');
});
$('.img-2').mouseover(function () {
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active')
}).mouseout(function () {
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
});
});
You are handing the hover event a list of functions. Just send it one that does eveything.
I.E.
jQuery(document).ready(function($) {
$('.img-1').hover(
function() {
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active');
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
}
);
$('.img-2').hover(
function() {
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active');
$('.img-1').removeClass('img-1-active');
$('.text-1').removeClass('text-1-active');
}
);
});
Try this
jQuery(document).ready(function($){
$('.img-1').hover(function(){
$('.text-1').toggleClass('text-1-active');
$('.img-1').toggleClass('img-1-active');
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
});
$('.img-2').hover(function(){
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
$('.img-1').toggleClass('img-1-active');
$('.text-1').toggleClass('text-1-active');
});
});
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').toggleClass('text-1-active');
$('.img-1').toggleClass('img-1-active');
}
)
$('.img-2').hover(
function(){
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
}
)
});
http://jsfiddle.net/w4mLtec8/10/
If I understand what's to be done, the approach itself used to solve the problem could be better. Basically, use CSS to your advantage. Here, I've reduced the number of times we call JQuery by taking a little time to set up the HTML and CSS.
Tag the corresponding text div with a number
Put the same number in a data attribute so the item to hover knows which text it's associated with
I believe the intent is to have one text hover active at a time, so we can simple remove all 'active'. Naturally, we'd one to restrict the selector here to only pull text hovers, but you get the idea.
//Javascript Code
$('.img').hover( function() {
var name = $(this).attr('data-name');
$('.text').removeClass('active');
$('.text[data-name="'+name+'"]').addClass('active');
});
http://jsfiddle.net/LkL9uo0k/1/
As far as I understand, you don't need classes to show and hide the text, use .show() and .hide() to take care of it, in the original js you're passing 4 functions to the hover event whereas only 2 are needed, one executes when the element is hovered and the second one when mouse exits the element causing hover event to stop.
Here's the modified js, take a look at the fiddle too -
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').show();
$('.text-2').hide();
},
function(){
$('.text-1, .text-2').hide();
}
);
$('.img-2').hover(
function(){
$('.text-2').show();
$('.text-1').hide();
},
function(){
$('.text-1, .text-2').hide();
}
);
});
FIDDLE
I'm basically hiding both texts on exit, if you want one text block to always stay visible you can hide the other one in hover 'exit' function. Here's the fiddle for that -
http://jsfiddle.net/w4mLtec8/9/

Disable CSS link for 1 second after it has been clicked

I'm trying to have a CSS link disabled for 1 second after it has been clicked.
I have tried this without success;
In the header:
<script type="text/javascript">
$(function() {
$("#link").click(function() {
$("#link").attr("disabled", "disabled");
setTimeout(function() {
$("#link").removeAttr("disabled");
}, 2000);
});
});
</script>
Html:
the link text
CSS:
.link:diabled {
some values here.. }
You have a class="link", but with $("#link") you are addressing the id called link.
So write $(".link") everywhere instead of $("#link").
By the way: with .link:disabled you won't address the link as this only works on inputs and buttons. If you need to address it, use .link[disabled="disabled"] { ... } or even better add a class to it called disabled_link and then do in CSS .disabled_link { ... }.
There are quite a few problems here:
You are using # (the ID selector), but your html is using classes.
<a> does not have a disabled attribute
If it did, you would probably want to use .prop instead of .attr
If you change code to use classes, $(".link").prop("disabled", true) would affect all anchors, so you should probably use this.
Because disabled does not exist for <a>, the :disabled selector does not seem to work for CSS.
A working solution would be something like this:
$(".link").click(function() {
var $this = $(this);
$this.addClass('disabled');
setTimeout(function() {
$this.removeClass('disabled');
}, 2000);
});
$(document).on('click', '.disabled', function (e) {
e.preventDefault();
});
http://jsfiddle.net/ExplosionPIlls/PaYcc/
'link' is a class and you are using it as ID. Do $('.link') instead of $('#link').
I think this approach works better. The other allows you to click the link multiple times and mess up the setTimeout this unbinds the event and then re-attaches the event after the setTimeout ex: double click the link
$(".link").click(linkBind);
function linkBind(){
var $this = $(this);
$this.addClass('disabled');
$this.unbind('click');
setTimeout(function() {
$this.removeClass('disabled');
$this.bind('click', linkBind);
}, 2000);
}
$(document).on('click', '.disabled', function (e) {
e.preventDefault();
});
http://jsfiddle.net/PaYcc/1/

Categories

Resources