I want to write in Javascript a generic eventListener for any possible mouse event.
I am trying to write an eventListener that handles any mouse moves inside the webpage, presses of any kind, scrolling and everything that can be done using the mouse.
I didn't find a good way to do it, also because I need it to be done using pure Javascript without jQuery or any other libraries, just using simple DOM elements and function.
Can anyone show me how it is done by writing one good handler (and not a handler for each possible event)?
What you can do is add event listeners for all mouse events but use the same handler function. Something like this:
function bindEventsToSameHandler(element, events, handler) {
for(var i = 0; i < events.length; i++) {
element.addEventListener(events[i], handler);
}
}
// ...
// usage
var element = document.getElementById('selector'); // select the element on which to handle mouse events
var events = ['click', 'mouseup', 'mousedown']; // add mouse events you want to handle
bindEventsToSameHandler(element, events, function() {
// your handler code goes here
});
Note: this would work for any event, not just the ones related to the mouse.
Here's an example:
function bindEventsToSameHandler(element, events, handler) {
for(var i = 0; i < events.length; i++) {
element.addEventListener(events[i], handler);
}
}
// usage
element = document.getElementById('capture');
events = ['click', 'dblclick', 'mouseup', 'mousedown']; // add your events here
bindEventsToSameHandler(element, events, function(e) {
console.debug('handled ' + e.type);
});
#capture {
width: 100%;
height: 100%;
border: 1px solid black;
padding: 100px;
}
<body>
<p id='capture'>CAPTURE EVENTS BOX</p>
</body>
Related
my goal to this one is when u type the search bar will pop up the code below is working but i have a problem while typing into different input for example the comment input the js listen and open the search bar. is it possible when im already in a different input field the search will not pop up and show.
<style>
#searchBar { display: none; -webkit-transition: width 2s; /* Safari */ transition: width 2s;}
.search { width: 250px; height: 20px; }
</style>
<script>
window.onload = function() {
var listen = /^[a-z0-9]+$/i;
var searchInput = document.getElementById('searchInput');
var searchBar = document.getElementById('searchBar');
if ( window.addEventListener )
window.addEventListener( 'keyup', insertKey, false);
function insertKey( e ) {
// Get the character from e.keyCode
var key = String.fromCharCode( e.keyCode ).toLowerCase();
// Match the character
if( key.match(listen) ) {
// Change display: none; to display: block;
searchBar.style.display = "block";
// Append every new character
searchInput.value += key;
// Focus on input
searchInput.focus();
// Since you focused on the input you don't need to listen for keyup anymore.
window.removeEventListener( 'keyup', insertKey );
// I didn't tested with jQuery
// $('#searchBar').fadeIn();
// $('#searchBar input').append(keys);
// $('#searchBar input').focus();
}
}
};
</script>
When you add an event listener to window for the keyup event, it will trigger when a keyup is detected no matter where it originates from. You aren't being discriminatory enough about what events you're listening to.
One solution is to add the event listener directly to the input elements, so that a keyup from one element doesn't trigger another element's listener:
document.getElementById("searchInput").addEventListener("keyup", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("keyup", commentInputKeyHandler);
// etc.
This works but is a bit weird. If all you're doing is listening for a user typing in an input HTML element, then a better event to listen for is input which triggers whenever an input element has its value changed.
document.getElementById("searchInput").addEventListener("input", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("input", commentInputKeyHandler);
// etc.
Some elements can also listen for a change event; do some research and see what event is most appropriate for your use case.
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;
}
I'm trying to listen to focus / blur events on span with contenteditable=true attribute.
So here's what I tried (jQuery) :
$('.editable').on('focus',function(){
var that = $(this),
defaultTxt = that.data('default');
that.html('');
});
$('.editable').on('blur',function(){
var that = $(this),
defaultTxt = that.data('default');
if(that.html() === ''){
that.html(defaultTxt);
}
});
But he doesn't seem to work, because span doesn't handle focus / blur. How can I achieve that anyway (IE8 support needed) ?
There are two ways to achieve this effect.
Approach 1: focusin and focusout
$('.editable').on('focusin', function() {
// your code here
});
$('.editable').on('focusout', function() {
// your code here
});
focusin and focusout are like focus and blur events, but unlike the latter, they are fired on almost(?) every element, and also bubble. focusin and focusout are a part of DOM level 3 Specification. Firefox 51 and older didn't support this due to a known bug, but Firefox 52 and above have full support.
Approach 2: click and focus
This only works if you have other focusable elements around your span. What you do is basically use the focus event on any other element as a blur handler.
$('.editable').on('click', function() {
// your code here
});
$('*').on('focus', function() {
// handle blur here
// your code here
});
I wouldn't recommend this approach in a large webapp, because browser performance will take a hit.
I have created a demo for you:
$('.editable').bind('click', function(){
$(this).attr('contentEditable',true);
});
$('.editable').bind('focus', function() {
var that = $(this);
//defaultTxt = that.data('default');
that.html('');
});
$('.editable').bind('blur', function() {
var that = $(this);
var defaultTxt = that.data('default');
if(that.html() === ''){
that.html(defaultTxt);
}
});
.editable{
padding: 5px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<span class="editable" data-default="default">Some text</span>
I have changed your code, take a look it. Also now it's keeping the old value when lost the focus if you don't type anything.
While working with browser events, I've started incorporating Safari's touchEvents for mobile devices. I find that addEventListeners are stacking up with conditionals. This project can't use JQuery.
A standard event listener:
/* option 1 */
window.addEventListener('mousemove', this.mouseMoveHandler, false);
window.addEventListener('touchmove', this.mouseMoveHandler, false);
/* option 2, only enables the required event */
var isTouchEnabled = window.Touch || false;
window.addEventListener(isTouchEnabled ? 'touchmove' : 'mousemove', this.mouseMoveHandler, false);
JQuery's bind allows multiple events, like so:
$(window).bind('mousemove touchmove', function(e) {
//do something;
});
Is there a way to combine the two event listeners as in the JQuery example? ex:
window.addEventListener('mousemove touchmove', this.mouseMoveHandler, false);
Any suggestions or tips are appreciated!
Some compact syntax that achieves the desired result, POJS:
"mousemove touchmove".split(" ").forEach(function(e){
window.addEventListener(e,mouseMoveHandler,false);
});
In POJS, you add one listener at a time. It is not common to add the same listener for two different events on the same element. You could write your own small function to do the job, e.g.:
/* Add one or more listeners to an element
** #param {DOMElement} element - DOM element to add listeners to
** #param {string} eventNames - space separated list of event names, e.g. 'click change'
** #param {Function} listener - function to attach for each event as a listener
*/
function addListenerMulti(element, eventNames, listener) {
var events = eventNames.split(' ');
for (var i=0, iLen=events.length; i<iLen; i++) {
element.addEventListener(events[i], listener, false);
}
}
addListenerMulti(window, 'mousemove touchmove', function(){…});
Hopefully it shows the concept.
Edit 2016-02-25
Dalgard's comment caused me to revisit this. I guess adding the same listener for multiple events on the one element is more common now to cover the various interface types in use, and Isaac's answer offers a good use of built–in methods to reduce the code (though less code is, of itself, not necessarily a bonus). Extended with ECMAScript 2015 arrow functions gives:
function addListenerMulti(el, s, fn) {
s.split(' ').forEach(e => el.addEventListener(e, fn, false));
}
A similar strategy could add the same listener to multiple elements, but the need to do that might be an indicator for event delegation.
Cleaning up Isaac's answer:
['mousemove', 'touchmove'].forEach(function(e) {
window.addEventListener(e, mouseMoveHandler);
});
EDIT
ES6 helper function:
function addMultipleEventListener(element, events, handler) {
events.forEach(e => element.addEventListener(e, handler))
}
ES2015:
let el = document.getElementById("el");
let handler =()=> console.log("changed");
['change', 'keyup', 'cut'].forEach(event => el.addEventListener(event, handler));
For me; this code works fine and is the shortest code to handle multiple events with same (inline) functions.
var eventList = ["change", "keyup", "paste", "input", "propertychange", "..."];
for(event of eventList) {
element.addEventListener(event, function() {
// your function body...
console.log("you inserted things by paste or typing etc.");
});
}
I have a simpler solution for you:
window.onload = window.onresize = (event) => {
//Your Code Here
}
I've tested this an it works great, on the plus side it's compact and uncomplicated like the other examples here.
One way how to do it:
const troll = document.getElementById('troll');
['mousedown', 'mouseup'].forEach(type => {
if (type === 'mousedown') {
troll.addEventListener(type, () => console.log('Mouse is down'));
}
else if (type === 'mouseup') {
troll.addEventListener(type, () => console.log('Mouse is up'));
}
});
img {
width: 100px;
cursor: pointer;
}
<div id="troll">
<img src="http://images.mmorpg.com/features/7909/images/Troll.png" alt="Troll">
</div>
AddEventListener take a simple string that represents event.type. So You need to write a custom function to iterate over multiple events.
This is being handled in jQuery by using .split(" ") and then iterating over the list to set the eventListeners for each types.
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native events in IE.
eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = types.split(" ");
var type, i = 0, namespaces;
while ( (type = types[ i++ ]) ) { <-- iterates thru 1 by 1
You can also use prototypes to bind your custom function to all elements
Node.prototype.addEventListeners = function(eventNames, eventFunction){
for (eventName of eventNames.split(' '))
this.addEventListener(eventName, eventFunction);
}
Then use it
document.body.addEventListeners("mousedown touchdown", myFunction)
// BAD: One for each event - Repeat code
textarea.addEventListener('keypress', (event) => callPreview);
textarea.addEventListener('change', (event) => callPreview);
// GOOD: One run for multiple events
"keypress change".split(" ").forEach((eventName) => textarea.addEventListener(eventName, callPreview));
I want to show a menu after a click, drag, and release action.
How do I trigger that with jQuery?
Listen for a mousedown event on whatever should be clicked on.
Add a mousemove and mouseup event handler to the window
In the mouseup event handler call trigger('yourcustomeventhere') on whatever element you please. Also, remove the mouseup and mousemove event handlers from window
...?
profit.
jQuery is the library that will do this for you. I thought I explained the code well enough, but apparantly not:
$(anElement).mousedown(foodown);
function foodown(){
$(window).mousemove(foomove).mouseup(fooup);
//stuff
}
function foomove(){
//stuff
}
function fooup(){
$(someElement).trigger('yourcustomevent');
$(window).unbind('mousemove', foomove).unbind('mouseup', fooup);
}
/**
* Dragondrop jQuery plugin by zzzzBov
*/
(function ($) {
"use strict";
var $window;
function begin(e) {
var event;
$window.mousemove(drag).mouseup(end);
event = $.Event('beginDragon');
$(e.target).trigger(event);
if (event.isDefaultPrevented()) {
e.preventDefault();
}
}
function drag(e) {
var event;
event = $.Event('dragDragon');
$(e.target).trigger(event);
if (event.isDefaultPrevented()) {
e.preventDefault();
}
}
function end(e) {
var event;
event = $.Event('endDragon');
$(e.target).trigger(event);
$window.unbind('mousemove', drag).unbind('mouseup', end);
if (event.isDefaultPrevented()) {
e.preventDefault();
}
}
$.each('beginDragon dragDragon endDragon'.split(' '), function (i, name) {
$.fn[name] = function(data,fn) {
if (fn == null) {
fn = data;
data = null;
}
return arguments.length > 0 ?
this.bind(name, data, fn) :
this.trigger(name);
};
});
$window = $(window);
$window.mousedown(begin);
}(jQuery));
You could use the jQueryUI and let it do a lot for you. It also comes with a create UI (of course, because it's jQuery UI)
Take a look at this: http://jqueryui.com/demos/droppable/
edit:
Or take a look here: http://jqueryui.com/demos/draggable/
Take a close look to the events used here.
jQuery UI has a drag and drop implementation. If that doesn't do what you do, you'll have to roll your own implementation by tracking the mouseup and mousedown events on the element yourself. (And possibly mouseleave to detect if the mouse left the area you want to track the gesture in.)