Remove class on click anywhere, unless a certain textbox is clicked on - javascript

I am trying to improve the following script a little:
$(document).click(function(event) {
$('.home.active').click();
$('.home').removeClass("active");
});
This works, but it works when I don't want it to work. For example, I have a textbox. If that textbox gets focus, the class should not be removed, but if anything else on the page is clicked, the class should be removed. So I tried the following, which does not work:
$(document).click(function(event) {
if( $('#txtHomeSearch').focus() ) {
// don't remove class
} else {
$('.home.active').click();
$('.home').removeClass("active");
}
});
This stops the class being remove altogether, no matter where I click, and the textbox always has focus.

You can use event.target to determine the id of the clicked element:
$(document).click(function(event) {
if (event.target.id === "txtHomeSearch") {
// Don't remove class.
} else {
$('.home.active').click();
$('.home').removeClass("active");
}
});

you can find the source of the event using the target property.
if ($(event.target).prop('id') == 'txtHomeSearch') {
//don't remove class
}

You can try. You might need to drop the # from #txtHomeSearch I can't remember off the top of my head.
$(document).click(function(event) {
if( $(this).attr('id') == '#txtHomeSearch') {
// don't remove class
} else {
$('.home.active').click();
$('.home').removeClass("active");
}
});

Use
$(document).click(function(event) {
if( event.target.id == 'txtHomeSearch' )
return;
$('.home.active').click();
$('.home').removeClass("active");
});
Whatever the $('.home.active').click(); does, might screw it up.

You can use the event.target property to cross-check the element.
The problem is your if( $('#txtHomeSearch').focus() ) ... that's not checking if it's in focus, its GIVING it focus.
to select a focused element you can use the jquery(1.6) :focus selector, use $(document.activeElement) for future reference

Related

How do we detect a double click outside an element?

I have this function:
this.div.click( function(e) {
...
});
I would like to listen for double clicks outside this element. I know that we can use blur() for clicks outside an element. But I would like to handle only double click events. What's the best way to do this?
You can use the .dblclick() event to listen to the double-click at the body level, and then use it's target attribute and .contains() to see if the click occurred within the div.
Something like this:
// div to check if dbl click did _not_ originate from
var mydiv = jQuery("#mydiv").get(0);
// listen to body for double clicks
$("body").dblclick(function(e) {
// if click target does not fall within #mydiv
if (mydiv !== e.target && $.contains(mydiv, e.target) !== true) {
console.log("outside of mydiv");
}
});
Here is a jsbin demo.
There is another way to do this, by modifying e.originalEvent:
$( "#mydiv" ).dblclick(function(e) {
e.originalEvent.inside = true;
});
$( "body" ).dblclick(function(e) {
if( e.originalEvent.inside ) {
console.log('inside');
} else {
console.log('outside');
};
});
I have updated Johnatan's Bin. Think it should be faster.

find select option with selected property using javascript

I have a view that loads select elements dynamically into the page on certain button clicks. Each of these selects have the same id value followed with an index value based on how many times the button is clicked. so the id would be like
id="my_id_" + numOfClicks;
I have also given all these selectors the same class value
class="selects"
What is the best way to have an event handler for when the selected option changes in any of the drop downs. right now I have the following:
$('.selects').change(function() {
if($('this option:selected').val() == 0) {
}
else {
}
});
So what I'm trying to do is first get the right select element using "this" then figure out which of the options are selected. Is there a better/more efficient way to do this?
As you say these get added at runtime, you'll want a delegated event handler. Within the handler, as the comments have pointed out, it's just $(this).val() to get the selected value of that select box. So:
$("selector for some container they're in").on("change", ".selects", function() {
if($(this).val() == 0) {
}
else {
}
});
For instance, if they're all inside an element with the class container, then:
$(".container").on("change", ".selects", function() {
if($(this).val() == 0) {
}
else {
}
});
If there's no other suitable container, you can just use $(document).on(..., but usually it's better to handle things a bit closer to where they are than that.
Side note: Values are always strings, but == will coerce, so "0" == 0 is true. Still, it's useful to remember that they're strings.
Assuming html input.selects:
$('body').on('change', '.selects', function() {
if($(this).val() == '0') {
}
else {
}
});
http://jsfiddle.net/r4pxx0yy/1/
No quote around this.

jquery selector help. Everything but the specified selector

I have the following function to open an overlay menu:
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
});
To hide the menu, I would like the user to be able to click on any area outside ".context-switch-menu"
I am trying with :not() but with no success..
$('body').click(function(e) {
if ($(e.target).hasClass('context-switch')) {
return;
}
$(".context-switch-menu").hide();
});
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
return false;
});
The reason this can be difficult is because of event bubbling.
You can try something like this:
$('.context-switch').click(function(e) {
e.stopPropagation();
$(".context-switch-menu").toggle();
});
$(".context-switch-menu").click(function(e){
e.stopPropagation();
});
$("body").click(function(e){
$(".context-switch-menu").hide();
});
The e.stopPropagation() prevents the click event from bubbling to the body handlers. Without it, any click to .context-switch or .context-switch-menu would also trigger the body event handler, which you don't want, as it would nullify the effect of the .context-switch click half the time. (ie, if the state is hidden, and then you click to show, the event would bubble and trigger the body handler that would then hide the .context-switch-menu again.)
Without testing, would something like this work?:
$('.context-switch').click(function() {
$(".context-switch-menu").show();
});
$(document).click(function() {
$(".context-switch-menu").hide();
});
Instead of using document, 'html' or 'body' may work as well.
$(document).on('click', function(e) {
if (e.target.className !='context-switch-menu') {
$(".context-switch-menu").hide();
}
});
Just an idea here, based on what what others have suggested in the past:
$(document).click(function(e){
//this should give you the clicked element's id attribute
var elem = $(e.target).attr('classname');
if(elem !== 'context-switch-menu'){
$('.context-switch-menu').slideUp('slow');
//or however you want to hide it
}
});
try this, we don't want to call a function when you clicked on the element itself, and not when we click inside the element. That's why we need 2 checks.
You want to use e.target which is the element you clicked.
$("html").click(function(e){
if( !$(e.target).is(".context-switch-menu") &&
$(e.target).closest(".context-switch-menu").length == 0
)
{
alert("CLICKED OUTSIDE");
}
});
Live fiddle: http://jsfiddle.net/Xc25K/1/

using is(':last') to check the last element

I have a list of input elements. I want to bind a keyup event handler to them, so that whenever user hits Enter, he goes to the next field. But if the input is the last input, then I want to fire the click event of a button, so that user goes to another level. My code is like this:
$('.loginBody input:visible').keyup(function (e) {
if (e.keyCode == 13) {
if ($(this).is(':last')) {
$('#next').click();
}
else {
$(this).closest('input').focus();
}
}
});
However, seems that is(':last') doesn't work. What's wrong?
:last returns the last element of a collection, and $(this) is only a single element collection.
Try using the :last-child selector instead, which will check whether your <input> is really the last one in that group.
Alternatively, if your fields aren't all in the same parent, reverse the sense of your test:
if ($('input').filter(':last').is(this)) {
// this is the last input
}
NB: using .filter(':last') rather than input:last per recommendations at http://api.jquery.com/last-selector/
UPDATED: You could create two different bindings:
$('.loginBody input:last').keyup(function (e) {
if (e.which == 13) {
$("#result").html("last one");
}
});
$('.loginBody input').not(":last").keyup(function (e) {
if (e.which == 13) {
$("#result").html("not last one");
}
});
Here is a working example: http://jsfiddle.net/6gYXk/1/
have you tried is(':last-child') pseudoclass instead?
:last-child means "if this element is the last child of its parent". Note that only element nodes (HTML tags) count, these pseudo-classes ignore text nodes.
edit:
also to focus closest sibling element use:
$(e.target).next('input').focus();
so full code can be:
$('.loginBody input:visible').keyup(function (e) {
if (e.keyCode == 13) {
if ($(this).is(':last-child')) {
$('#next').click();
} else {
$(e.target).next('input').focus();
}
}
});
i've prepared an example at: http://jsfiddle.net/HhvUF/
The nicest solution might well be to use nextAll to see if there are any subsequent sibling elements:
if ($(this).nextAll().length) {
$(this).closest('input').focus();
} else {
$('#next').click();
}
NB that I have turned the if around to make it easier to read.
If you need to check only for input elements, you can supply a selector:
if ($(this).nextAll('input').length) {

How to call a function with jQuery blur UNLESS clicking on a link?

I have a small jQuery script:
$('.field').blur(function() {
$(this).next().children().hide();
});
The children that is hidden contains some links. This makes it impossible to click the links (because they get hidden). What is an appropriate solution to this?
This is as close as I have got:
$('.field').blur(function() {
$('*').not('.adress').click(function(e) {
foo = $(this).data('events').click;
if(foo.length <= 1) {
// $(this).next('.spacer').children().removeClass("visible");
}
$(this).unbind(e);
});
});
The uncommented line is suppose to refer to the field that is blurred, but it doesn't seem to work. Any suggestions?
You can give it a slight delay, like this:
$('.field').blur(function() {
var kids = $(this).next().children();
setTimeout(function() { kids.hide(); }, 10);
});
This gives you time to click before those child links go away.
This is how I ended up doing it:
var curFocus;
$(document).delegate('*','mousedown', function(){
if ((this != curFocus) && // don't bother if this was the previous active element
($(curFocus).is('.field')) && // if it was a .field that was blurred
!($(this).is('.adress'))
) {
$('.' + $(curFocus).attr("id")).removeClass("visible"); // take action based on the blurred element
}
curFocus = this; // log the newly focussed element for the next event
});
I believe you can use .not('a') in this situation:
$('.field').not('a').blur(function() {
$(this).next().children().hide();
});
This isn't tested, so I am not sure if this will work or not.

Categories