How to run doSomething() once when scrolling up or scrolling down?
window.onscroll = function(e) {
// scrolling up
if(this.oldScroll > this.scrollY){
doSomething();
// scrolling down
} else {
doSomething();
}
this.oldScroll = this.scrollY;
};
The doSomething() bind some elements and I don't want to do repeat binds. I Just want when on scrolling up, bind once and when on scrolling down bind once.
If you mean, your function should be executed once per each scroll event, then your code should do the job already.
However, if you mean you want your function to only be executed first time when the user scrolls, the code can look like this:
window.onscroll = function(e) {
if (this.oldScroll > this.scrollY) {
doSomething();
} else {
doSomethingElse();
}
this.oldScroll = this.scrollY;
delete window.onscroll;
};
Do NOT rely on any kind of "flag variables" as it is proposed above. It is a very bad practice in this scenario!
You can have an option of defining the closure function and using it in a way like described in this post
Apart from the above post I came across this situation and i used the following method to check if the event is already registered or not see below function where I needed to bind the click once only I used typeof $._data ( elementClose.get ( 0 ), 'events' ) === 'undefined' to get the events registered with the element, $._data is used to retrieve event handlers registered to an element/
this.closeButtonPreview = () => {
let elementClose = $("a.close-preview");
if (typeof $._data(elementClose.get(0), 'events') === 'undefined') {
elementClose.on('click', function(e) {
e.preventDefault();
let container = $(this).parent();
container.find('video').remove();
$("#overlay,.window").effect("explode", {}, 500);
});
}
return;
};
EDIT
Just to get the concept clear for you about the logic I used with $._data(). i created an example below.
What i am doing is binding event click to anchor with id=unique inside the condition if (typeof $._data(uniqueBind.get(0), 'events') == 'undefined') { which determines if an event is assigned to the element and binding the event click to the anchor id=multi outside the condition without checking binded events on the element.
What you have to do.
Initially the button unique and multi won't log anything to console, click on EVENT BINDER once and then click on both unique and mutli they both will log text once in console, but as you keep clicking on the EVENT BINDER notice that clicking the multi button will start logging the text as many times as you have clicked the EVENT BINDER button but the unique button will only log once no matter how many times you click on the EVENT BINDER button.
$(document).ready(function() {
$('#binder').on('click', bindEvents);
$('#clear').on('click', function() {
console.clear();
})
});
function bindEvents() {
var uniqueBind = $('#unique-bind');
var multiBind = $('#multi-bind');
//will bind only once as many times you click on the EVENT BINDER BUTTON
//check if any event is assigned to the element
if (typeof $._data(uniqueBind.get(0), 'events') == 'undefined') {
uniqueBind.on('click', function() {
console.log('clicked unique bind');
});
}
//will log the text EVENT BINDER * TIMES_EVENT_BINDER_CLICKED button
multiBind.on('click', function() {
console.log('clicked multi bind');
});
}
body {
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
EVENT BINDER
CLEAR CONSOLE
<br /><br /><br /><br />
UNIQUE
MULTI
Related
I have input element which will take input and filter the contents and the filter event will be trigger once the user gets focused out from the input element.
When the user having the focus in the input element and he clicks in one of the button, the click event is invoked first and then the focus out event, as it creates conflicts while generating the filtered content.
I tried changing the order of code and other options such as changing the way of invocation of the click event - none of the ways worked out for me
$('body').on('focusout', '.classname', functionname);
function functionname(e) {
if (typeof e == 'object') {
}
}
$('body').on('click', '.buttonclass', function (e) {});
Could someone help me to build The FocusOut event to trigger first and then the click event.
Based on the current conditions, you have to - inside the click handler - retrieve the validation result, and based on that result, decide if button submission should or should not occur.
JS Code:
$("#input").focusout(function(){
var that = this;
valid = this.value.length ? true : false;
!valid && window.setTimeout(function() {
$(that).focus();
}, 0);
});
$("#button").click(function(e) {
if ( !valid ) { return false; }
e.preventDefault();
alert('execute your filter)');
});
I have the following code:
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
The problem with the above is when I click myButton both events are triggered and triggerProcess() is fired twice which is not desired.
I only need triggerProcess() to fire once. How can I do that?
Small demo
You can have a static flag that disables any more triggers once the first trigger has occurred. Might look something like this:
var hasTriggered = false;
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
function triggerProcess () {
// If this process has already been triggered,
// don't execute the function
if (hasTriggered) return;
// Set the flag to signal that we've already triggered
hasTriggered = true;
// ...
}
For resetting the hasTriggered flag, that's entirely up to you and how this program works. Maybe after a certain event occurring in the program you'd want to reenable the ability to trigger this event again — all you'd need to do it set the hasTriggered flag back to true.
You can use the mousedown event, which will fire before the input is blurred, and then check if the input has focus by checking if it's the activeElement, and if it does have focus, don't fire the mousedown event, as the change event will fire instead.
Additionally, if you want a mousedown event to occur when the value hasn't changed, and the change event doesn't fire, you'll need a check for that as well
var myInput = $('#test1'),
myButton = $('#test2'),
i = 0;
myInput.change(function(e) { // this triggers first
$(this).data('prev', this.value);
triggerProcess();
});
myButton.mousedown(function(e) { // this triggers second
var inp = myInput.get(0);
if (document.activeElement !== inp || inp.value === myInput.data('prev'))
triggerProcess();
});
function triggerProcess() {
console.log('triggered : ' + (++i))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="test1">
<br />
<br />
<button id="test2">
Click
</button>
In a fairly typical scenario where you have an input with a button next to ie, eg quick search.
You want to fire when the input changes (ie onblur) but also if the user clicks the button.
In the case where the user changes the input then clicks the button without changing input focus (ie no blur), the change event fires because the text has changed and the click event fires because the button has been clicked.
One option is to debounce the desired event handler.
You can use a plugin or a simple setTimeout/clearTimeout, eg:
$('#inp').change(debounceProcess)
$('#btn').click(debounceProcess);
function debounceProcess() {
if (debounceProcess.timeout != null)
clearTimeout(debounceProcess.timeout);
debounceProcess.timeout = setTimeout(triggerProcess, 100)
}
function triggerProcess() {
console.log('process')
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="inp">
<button id="btn">Click</button>
Use a real <button>BUTTON</button>. If you click on input text, alert is triggered, then once you leave the input text to click anywhere else, that unfocuses the input text which triggers the change event, so now 2 events have been triggered from the text input.
This is an assumption since the code provided is far from sufficient to give a complete and accurate answer. The HTML is needed as well as more jQuery/JavaScript. What is myInput and myButton actually referring to, etc.?
So I bet if you change...
var myButton = $('{whatever this is}'); and <input type='button'>
...TO:
var myButton = $("button"); and <button></button>
...you should no longer have an event trigger twice for an element.
This is assuming that triggerProcess() is a function that does something that doesn't manipulate the event chain or anything else involving events. This is an entirely different ballgame if instead of click() and change() methods you are using .trigger() or triggerHandler(), but it isn't. I'm not certain why such complex answers are derived from a question with very little info...?
BTW, if myInput is a search box and myButton is the button for myInput, as freedomn-m has mentioned, simply remove:
myButton.click(...
Leave myButton as a dummy. The change event is sufficient in that circumstance.
SNIPPET
var xInput = $('input');
var xButton = $('button'); //«———Add
xInput.on('change', alarm);
xInput.on('click', alarm);
xButton.on('click', alarm);
function alarm() {
return alert('Activated')
}
/* For demo it's not required */
[type='text'] {
width: 5ex;
}
b {
font-size: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id='f1' name='f1'>
<input type='text'>
<input type='button' value='BUTTON TYPE'>
<label><b>⇦</b>Remove this button</label>
<button>BUTTON TAG</button>
<label><b>⇦</b>Replace it with this button</label>
</form>
I have a listener which runs when I click on document.
document.addEventListener('click', print);
function print(element)
{
doSomething();
}
It creates div id=panel, where I print some information.
When I run the print function I would like to detect whether I clicked outside of the div#panel (The panel exists when I click second time).
I wish not to use the mouseout event listener because I think it is redundant to use listener for mouse movements when the event click is already fired.
How to detect when I clicked out of div#panel?
You can check the target of jQuery's click event, which element it was:
$(document).click(function(e) {
var target = $(e.target);
if( !target.is("#panel") && target.closest("#panel").length === 0 ) {
// click was not on or inside #panel
}
});
Your event handler gets passed an event object, not an element. Since you are listening for the click event, the event will be of type MouseEvent and that event object will have a target property which you can use to check if the target element matches your desired element.
function handler(event) {
if (event.target == document.getElementById("panel")) {
// Do stuff
}
}
document.addEventListener('click', handler);
Edit: I intentionally gave the vanilla JS answer since your own code fragments don't use jQuery. But jQuery wouldn't change anything as its event handling API is almost just a thin wrapper over JS.
I am just using event from the click. Here it is
var elem=document.getElementById("elem");
var rects=elem.getBoundingClientRect();//get the bounds of the element
document.addEventListener('click', print);
function print(e)
{
//check if click position is inside or outside target element
if(e.pageX<= rects.left +rects.width && e.pageX>= rects.left && e.pageY<= rects.top +rects.height && e.pageY>= rects.top){
console.log("Inside element");
}
else{
console.log("Outside element");
}
}
JS Bin link : https://jsbin.com/pepilehigo/edit?html,js,console,output
A different approach, using only javascript is:
function print(evt) {
if (!(evt.target.tagName == 'DIV' && evt.target.classList.contains('myDiv'))) {
var div = document.createElement('div');
div.classList.add('myDiv');
div.textContent="new div";
document.body.appendChild(div);
}
}
window.onload = function() {
document.addEventListener('click', print);
}
.myDiv {
border:1px solid green;
}
1 - I've gat an html tag with data-needlogged attribute.
2 - I would like to disable all click events on it.
3 - When the user click on my element, I want to display the authentification popin.
4 - When the user will be logged, I would like to launch the event than I disabled before.
I try something like the following code but it miss the "...?" part.
Play
<script>
// 1 - some click events has been plug on the tag.
jQuery('[data-btnplay]').on('click', function() {
alert('play');
return false;
});
// 2 - disabled all click events
jQuery('[data-needlogged]').off('click');
// 3 - Add the click event to display the identification popin
var previousElementClicked = false;
jQuery('body').on('click.needlogged', '[data-needlogged]="true"', function() {
previousElementClicked = jQuery(this);
alert('show the identification popin');
return false;
});
jQuery(document).on('loginSuccess', function() {
// 4 - on loginSuccess, I need to remove the "the show the identification popin" event. So, set the data-needlogged to false
jQuery('[data-needlogged]')
.data('needlogged', 'false')
.attr('data-needlogged', 'false');
// 4 - enable the the initial clicks event than we disabled before (see point 2) and execute then.
// ...?
jQuery('[data-needlogged]').on('click'); // It doesn't work
if (previousElementClicked) {
previousElementClicked.get(0).click();
}
});
</script>
Thanks for your help
Thank for your answer.
It doesn't answer to my problem.
I will try to explain better.
When I declare the click event on needlogged element, I don't know if there is already others click event on it. So, in your example how you replace the alert('play'); by the initial event ?
I need to find a way to
1 - disable all click events on an element.
2 - add a click event on the same element
3 - and when a trigger is launch, execute the events than I disabled before.
So, I found the solution on this stackoverflow
In my case, I don't realy need to disable and enable some event but I need to set a click event before the other.
Play
<script>
// 1 - some click events has been plug on the tag.
jQuery('[data-btnplay]').on('click', function() {
alert('play');
return false;
});
// [name] is the name of the event "click", "mouseover", ..
// same as you'd pass it to bind()
// [fn] is the handler function
jQuery.fn.bindFirst = function(name, fn) {
// bind as you normally would
// don't want to miss out on any jQuery magic
this.on(name, fn);
// Thanks to a comment by #Martin, adding support for
// namespaced events too.
this.each(function() {
var handlers = $._data(this, 'events')[name.split('.')[0]];
// take out the handler we just inserted from the end
var handler = handlers.pop();
// move it at the beginning
handlers.splice(0, 0, handler);
});
};
var previousElementClicked = false;
// set the needlogged as first click event
jQuery('[data-needlogged]').bindFirst('click', function(event) {
//if the user is logged, execute the other click event
if (userIsConnected()) {
return true;
}
//save the click element into a variable to execute it after login success
previousElementClicked = jQuery(this);
//show sreenset
jQuery(document).trigger('show-identification-popin');
//stop all other event
event.stopImmediatePropagation();
return false;
});
jQuery(document).on('loginSuccess', function() {
if (userIsConnected() && lastClickedElement && lastClickedElement.get(0)) {
// if the user has connected with success, execute the click on the element who has been save before
lastClickedElement.get(0).click();
}
});
I'm trying to write a web app which replaces the context menu (right-click menu) with my own customized ones. I want it so that when the user clicks on a table row, they get one certain context menu and when they click on the background of the page, they get a different one.
I have already written the menus and gotten them working. The problem comes in when trying to figure out how to get the background's menu to show ONLY when clicking on the background and how to get the table row's menu to show when that is clicked.
I tried using document.body.oncontextmenu for the body and and setting the oncontextmenu function for each table row, but the body's oncontextmenu function overrides the row's so I get the wrong menu. The menu for the table rows DOES work if I stop using the body's menu, so that's not the issue.
I could be using the wrong events, so is there a different event for just the background (and not the elements on top of the background)? Or a way to "prioritize" the events so the table row's function takes precedence?
This is how the code looks:
var tableMenu;
var bodyMenu;
window.onload = function()
{
bodyMenu = new rightClickMenu("bodyMenu");
document.body.oncontextmenu = function() { bodyMenu.show(); tableMenu.hide(); }
bodyMenu.add("Add Entry", function()
{
alert("ADD");
});
tableMenu = new rightClickMenu("tableMenu", "tblSims");
simRows = getElementsByClassName("trSimRow");
for (var i in simRows)
simRows[i].oncontextmenu = function() { tableMenu.show(this.id.substring(2)); bodyMenu.hide(); }
tableMenu.add("Delete Entry", function(mac)
{
alert("DELETE");
});
document.body.onclick = function()
{
bodyMenu.hide();
tableMenu.hide();
};
}
You can capture the target element, e.g.:
$('*').click(function(e) {
alert(e.target);
alert(e.target.tagName);
if(e.target.tagName == 'html') {
// show background menu
}
});
You have to work with the Javascript Event Propagation model. What happens is that your click event is automatically passed down the layers of objects on a page that have been registered as event listeners, unless you explicitly tell it to stop, try something like this:
function setupClickHandlers()
{
document.getElementsByTagName('body')[0].onclick = doBodyMenu;
document.getElementById('tableID').onclick = doTableMenu;
}
function doBodyMenu()
{
//do whatever it does
}
function doTableMenu(e)
{
//do whatever it does
//stop the event propagating to the body element
var evt = e ? e : window.event;
if (evt.stopPropagation) {evt.stopPropagation();}
else {evt.cancelBubble=true;}
return false;
}
This should deal with the way each browser handles events.
$( document ).ready(function() {
var childClicked = false;
// myContainer is the nearest container div to the clickable elements
$("#myContainer").children().click(function(e) {
console.log('in element');
childClicked = true;
});
$("#myContainer").click(function(e){
if(!childClicked) {
console.log('in background');
e.preventDefault();
e.stopPropagation();
}
childClicked = false;
});
});
#myContainer {
width:200px;
height:200px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myContainer" style="">
link
<div style="width:50px;height:50px;background-color: white;">
another link
</div>
</div>