toggleClass for different functions - javascript

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/

Related

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 toggle multiple elements

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

Hiding Bootstrap Popover on Click Outside Popover

I'm trying to hide the Bootstrap Popover when the user clicks anywhere outside the popover. (I'm really not sure why the creators of Bootstrap decided not to provide this functionality.)
I found the following code on the web but I really don't understand it.
// Hide popover on click anywhere on the document except itself
$(document).click(function(e) {
// Check for click on the popup itself
$('.popover').click(function() {
return false; // Do nothing
});
// Clicking on document other than popup then hide the popup
$('.pop').popover('hide');
});
The main thing I find confusing is the line $('.popover').click(function() { return false; });. Doesn't this line add an event handler for the click event? How does that prevent the call to popover('hide') that follows from hiding the popover?
And has anyone seen a better technique?
Note: I know variations of this question has been asked here before, but the answers to those questions involve code more complex than the code above. So my question is really about the code above
I made http://jsfiddle.net/BcczZ/2/, which hopefully answers your question
Example HTML
<div class="well>
<a class="btn" data-toggle="popover" data-content="content.">Popover</a>
<a class="btn btn-danger bad">Bad button</a>
</div>
JS
var $popover = $('[data-toggle=popover]').popover();
//first event handler for bad button
$('.bad').click(function () {
alert("clicked");
});
$(document).on("click", function (e) {
var $target = $(e.target),
var isPopover = $target.is('[data-toggle=popover]'),
inPopover = $target.closest('.popover').length > 0
//Does nothing, only prints on console and wastes memory. BAD CODE, REMOVE IT
$('.bad').click(function () {
console.log('clicked');
return false;
});
//hide only if clicked on button or inside popover
if (!isPopover && !inPopover) $popover.popover('hide');
});
As I mentioned in my comment, event handlers don't get overwritten, they just stack. Since there is already an event handler on the .bad button, it will be fired, along with any other event handler
Open your console in the jsfiddle, press 5 times somewhere on the page (not the popover button) and then click bad button you should see clicked printed the same amount of times you pressed
Hope it helps
P.S:
If you think about it, you already saw this happening, especially in jQuery.
Think of all the $(document).ready(...) that exist in a page using multiple jquery plugins. That line just registers an event handler on the document's ready event
I just did a more event based solution.
var $toggle = $('.your-popover-button');
$toggle.popover();
var hidePopover = function() {
$toggle.popover('hide');
};
$toggle.on('shown', function () {
var $popover = $toggle.next();
$popover.on('mousedown', function(e) {
e.stopPropagation();
});
$toggle.on('mousedown', function(e) {
e.stopPropagation();
});
$(document).on('mousedown',hidePopover);
});
$toggle.on('hidden', function () {
$(document).off('mousedown', hidePopover);
});
short answer
insert this to bootstrap min.js
when popout onblur will hide popover
when popout more than one, older popover will be hide
$count=0;$(document).click(function(evt){if($count==0){$count++;}else{$('[data-toggle="popover"]').popover('hide');$count=0;}});$('[data-toggle="popover"]').popover();$('[data-toggle="popover"]').on('click', function(e){$('[data-toggle="popover"]').not(this).popover('hide');$count=0;});
None of the above solutions worked 100% for me because I had to click twice on another, or the same, popover to open it again. I have written the solution from scratch to be simple and effective.
$('[data-toggle="popover"]').popover({
html:true,
trigger: "manual",
animation: false
});
$(document).on('click','body',function(e){
$('[data-toggle="popover"]').each(function () {
$(this).popover('hide');
});
if (e.target.hasAttribute('data-toggle') && e.target.getAttribute('data-toggle') === 'popover') {
e.preventDefault();
$(e.target).popover('show');
}
else if (e.target.parentElement.hasAttribute('data-toggle') && e.target.parentElement.getAttribute('data-toggle') === 'popover') {
e.preventDefault();
$(e.target.parentElement).popover('show');
}
});
My solution, works 100%, for Bootstrap v3
$('html').on('click', function(e) {
if(typeof $(e.target).data('original-title') !== 'undefined'){
$('[data-original-title]').not(e.target).popover('hide');
}
if($(e.target).parents().is('[data-original-title]')){
$('[data-original-title]').not($(e.target).closest('[data-original-title]')).popover('hide');
}
if (typeof $(e.target).data('original-title') == 'undefined' &&
!$(e.target).parents().is('.popover.in') && !$(e.target).parents().is('[data-original-title]')) {
$('[data-original-title]').popover('hide');
}
});

how to apply function to each checkbox on page?

I am trying to apply a function to every checkbox on a page that shows/hides <div class="selectlist"> depending on if the checkbox is checked, this function makes all the <div class="selectlist"> on the page toggle
$("input[type=checkbox]").live('change', function() {
if ($(this).is(':checked') == false) {
$('#selectlist').hide();
} else {
$('#selectlist').show();
}
});
I tried the jquery each function like this but that doesnt seem to work
$.each($("input[type=checkbox]").live('change', function() {
if ($(this).is(':checked') == false) {
$('#selectlist').hide();
} else {
$('#selectlist').show();
}
}));
I know its possible to this by using a class instead of input[type=checkbox] but I want to avoid doing that
How can I make jquery change the behavior of the checkbox the user clicks?
If you're trying to bind an event handler to all elements verifying input[type=checkbox], simply do
$(document).on('change', "input[type=checkbox]", function() {
if (!this.checked) {
$('#selectlist').hide();
} else {
$('#selectlist').show();
}
});
No need to use each there : most jQuery functions work if the jQuery set contains more than one element.
Note that I use on there instead of live : after having been deprecated for a long time, live has been removed from recent versions of jQuery.
EDIT : discussion in comments below lead to this code :
$(document).on('change', "input[type=checkbox]", function() {
$(this).next().toggle(this.checked);
});
$(document).on('change', 'input[type=checkbox]', function() {
$('#selectlist').toggle(this.checked);
});
ID's are uniqe, and there is no "all the <div id="selectlist"> on the page toggle", there can be only one? Use a class instead, and show us what the markup looks like !

jquery how to combine two selectors to second function of single toggle event

If I have a regular toggle function bound to a click event
$('#work-content a').toggle(
function() {
// first click stuff
}, function() {
// second click stuff
}
);
But, I also need to bind $(document).click event to the second function somehow. My logic is probably off so I'm sure a new solution is necessary.
Functionality is 1) do something when link is clicked then 2) do the opposite when the link is clicked again or if the outside of the #work-content div is clicked.
Just extract the anonymous function and give it a name:
var thatFunction = function () {
...
}
$('#work-content a').toggle(
function() {
// first click stuff
},
thatFunction);
$(document).click(thatFunction);
the toggle function is used to hide/show your div and should not be used to maintain state of an event. just use another local variable for this and also define two functions perform your two different actions and pass the function pointer as callback to your event listener.
thus:
var linkClicked=false;
function fun1(){}
function fun2(){}
$('#work-content a').click(
function() {
if(!linkClicked)
fun1();
else
fun2();
});
$("body").click(function(){
if($(event.target).closest("#work-content")===null) //to make sure clicking inside your div does not trigger its close
{
fun2();
}
});
linkClicked = false;
$('#work-content .pic a').click(function(event) {
event.preventDefault();
var c = $(this);
if (!linkClicked) {
values = workOpen($(this));
} else {
workClose(c, values);
}
$('body').one('click',function() {
workClose(c, values);
});
});
This solution was exactly what I needed for what it's worth.

Categories

Resources