I am using Tristen Brown's hoverintent library, which is a pure Javascript version of the jQuery hoverIntent library.
I have two elements first and second.
The second element has hoverintent handlers which causes a tooltip to appear above that element. When I manually hover over second, the tooltip appears as expected.
I would like to trigger the tooltip of second programmatically. For example, to make interacting with the first element cause the tooltip of the second element to appear. I have attempted to do this using jQuery trigger. I am able to trigger mouseover handlers, but not any hoverIntent.
Any suggestions?
Here is my Javascript:
$( document ).ready(function() {
var first = document.getElementById('first');
var second = document.getElementById('second');
$(first).mouseover(function(){
$(second).trigger({ type:"mouseover", clientX:"350", clientY:"105" });
$(second).trigger({ type:"mousemove", clientX:"350", clientY:"105" });
});
hoverintent(second, function(e) {
this.className = 'on';
}, function(e) {
this.className = 'off';
});
$(second).mouseover(function(){
console.log("mouseover");
});
});
Here is my HTML:
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src='http://tristen.ca/hoverintent/dist/hoverintent.min.js'></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div style="padding:100px;">
<ul class='examples'>
<li id='first'>
Trigger
</li>
<li id='second'>
hoverintent
<span class='popup'>Hi there</span>
</li>
</ul>
</div>
</body>
</html>
The full JS bin is here:
http://jsbin.com/kumeva/4/edit?js,output
I would like to trigger the tooltip of second by mousing over the first element.
You can dispatch a sequence of mouse events to #second and keep the hoverintent code and the dispatch code completely separate like this:
// Hoverintent code
$(document).ready(function() {
var second = document.getElementById('second');
hoverintent(second, function(e) {
this.className = 'on';
}, function(e) {
this.className = 'off';
});
});
///////////////////////////////////
// Dispatch code
$(document).ready(function() {
var first = document.getElementById('first');
var second = document.getElementById('second');
$(first).on("mouseover", function(){
// Send a mouseover to wake hoverintent
var event = new MouseEvent("mouseover");
second.dispatchEvent(event);
// Send a mousemove trigger the internal hover code
event = new MouseEvent("mousemove");
second.dispatchEvent(event);
});
$(first).on("mouseout", function(){
// Cancel the hover code
var event = new MouseEvent("mouseout");
second.dispatchEvent(event);
});
});
Demo
According to the source code of the librairy, it seam that it rely on mouseover and mouseout. To determine the mouse position, it seam to use clientX and clientY, not pageX/Y.
Source file : https://github.com/tristen/hoverintent/blob/gh-pages/index.js
Related
I have this piece of code
window.onload = function () {
$('#btnFilter').click(function (e) {
btnFilter(e);
});
}
The function works on button click but I need that the button is clicked when the page opens. I've tried things like $('#btnFilter').trigger( "click" ); but the button still not clicked on page opening. How can I achieve this thing? I can't just call the function because I get the error "Cannot read property 'currentTarget' of undefined" beacuse I don't give any event as parameter.
function btnFilter(e) {
element = e.currentTarget.parentElement;
//other code
}
You can try like this:
$(document).ready(function(){
$('#btnFilter').trigger('click');
});
$(document).on('click','#btnFilter',function(e){
btnFilter(e);
});
function btnFilter(e)
{
element = e.currentTarget.parentElement;
}
You can change your 'btnFilter' to accept the button instead of the event:
function btnFilter(element) {
element = element.parentElement;
...
}
$(function() {
$("#btnFilter").click(function(e) { btnFilter(this); return false; });
// Pass the button to the filter operation on load
btnFilter($("#btnFilter")[0]);
});
alternatively, accept the parent element directly
$(function() {
$("#btnFilter").click(function(e) { btnFilter(this.parentElement); return false; });
// Pass the button parent to the filter operation on load
btnFilter($("#btnFilter")[0].parentElement);
});
If you use jquery i would keep it coherent and not mix it with vanilla javascript. A Jquery solution is:
$(document).on("click", "#btnFilter", btnFilter);
$(document).ready(function(){$("#btnFilter").click()});
or
$(document).on("click", "#btnFilter", btnFilter);
$(document).ready(btnFilter);
In you solution the error is the event binding: when you bind the event to #btnFilter on page load, the element is not existing yet, so the function cannot be triggered.
jQuery Solution:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").trigger("click");
});
</script>
</head>
<body>
<button onclick="alert('clicked')">Click</button>
</body>
</html>
I have begun to learn JavaScript. I have tried the following to drag and drop an image into a dropzone called "dropTarget1"; the image is not draggable. Can you please take a look at my code and advise what I am doing wrong.
var draggable=document.getElementById('dragMe1');
draggable.addEventListener('dragstart',dragStart,false);
var droptarget=document.getElementById("dropTarget1");
droptarget.addEventListener('dragenter',dragEnter,false);
droptarget.addEventListener('dragover',dragOver,false);
droptarget.addEventListener('dragleave',dragLeave,false);
droptarget.addEventListener('drop',drop,false);
function dragStart(event){
event.dataTransfer.setData('text/html', event.currentTarget.id);
}
function dragOver(event) {
event.preventDefault();
return false;
}
function drop(event) {
var dragMe1=document.createElement("img");
var data = event.dataTransfer.getData('text/html');
event.preventDefault();
event.stopPropagation();
dragMe1.src=data;
droptarget.appendChild('dragMe1');
return false;
}
#dropTarget1{
width:300px;
height:300px;
background-color:#DBF272;
}
#dragMe1{
width:300px;
}
#dragMe1 img{
padding-left:45px;
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
<link href="myStyle.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="dropTarget1"></div>
<img id="dragMe1" src="logo1.png" draggable="true" >
<script src="myDragnDrop.js"> </script>
</body>
</html>
If you want to use jQuery, then this Draggable|jquery UI can be a really simlple option.
Your JavaScript code should be like this (Explanation in the comments);
var draggable=document.getElementById('dragMe1');
var droptarget=document.getElementById("dropTarget1");
var newIm = document.createElement("img"); //Create new image element
/*Subscribe to dragover event.
This event fires when a user drag the image over the target */
droptarget.addEventListener('dragover',dragOver,false);
/*Subscribe to drop event.
This event fires when a user drop the image on the target */
droptarget.addEventListener('drop',drop,false);
function dragOver(event) {
event.stopPropagation(); //Prevent further drop events from bubbling up the DOM tree
event.preventDefault(); //Prevent the default behavior of the browser when dropping something on it
event.dataTransfer.dropEffect = "move"; //Specify the feedback that the user receives when a user drags over the target. It can be copy, link, or none
return false;
}
function drop(event) {
var data = event.dataTransfer.getData('text/plain'); //To retrieve the image URL
event.preventDefault();
event.stopPropagation();
newIm.src=data; //Write the image URL into the src attribute of newIm
droptarget.appendChild(newIm); //Add the new created image to the target element
document.body.removeChild(draggable); //Remove the original image as you're dragging and dropping (moving)
return false;
}
You don't have to subscribe to some events like dragenter, you just need to subscribe to dragover and drop events.
I am trying to make the image of the mole clickable and once clicked will increase the score but the .on() will not work with the class name of the image. It will, however, work if I use the selector "#gamespace", but then clicking anywhere within the game space will get the player points rather than just clicking the mole.
<!DOCTYPE html>
<html>
<head>
<title>Whack-A-Mole (CSCI2447)</title>
<!-- CSS styles: This is for me to worry about; not you. -->
<link href="css/game.css" rel="stylesheet" />
<script src="js/jquery-2.2.1.min.js"></script>
<script type="text/javascript">
var score = 0
var time = 30
var t;
var moleRepeat;
$(document).ready(function(){
$('#start_button').click(function (){
start();
});
$('.mole').on('click' , function () {
counter();
});
});
function getYRandomNumber(){
return Math.floor((Math.random()*300)+0);
};
function getXRandomNumber(){
return Math.floor((Math.random()*600)+0);
};
function counter() {
score++;
$("#score").html(score + ' pts');
};
function start() {
$('#timer').show();
addMole();
decrement();
$('h1').css("color","purple");
$('#gamespace').css("background-color", "green");
};
function decrement() {
time--;
$('#timer').html(time + ' seconds left');
t = setTimeout('decrement()', 1000);
};
function addMole() {
$('#gamespace').append('<img class="mole" src="img/mole.png" onClick="counter()"/>');
moleRepeat = setTimeout('addMole()', 2000);
};
</script>
</head>
<body>
<div id="content">
<h1>Whack-A-Mole</h1>
<p>After clicking "start", you will have 30 seconds to click
as many moles as you can. The moles appear randomly so be ready! </p>
<div id="controls">
<span id="score">0 pts</span>
<button type="button" id="start_button">Start!</button>
</div>
<div id="timer">30 seconds left</div>
<div id="gamespace">
</div>
</div>
</body>
</html>
You are adding click event handler on .mole before it is appended to #gamespace and exist on the page, use event delegation instead
$('#gamespace').on('click','.mole' ,function () {
counter();
});
It looks like your trying to bind to the click event of '.mole' before any exist. Direct bindings only work for elements that already exist in the DOM. You could fix this by doing a delegate binding.
$('#content').on('click', '.mole', function(){ ... });
This will make it listen for the bubbled events from mole elements. Since it works with the bubbled events, it does not matter when they are created.
This is my page which contains both HTML and Javascript code. No matter how I set the initial value of the ID, it only works once. Which I find very strange!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!--<meta http-equiv="refresh" content="30" />-->
<title>Relay Trigger</title>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js></script>
</head>
<body>
<div id="button">
<button id="off">OFF</button>
</div>
<script type="text/javascript">
$(document).ready(function(){
$("#on").click(function(){
document.getElementById("on").innerHTML="OFF";
document.getElementById("on").id="off";
alert(document.getElementById("button").innerHTML)
});
$("#off").click(function(){
document.getElementById("off").innerHTML="ON";
document.getElementById("off").id="on";
alert(document.getElementById("button").innerHTML)
});
})
</script>
</body>
</html>
When you use $("#on").click(function(){/*...*/}, there isn't any element with id on.
Then, that event handler isn't attached.
Moreover, when you use $("#off").click(function(){/*...*/}, you add the event handler to the element that, in that moment, has the id off. It doesn't matter if the id changes, the element is still the same and still has the same event handler.
To get the functionality you want, you can use event delegation to an ancestor with a filtering selector:
$("#button")
.on('click', '#on', function(){
document.getElementById("on").innerHTML="OFF";
document.getElementById("on").id="off";
alert(document.getElementById("button").innerHTML)
})
.on('click', '#off', function(){
document.getElementById("off").innerHTML="ON";
document.getElementById("off").id="on";
alert(document.getElementById("button").innerHTML)
});
Note this can be several times slower.
But a better alternative would be using id="myButton" data-state="off", and
$('#myButton').on('click', function() {
var state = $(this).data('state');
$(this).data('state', state==='on' ? 'off' : 'on');
state = state.toUpperCase();
$(this).html(state);
alert(state);
});
Try using a class instead, ID's should not be used like this.
The reason it happens is because when you registered the event handlers - the #on actually did nothing because there was no #on element in the document in that time
You have 2 options here:
set the handler only after you change the id:
<script type="text/javascript">
$(document).ready(function(){
$("#off").click(function(){
document.getElementById("off").innerHTML="ON";
document.getElementById("off").id="on";
alert(document.getElementById("button").innerHTML)
$("#on").click(function(){
document.getElementById("on").innerHTML="OFF";
document.getElementById("on").id="off";
alert(document.getElementById("button").innerHTML)
});
});
})
use "live" behavior:
the live function of jQuery is deprecated - but you can do it by doing:
instead of
$("#on").click(function);
write
$(document).on("click","#on",function);
You're missing a " in your script src.
All you need is
LIVE DEMO
$(function(){ // DOM ready
$("#on, #off").click(function(){
var io = this.io ^= 1; // Toggler used as 1/0 boolean
$(this).text(io?"ON":"OFF").prop('id', io?"on":"off");
});
});
So inside this simple click function if you need to do more stuff depending on the stored io object value you can do:
PLAYGROUND
if(io){
// do additional stuff if "on"
}else{
// do additional stuff if "off"
}
I have a text input that I would like to, when it has focus, register a click event anywhere on the body. But when focus is removed from it, that click event is removed from the body. Sadly, I seem not to be able to suss it.
$(document).ready(function () {
$("html").on("focus", "#asdf", function () {
$("body").on("click", "*:not(#asdf)", wasItClicked);
});
$("html").on("blur", "#asdf", function () {
$("body").off("click", "*", wasItClicked);
});
});
function wasItClicked() {
alert("yeah");
}
BIN
Thanks for any help.
When #asdf is focused, and some other element is clicked, The events fire in order mousedown, blur, mouseup, click. So the handler has been removed before click fires.
The mousedown event fires before blur. If you are OK with mousedown instead of click, you could use this:
$(document).ready(function () {
$("#asdf").on("focus", function () {
$("body").on("mousedown", wasItClicked);
});
$("#asdf").on("blur", function () {
$("body").off("mousedown", wasItClicked);
});
});
(bin)
Edit:
You could use the mousedown event to help determine if you are losing focus because of a click, and remove the handler in the click handler if have lost focus.
$(document).ready(function () {
$("#asdf").on("focus",function() {
$("body").on("mousedown", setDown);
$("body").on("click", wasItClicked);
});
$("#asdf").on("blur", function() {
if ($(this).attr("mouse") != "down") {
$("body").off("mousedown", setDown);
$("body").off("click", wasItClicked);
}
});
});
function setDown() {
$("#asdf").attr("mouse","down");
}
function wasItClicked() {
if ($("#asdf") != $(document.activeElement)) {
$("body").off("mousedown", setDown);
$("body").off("click", wasItClicked);
}
$("#asdf").attr("mouse","up");
alert("yeah");
}
new bin
You could use setTimeout to remove the click and use namespaces when adding and removing events because you may accidentally remove another click handler but the simplest way would be to remove the click event in the handler:
...
$("body").on("click.fromasf", "*:not(#asdf)", wasItClicked);
...
function wasItClicked() {
$("body").off("click.fromasf");
console.log("yeah");
}
Here is an example using timeout:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-1.9.0.js"></script>
<style>
</style>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>Example</title>
</head>
<body>
<input type="text" id="asdf" />
<input type="text" id="Text1" />
<script>
$(document).ready(function () {
$("html").on("focus", "#asdf", function () {
console.log("adding click handler");
$("body").on("click.fromasf", "*:not(#asdf)", wasItClicked);
});
$("html").on("blur", "#asdf", function () {
setTimeout(function () {
console.log("remove click");
$("body").off("click.fromasf");
}, 500);
});
});
function wasItClicked() {
console.log("yeah");
}
</script>
</body>
</html>
Ok, I see a couple of issues...
You're delegating a focus event to the HTML element for an event on
a single element... That's a bit of overkill, so I would put the
focus and blur events directly on the input
When you call off, you need to pass it the exact same selector in the second parameter
Your click event is delegated to the body, and firing on any child element that is clicked and matches the selector - this does not include the body itself... not sure if you wanted it that way, but I moved it up to the html element, to include the body
As soon as the input loses focus, the event will be removed, so the clicks won't register (You can use a timeout as #HMR suggested in their answer)
I had some problems with the delegation on the html element that was still returning the input (despite the :not(#asdf) selector) so I just put the filter into the function.
Here is the revised code (testing version):
var click_selector = ":not(#asdf)";
var click_target = 'html';
$(document).ready(function () {
$("#asdf").on("focus", function () {
$(click_target).on("click", click_selector, wasItClicked);
});
$("#asdf").on("blur", function () {
// Use timeout to be able to register the click before function is removed
// NOTE that since 'click' fires when the mouse is released, if they
// hold the mouse down for a while, the event will be gone and won't
// register. Maybe better to use 'mousedown' instead of 'click'
// in which case the timeout could probably be reduced to 10ms or something
// Also, using timeouts creates the possibility of multiple click handlers
// present at the same time (new one added before the previous is removed)
setTimeout( function(){
$(click_target).off("click", click_selector, wasItClicked);
}, 100);
});
});
function wasItClicked(e) {
e.stopPropagation();
e.preventDefault();
if( e.target.id !== 'asdf' ){
console.log('yeah', click_target, click_selector);
}
}