JavaScript / jQuery not on element - javascript

How can i create an action for an element which will change when the user is not over it. mouseover and mouseleave can't be applied in this situation because the element is activated on page load and the mouse location can be outside the element.
Here is the condition:
if mouse is not over element:
close element
else:
do nothing
So what i want to know is how can i check with jQuery/JavaScript if the current mouse position is not on the specific element.
Thanks!!

You could bind the event handler to the body and check for the requested target:
$().ready(function() {
$("body").on('mouseover',function(event) {
if($(event.target).attr('id') === 'yourid' ) {
console.log('do close this element');
} else {
console.log('do nothing');
}
});
});

I would use a global boolean to keep track of whether the mouse is currently hovering over the element or not. Then, you can periodically check that boolean using setInterval (with some reasonable time interval) which will decide whether the element should be hidden or not.
var mouseIsOver = false;
$('#elementId').hover(
function () {
mouseIsOver = true;
},
function () {
mouseIsOver = false;
}
);
setInterval(function() {
if (mouseIsOver == false) {
$('#elementId').fadeOut();
}
}, 250);

There is a brilliant jQuery plugin for just this. It's called jQuery outside events.
Check the homepage here: http://benalman.com/code/projects/jquery-outside-events/docs/files/jquery-ba-outside-events-js.html
The usage is super-simple and straight forward. I'd recommend this with great experience earlier.

Related

removeEventListener on class name after one click

I'm trying to write some Javascript to get click event on all elements with class from an array. Everything works fine, but I need it unclickable only until second condition in klikej() function is met. Once the click event fires, then the item with that class shouldn't be clickable. I've tried using removeEventListener and/or handle it with PreventDefaults(), but nothing works. I need to use only vanilla Javascript - no jQuery or anything else. Could you please help me?
poleRandomKaret.forEach(karta => {
document.querySelectorAll(`.${karta}`).forEach(element => {
element.addEventListener('click', event => {
console.log("klik");
klikej(event, element);
});
});
});
function klikej(event, element) {
let kliknuteKarty = document.querySelectorAll('[data-ovoce]');
if (kliknuteKarty.length < 2) {
element.setAttribute('data-ovoce', 'otoceno');
}
kliknuteKarty = document.querySelectorAll('[data-ovoce]');
if (kliknuteKarty.length === 2) {
kliknuteKarty[0].className === kliknuteKarty[1].className ? console.log("yes") : console.log("nope");
kliknuteKarty.forEach(element => {
element.removeAttribute("data-ovoce");
});
}
}
EDIT: The item shouldn't be clickable until the second condition in klikej() function is met. I'm trying to do memory game using vanilla JS. Function klikej() sets data attribute to an item and once there are two items with identical data attributes, it'll print in console "yes". If they're two different data attributes, they needs to be clickable again.
If you remove event listener, and will need to listen again, you would need to add it again or listen with something else. If I would need to recognize if something was clicked, I would add property to the element in the listener callback, so something like:
// before anything else we check if it was clicked before
if (element.clicked) {
// do your magic when element was already clicked
} else {
// do different magic with not yet opened element here
}
// after you did everything needed
// set the clicked attribute to true or false (if you need "unclick" it)
element.clicked = true;
It isn't directly answer to your question but hopefully another view to possible solution - if I understood you correctly, you do something when it was clicked and something else when it wasn't yet clicked and here you have control for both cases.
You can add an option called once as the third parameter of the addEventListener, which makes the event listener execute once.
element.addEventListener('click', function(e){
console.log('clicked'); // This will be executed once.
}, {once: true});

trigger function if scroll reaches a certain point only once. Not every time

I want to check if my users arrive at a certain point in my page. SO I created the following JS code:
$(document).on('scroll', function() {
if($(this).scrollTop()>=$('#page2').position().top){
alert("trigger");
}
})
Which checks if the users reached my id="page2". But I want this to trigger ONLY once, no matter if the users goes back up and back down, right now it gets trigger everytime the page2.position().top = scrollTop.
How can I do this ?
You can use event.namespace and off() to unbind event handler after execution of desired statement.
$(document).on('scroll.something', function() {
if ($(this).scrollTop() >= $('#page2').position().top) {
//Do something
//Unbind the event
$(document).off('scroll.something')
}
})
You can use this code to achieve your desired output.
var checkonce = false;
$(document).on('scroll', function() {
if($(this).scrollTop()>=$('#page2').position().top){
if(checkonce == false) {
alert("trigger");
checkonce = true;
}
}
});
You can just off the scroll event on your document after the first scroll has reached.
Edit: Also it would be better if you name your events, Which will help us remove the specific event by using the name. (Satpal already mentioned this in his answer before me, I am improving my answer standard as well.)
$(document).on('scroll.Page2ScrollEvent', function() {
if($(this).scrollTop()>=$('#page2').position().top){
$(this).off('scroll.Page2ScrollEvent'); // remove specific scroll event.
alert("trigger");
}
})

Trigger function based on Class Change

I have the following. I am trying to trigger the function based on the css class changing but it's not working.
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#slider-banner").bind("cssClassChanged",function(){
console.log("I'm Here!");
if(jQuery("#slider-banner").hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
});
jQuery("#slider-banner").trigger('cssClassChanged');
The colsole displays my console.log message on page load, but not when the class changes again after page load. Anyone see what I'm doing wrong?
UPDATE:
So I've learned that "cssClassChanged" is not legit... I was attempting to adapt an answer I found somewhere else... I do realize that if jQuery were a weapon, I'd be dangerous! (knowing that is half the battle, right?)
My attempt to adapt gdoron's answer linked to below:
<script type="text/javascript">
jQuery(document).ready(function()
{
function checkForChanges()
{
if(jQuery("#slider-banner").hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
else
setTimeout(checkForChanges, 500);
}
});
</script>
I'm still missing something, though. It only works for the first class on page load.
Someone asked how I'm changing the classes. I'm using a slider and on each slide is a div with the ID "slider-banner" and the class varies depending on which of the three ID'd areas below it that I am trying to switch the background image for.
There is no such event cssClassChanged I think that explains all...
10 hours ago I answered how you can detect class change, read my answer there
Update:
function checkForChanges()
{
var sliderBanner = jQuery("#slider-banner");
if(sliderBanner.hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(sliderBanner.hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(sliderBanner.hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
setTimeout(checkForChanges, 500);
}
jQuery(checkForChanges);
There is no built-in event named "cssClassChanged". You have created your own custom event, and are triggering it manually during page load. It will not fire automatically -- you'll have to call trigger('cssClassChanged') each time you change the CSS class.
There is no cssClassChanged event that I am aware of, you need to manually trigger it. However, you aren't changing the class in the code you posted, therefore I'm not sure where you would want to trigger it.
you can wire your own click event listener on slideshow (prev/next) buttons - they will be added in addition to the existing ones.
in your event listeners, you can check css-class for whatever element you are interested in.
$(".prev").on("click", function() {
//user has explicitly clicked "prev"!!
});
$(".next").on("click", function() {
//user has explicitly clicked "next"!!
});

If else statement for javascript click event

I have two statements. What I am trying to do is when someone clicks on #area_a then hide then entire #area_b div without activating the focusout for the #area_b_textbox. But I've tried different code (which I am not including here because it is incorrect and want to get your suggestions) and what is happening is it is activating the focusout everytime I click on the #area_a div.
JQuery base actions
$("#area_a").click(function() { $("#area_b").hide(); });
$("#area_b_textbox").focusout(function() {$("#area_b_error").show();});
HTML:
<div id="area_a"></div>
<div id="area_b">
<input id="area_b_textbox">
<div id="area_b_error"></div>
</div>
Thanks!
You could hack around the problem with a timer. Timers usually smell bad but I think it is your safest bet here. If you try using hover or other mouse events you might run into trouble with keyboard navigation and activation or the lack of "hoverish" events on touch interfaces (and we can't pretend those don't exist anymore).
Something like this:
var timer_kludge = {
start: function(fn) {
this.id = setTimeout(fn, 200);
},
stop: function() {
if(this.id)
clearTimeout(this.id);
this.id = null;
},
id: null
};
$('#area_a').click(function() {
timer_kludge.stop();
$('#out').append('<p>click</p>');
});
$('#area_b_textbox').focusout(function() {
timer_kludge.start(function() {
$('#out').append('<p>textarea focusout</p>');
});
});
$('#area_b_textbox').focusin(function() {
timer_kludge.stop();
});
Demo: http://jsfiddle.net/ambiguous/s8kw8/1/
You'd want to play with the 200 timeout a bit to see what works best in your circumstances.
Why not just add a flag to ignore next focusout (blur?) event.
ignoreNextFocus = false;
$("#area_a").click(function() { ignoreNextFocus=true; $("#area_b").hide(); });
$("#area_b_textbox").focusout(function() { if(!ignoreNextFocus)$("#area_b_error").show();ignoreNextFocus=false;});
On that note setting the flag on click event might be too late. If it is the case, try mousedown event.
this is not possible since you loose the focus automatically when you click somewhere else...
What you need to do is to unbind the focusout event on hover of the #area_a and rebind it later on...
$("#area_a").click(function() {
$("#area_b").hide()
}),hover(
function(){
$("#area_b_textbox").unbind("focusout")
},
function(){
$("#area_b_textbox").focusout(function() {$("#area_b_error").show();});
}
)
PS: what is your ultimate goal here?
I'm not sure this is possible since by definition the focus has to leave the #area_b_textbox if the user is going to click a button.

jquery priority execution

Can anyone help me with this:
$('#n').click(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
$(this).blur(function() {
$(this).next().remove();
});
});
JS Fiddle demo; the problem is that the blur() event is executed before click() event.
You can use a timeout to postpone the removal for some milliseconds.
example : http://jsfiddle.net/vkun9/7/
$(this).blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
I also moved the blur attaching to be outside of the click handler, as it was adding an additional one each time the element was clicked, and changed the click handler to the focus to avoid multiple remove buttons from repeated clicking on the input, as #dheerosaur noted.
so
$('#n')
.focus(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
})
.blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
What you experience, though, is not a problem. It is the normal behaviour, as the element need to lose focus (fires the blur) before another element can have it.
You should also match the label for attribute with the id of the input element.
Use the outside events plugin and you can do something like this:
$('.input_field input').focus(function() {
var div = $(this).parent();
var link = $('delete').click(function(e) {
e.preventDefault();
alert('clicked');
}).appendTo(div);
$(this).data('delete', link);
}).bind('focusoutside clickoutside', function(e) {
var link = $(this).data('delete');
if (link && e.target != link[0]) {
link.remove();
}
});
First switch to using the focus event rather than the click event on your input field, some people actually use the keyboard to navigate through form fields ;-).
Then its creating the delete link, adding it to the page and storing a reference to it in on the input field.
Then with the outside event plugin we can bind focusoutside and clickoutside which get triggered when the user tabs or clicks outside the input field. By checking of the target of the event was the delete link or not we can tell if we should remove the link.
Example: http://jsfiddle.net/petersendidit/vkun9/6/
you can try setting a very short timeout in the blur event. this worked for me.
$(this).blur(function() {
setTimeout(function(){$(this).next().remove();}, 1);
});
Rather than using blur() I put together a hover()-based approach, though it does have a slightly clunky if/else statement:
$('.input_field').hover(
function(){
if ($(this).find('.delete').length) {
return false;
}
else {
$('delete')
.appendTo($(this));
}
},
function(){
if ($('#n').is(':focus')){
return false;
}
else {
$(this).find('.delete').remove();
}
}
);
JS Fiddle demo.
This approach does, however, ensure that there's only one delete link appended to the input_field (rather than the multiple links appended if the input is clicked multiple times in your original demo).

Categories