Javascript keydown event twice to cancel - javascript

My intention is to make div when keydown, and remove div when the same key is pressed again.
This is my code.
let keydown = false;
document.addEventListener('keydown', function(e) {
if (e.code === 'Space') {
if (!keydown) {
keydown = true;
console.log("space")
e.preventDefault(); //space doesn't manipulate position
$("body").append($("<div id='refactor'></div>"))
$(refactor).append($(".highlight").text())
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
What should I do to remove the div when Space is hit again?

First of all...jquery...avoid this bloatware by all means, please...
Of course this is based on what you've asked here, but I'd recommend instead of store true/false for the pressed key, store the new div element instead. This way, you'll have instant access to it without need search in the DOM.
To remove a node from the DOM, you just need execute node.removeChild(child)
let div = null;
document.addEventListener('keydown', function(e) {
if (e.code === 'Space') {
console.log("space")
e.preventDefault(); //space doesn't manipulate position
if (div)
{
//remove div from DOM
div.parentNode.removeChild(div);
div = null;
}
else
{
//create new div
div = document.createElement("div");
div.id = "refactor";
div.textContent = document.querySelector(".highlight").textContent;
document.body.appendChild(div);
}
}
})
#refactor
{
background-color: lightgreen;
}
<div class="highlight">test</div>
If your whole goal is to show/hide an element, than you should do so via CSS instead of adding/removing elements from DOM, it's significantly faster and allows add additional animations/styles:
let div = document.getElementById("refactor");
document.addEventListener('keydown', function(e) {
if (e.code === 'Space') {
console.log("space")
e.preventDefault(); //space doesn't manipulate position
if (div.classList.contains("hidden"))
{
div.textContent = document.querySelector(".highlight").textContent + " " + Date();
}
div.classList.toggle("hidden");
}
})
#refactor
{
background-color: lightgreen;
transition: height 0.5s, width 0.5s, background-color 0.5s;
height: 1.5em;
width: 100%;
overflow: hidden;
}
#refactor.hidden
{
height: 0;
width: 0;
background-color: pink;
}
<div class="highlight">test</div>
<div id="refactor" class="hidden"></div>
<div>blah</div>

Related

How would I prevent redirecting of a href during touchmove and mousemove?

I've got an issue while I'm trying to combine touchstart and mousedown in 1 function. I've used an a tag as the target element of the function for going to the link directly when I touched or clicked the tag.
The issue is when I touch the middle of a tag, link doesn't respond. it only works when I click the element or touch the edge of the a tag, and the output fires mousedown.
In the mobile mode, try to click the edge of a tag as much as you would possible like a grey dot in the picture above. I've created an CodePen example for looking, testing and understanding better.
How would I fix this issue?
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
e.preventDefault();
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
return false;
}
apply() {
this.$el.bind('touchstart mousedown', (e) => this.start(e));
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'), {passive: false});
setSlider.apply();
a {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
<a id="anchor" href="https://google.co.uk">Tap or Click Me</a>
<p class="textbox"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
========= Progress Update ==========
I've just added move & end function then I have to click twice for moving on to the linked website. It keeps getting worse and have no idea how to solve this issue.
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
e.preventDefault();
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
this.$el.bind('touchmove mousemove', (e) => this.move(e));
this.$el.bind('touchend mouseup', (e) => this.end(e));
return false;
}
move(e) {
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
return false;
}
end(e) {
console.log('test');
this.$el.on('click');
this.$el.off('touchstart touchend');
return false;
}
apply() {
this.$el.bind('touchstart || mousedown', (e) => this.start(e));
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'));
setSlider.apply();
======== Progress Updated After Bounty (Latest) ========
After dozens of tried, I've finally figured out and solve the previous problem but I've faced up a new issue that can't draggable and redirecting instantly.
When I use the preventDefault in the start function, all of the events work fine. The only issue of this case is dragging doesn't prevent redirecting link from the a tag. It always send me to the website no matter which ways to call the functions, clicked or dragged.
when I don't use the preventDefault, dragging doesn't work. it only works clicking the elements.
My final goal is to prevent redirecting link of the a tag from the both events, touchmove and mousemove. I've been searched about on google so many times but haven't got any of the clues.
I've written an example in Codepen and this is what I've done so far:
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
var type = e.type;
if (type === 'touchstart') {
this.paragraph.text(this.paragraph.text() + ' ' + type);
} else if (type === 'mousedown') {
this.paragraph.text(this.paragraph.text() + ' ' + type);
}
}
move(e) {
var type = e.type;
}
end(e) {
var type = e.type;
if (type === 'touchend') {
console.log('touchstart enabled');
} else if (type === 'mouseup') {
console.log('mousedown enabled');
}
}
apply() {
this.$el.bind({
touchstart: (e) => this.start(e),
touchmove: (e) => this.move(e),
touchend: (e) => this.end(e),
mousedown:(e) => this.start(e),
onmousemove: (e) => this.move(e),
mouseup: (e) => this.end(e)
});
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'));
setSlider.apply();
a {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
<a id="anchor" href="https://google.co.uk">Tap or Click Me</a>
<p class="textbox"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I think I found the solution about this. I add this code for some people in the future who are trying hard to search the same problem such as me.
function start(event, etype, condition) {
console.log(etype); // track the type of event
if (!condition) event.preventDefault(); // compare etype(eventType). Set preventDefault if condition is falsy.
items.off('click');
items.on({
['touchmove mousemove']: (event) => move(event, etype, condition),
['touchend mouseup']: end
});
}
function move(event, etype, cnd) {
if (cnd) event.preventDefault();
console.log(cnd); // track the type of event from the condition
items.on('click', function(event) {event.preventDefault();});
}
function end(event) {
items.off('touchmove mousemove touchend mouseup');
}
var items = $('.item a');
items.on('touchstart mousedown', function() {
var eventType = event.type;
var condition = (eventType === 'touchstart' || eventType === 'mousedown');
start(event, eventType, condition);
});
#anchor {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
.item {
background-color: gray;
}
.item + .item {
margin-top: 10px;
}
.item a {
cursor: pointer;
display: inline-block;
background-color: blue;
color: white;
padding: 9px;
width: 100%;
height: 100%;
}
<div id="items" class="items">
<div class="item">
<a target="_blank" href="https://google.com">Anchor</a>
</div>
<div class="item">
<a target="_blank" href="https://google.com">Anchor</a>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
i think i figured out little solution for you. enable the preventDefault and afterwards enable the draggable for the a tag. Let me know if this works for you.
start(e) {
e.preventDefault();
...//rest of the code
apply() {
$el.draggable("enable");
...//rest of the code

Reset Dom element to initial state (jquery/javascript)

So i am trying to add a couple of css classes (red and shrink) on mouseover and mouseout. I have successfully done that but once I move my mouse out of the container or area of focus, the shrink class still remains.
How can I reset all classes back to the original state?
Here is the code i have so far:
var lis = $('.list');
lis.on('mouseover mouseout', changeColor);
function changeColor (e) {
$el = e.currentTarget;
if( e.type == 'mouseover') {
$el.classList.add('red');
$el.classList.remove('shrink');
} else if (e.type == 'mouseout'){
$el.classList.remove('red');
$el.classList.add('shrink');
}
else {
$el.classList.remove('red');
$el.classList.remove('shrink');
}
}
Thank you.
This might work.
var lis = $('.list');
lis.on('mouseover mouseout', changeColor);
function changeColor (e) {
$el = e.currentTarget;
if( e.type == 'mouseover') {
$el.classList.add('red');
$el.classList.remove('shrink');
} else if (e.type == 'mouseout'){
$el.classList="list";
}
}
.list
{
height:50px;
width:50px;
background:green;
}
.red
{
background : red;
}
.shrink
{
background:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="list"></div>
Refactored the code using pure jQuery. works as expected.
var lis = $('.list');
lis.hover(function(e){
e.preventDefault();
$(this).toggleClass('red')
.siblings(lis).toggleClass('shrink');
});

Make appended children to also trigger parent element

I have appended 2 buttons for each li element in my app:
todoLi.appendChild(this.createToggleButton());
todoLi.appendChild(this.createDeleteButton());
Later, I added event listeners to trigger when li is moused over and out
todosUl.addEventListener('mouseover', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi') {
elementMousedOver.lastElementChild.style.display = 'inline';
}
});
todosUl.addEventListener('mouseout', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi') {
elementMousedOver.lastElementChild.style.display = 'none';
}
});
Everything works fine for li element, but when I mouse over the buttons, that are children of the li element, event listeners stop working for some reason if the bottons were not children of li element after all.
How can I make appended children to also trigger its parent's event listener?
Here is my app on github: https://mikestepanov.github.io/
repo with files: https://github.com/mikestepanov/mikestepanov.github.io
Events by default are bubbling up the DOM, therefore the event triggered from the li will trigger the ul as well, the issue is that your if statement will handle only the cases in which the event's target is the ul (className == "todoLi")
var todosUl = document.getElementsByClassName("todo")[0];
todosUl.addEventListener('mouseover', function(event) {
let eOver = event.target;
if(eOver.className == 'todo') {
//for the ul
console.log("I'm handeled from " + eOver.className);
} else if (eOver.className == 'item') {
//for the li
console.log("I'm handeled from " + eOver.className);
}
});
todosUl.addEventListener('mouseout', function(event) {
let eOver = event.target;
if(eOver.className == 'todo') {
//for the ul
console.log("I'm handeled from " + eOver.className);
} else if (eOver.className == 'item') {
//for the li
console.log("I'm handeled from " + eOver.className);
}
});
ul{
padding: 15px;
background: lightblue;
}
li{
background: grey;
padding: 5px 5px;
}
<ul class="todo">
<li class="item">Do it!!</li>
</ul>
The problem here lies with the conditional statement. Simply modify your conditional statement to include the button element and it should work.
todosUl.addEventListener('mouseover', function(event) {
let elementMousedOver = event.target;
if(elementMousedOver.className == 'todoLi' ||
elementMousedOver.tagName === "BUTTON") {
elementMousedOver.lastElementChild.style.display = 'inline';
}
});

Click outside element without using event.stopPropagation

I know there are lots of ways to detect the click outside of an element. Mostly all of them use event.stopPropagation. Since event.stopPropagation will break other stuff, I was wondering if there is another way to achieve the same effect. I created a simple test for this:
HTML:
<div class="click">Click me</div>
Javascript:
$(function() {
var $click = $('.click'),
$html = $('html');
$click.on( 'click', function( e ) {
$click.addClass('is-clicked').text('Click outside');
// Wait for click outside
$html.on( 'click', clickOutside );
// Is there any other way except using .stopPropagation / return false
event.stopPropagation();
});
function clickOutside( e ) {
if ( $click.has( e.target ).length === 0 ) {
$click.removeClass('is-clicked').text('Click me');
// Remove event listener
$html.off( 'click', clickOutside );
}
}
});
http://jsfiddle.net/8p4jhvqn/
This works, but only because i stop the bubbling with event.stopPropagation();. How can i get rid of event.stopPropagation(); in this case?
It can be done in a simpler way, can't it be? Why complicate things when something as simple as below could work.
$(document).click(function(e){
var elm = $('.click');
if(elm[0] == e.target){
elm.addClass("is-clicked").text("click outside");
} else { elm.removeClass("is-clicked").text("click inside"); }
});
DEMO
You could do something like this to achieve the same effect
$(document).on("click", function(e){
var target = $(e.target);
if(target.hasClass("click")){
$click.addClass('is-clicked').text('Click outside');
}else{
$click.removeClass('is-clicked').text('Click me');
}
});
HTML code:
<div id="box" style="width:100px; height:100px; border:1px solid #000000; background-color:#00ff00;"></div>
JavaScript code:
function Init()
{
$(document).click(function(event){
if(event.target.id == "box")
{
$(event.target).css("backgroundColor", "#ff0000");
}
else
{
$("#box").css("backgroundColor", "#00ff00");
}
})
}
$(document).ready(Init);
If the element in question has child elements, then those may show up as e.target, and you can't simply compare it to your element.
In that case, capture the event in both the event and in the document, and detect events which only occurred on the document, for example by recording and comparing e.target:
var lastTarget = undefined;
$("#interesting-div").click(function(e) {
// remember target
lastTarget = e.target;
});
$(document).click(function(e) {
if (e.target != lastTarget) {
// if target is different, then this event didn't come from our
// interesting div.
// do something interesting here:
console.log("We got a click outside");
}
});
var lastTarget = undefined;
$("#interesting-div").click(function(e) {
// remember target
lastTarget = e.target;
});
$(document).click(function(e) {
if (e.target != lastTarget) {
// if target is different, then this event didn't come from our
// interesting div.
// do something interesting here:
console.log("We got a click outside");
}
});
#interesting-div {
background: #ff0;
border: 1px solid black;
padding: .5em;
}
#annoying-childelement {
background: #fa0;
border: 1px solid black;
margin: 1em;
padding: .5em;
width: 20em;
}
#large-div {
background: #ccc;
padding: 2em 2em 20em 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="large-div">
<div id="interesting-div">
This is our interesting element
<div id="annoying-childelement">
child element
</div>
</div>
</div>
</div>

event onmouseover : function launched many times when a <div> includes a <div>

I have a javascript event onmouseover which is linked to a <div> called div1. As soons as the mouse enter the <div>, it writes something into the console. Right.
If i include an other <div> called div2 into the first one, the problem is that the event will be launched at each time the mouse goes from the first into the second, without escaping from div1. The event should be launched only one time, when the mouse enters div1
The code is pretty simple and can be tested here (please open a js console and put your mouse between red and blue)
<html>
<head>
<style>
#div1{
position : absolute ;
top: 100px;
left: 100px;
width : 200px;
height : 200px;
background : red;
}
#div2{
position : absolute ;
top: 10px;
left: 10px;
width : 100px;
height : 100px;
background : blue;
}
</style>
</head>
<body>
<div id="div1" >
<div id="div2">
</div>
</div>
</body>
<script>
var div1 = document.getElementById('div1');
div1.onmouseover = function(){
console.log('Function launched!');
};
</script>
</html>
In my website, it sends an AJAX request at each event... so it involves to many data transfer.
Use next(), previous() methods or use nth-child or nth-of-type. Thanks and Good luck
Try this.
<script>
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
flag = 0;
div1.onmouseover = function(event){
if (event.target === this && flag == 0)
{
console.log('ok');
}
};
div1.onmouseout = function(event){
if (event.target === this)
{
flag = 0;
}
};
div2.onmouseover = function(event){
if (event.target === this)
{
flag = 1;
}
};
</script>
The above code will not allow to listen mouse over event of inner div.
Try to stop the event propagation by using stopPropagation().
function myEventHandler(e)
{
if (!e)
e = window.event;
//IE9 & Other Browsers
if (e.stopPropagation) {
e.stopPropagation();
}
//IE8 and Lower
else {
e.cancelBubble = true;
}
}

Categories

Resources