Onmousedown doesn't trickle down - javascript

In my html I have
<div id="map"></div>
#map {
width: 100%;
height: 100%;
background-color: #CCC;
}
that gets dynamically filled with several divs like the following
<div class="basicTiles1" style="left: 8128px; top: 8128px;"></div>
.basictiles1 {
position: absolute;
width: 64px;
height: 64px;
background-image: url(<snip urlToPng>);
background-position: 0px 0px;
}
Then an onmousedown event is added to #map like so
$('#map').on('mousedown', function(){console.log("mousedown");});
The event is never triggered. If I don't add the tiles to the map, it works.
I tried doing it with jquery's 'on', 'onmousedown', javascripts 'addEventListener'.
The script doesn't have any compilation errors. The event just doesn't seem to trickle down.
Is it because the tiles are position absolute? Is it because they are added dynamically?

I understand that when you bind the event, the DIV's are not there yet. Try using delegate instead, like this:
$("#map").delegate("div", "mousedown", function() {
console.log("mousedown");
});
EDIT: Elaborating
The jQuery .on() reference states: "Attach an event handler function for one or more events to the selected elements."
Moreover, when you bind the event directly to your #map it will work as long as you don't cover it with something else (you have to mousedown ON the actual #map element).
The jQuery .delegate() reference states instead: "Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements."
Since you will be adding inner div's -after- binding the event, this exactly fits what you want to do. Specifying the "div" selector actually binds mousedown to any (current or future) div inside #map. You could actually use div.basictiles1 if you have other, non-clickable divs there.

Related

remove the child of an element (chess)

I am making a chess game, and I need your help to solve the following problem.
event.target.removeChild(event.target.firstChild);
dragged.parentNode.removeChild(dragged);
event.target.appendChild(dragged);
//dragged is ref to the dragged piece
//event is the drop event
when I move a piece :
I remove the existing piece from the square
I add the new Piece
If the square is empty I just add the piece
note: event.target is a square and the pieces are images.
The problem is when I remove The existing piece from the square, I get the following error:
Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.
It is possible that the event.target is not what you think it is and that therefore does not have the child element you expect (likely if your pieces are images with transparency that fill a significant part of the parent aquare). The target of an event can be any descendent of the element on which the event listener was set, depending where the event occured.
In other words, if you establish an event listener on the square divs representing squares on the chess board, a click (or drop, or whatever event you listen for) inside the square might easily target the piece and not the square.
Here's an illustration using a click event (but it applies to drops or anything else), a console message reports the target element's id:
const square=document.getElementById("div1");
square.addEventListener('click', event => {
console.log(event.target.id);
}); // end click listener
#div1 {
width: 50px;
aspect-ratio: 1;
background: yellow;
padding: 5px;
}
#div2 {
width: 100%;
aspect-ratio: 1;
border-radius: 50%;
background: red;
}
<div id="div1">
<div id="div2"></div>
</div>
(You can easily check what's going on in your example by putting some console messages inside the event listener to report information about the target)
Personally, I approach tasks like this by making the listener as non-specific as possible (by targetting the document in its entirety). This forces you to test where the event was received and so allows you to cover all bases.
In this working snippet, I've used a click event listener but it will be the same for any event. The listener contains an if-else loop that tests whether the outer square or the inner circle was clicked and forms the code required to remove the circle dependent on what the target was:
document.addEventListener('click', event => {
if (event.target.className == 'square' && event.target.children[0]) {
event.target.removeChild(event.target.children[0]);
} else if (event.target.className == 'piece') {
event.target.parentElement.removeChild(event.target.parentElement.children[0]);
} // end if/else;
}); // end click event listener
.square {
width: 50px;
aspect-ratio: 1;
background: yellow;
padding: 5px;
}
.piece {
width: 100%;
height: 100%;
border-radius: 50%;
background: red;
}
<div class="square">
<div class="piece"></div>
</div>
Note the opening if block contains two conditions:
(event.target.className == 'square' && event.target.children[0])
obviously the first confirms a square was clicked, the second checks whether there's anything inside that element to remove (preventing an error when an empty square is clicked).

How do I select only the <body> element's background whitespace for a Javascript onclick callback?

I need to create a callback that allows me to click or double click the background of my webpage, to return it to its default layout (thereby, closing and returning things so far affected by event callbacks). If I add an onclick callback to my <body> element, it is called whenever I click higher-level elements, not just on the background. So, it is available everywhere. How do I ensure that only the lowest-level element (i.e. the background whitespace) can call the reset function?
You need to do event propagation stop technique. So that you stop your event from going up the DOM tree.
One such method is event.stopPropagation();
Do also look Event Delegation, this may also help depending on your requirement.
The idea is that if we have a lot of elements handled in a similar
way, then instead of assigning a handler to each of them – we put a
single handler on their common ancestor.
In the handler we get event.target to see where the event actually
happened and handle it.
In your case I believe You may require Event Delegation technique along with stopPropagation
I would suggest you have 2 elements background div and the inner div which will contain all the content of your webpage
<body>
<!-- the clickable background -->
<div class="background-container" onclick="reset()" id="background"></div>
<!-- Your webpage -->
<div class="webpage">
<h3>This is your webpage</h3>
</div>
</body>
CSS - to make the background fullscreen
.background-container{
background-color: #4158D0;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
/* Use z-index to put the background behind your webpage */
z-index: 0;
}
.webpage{
/* positioned relative to the nearest positioned ancestor (instead of positioned relative to the viewport, like fixed). */
position: absolute;
/*setting the z-index to one to bring it to front*/
z-index: 1;
}
h3{
font-size: 40px;
color: white;
font-family: 'Roboto';
}
Javascript - to make the background clickable and run the function reset()
This function will be triggered when the background is clicked
you can edit the function to fit your purpose
function reset(){
var colors = ["#4158D0", "#C850C0", "#FFCC70"];
document.querySelector('#background').style.cssText = `background-image: linear-gradient(43deg, ${colors[Math.floor(Math.random() * 3)]}, ${colors[Math.floor(Math.random() * 3)]}, ${colors[Math.floor(Math.random() * 3)]},${colors[Math.floor(Math.random() * 3)]},${colors[Math.floor(Math.random() * 3)]})`
}
For this demo the reset() function will change the background color
Here is the codepen https://codepen.io/Alemalohe/pen/MWjBwOd

JQuery UI Draggable set hitbox different from element or set multiple elements

I'm having an Issue that I'm trying to apply draggable to some a popup element of an external library (I can't modify them).
The problem is that, the most outer div of this popup is actually slightly outside it and has 0 height (its an arrow shaped div, its kinda like a dialog balloon), so it doesn't properly works with the containment.
I could just chose the inner element as a selector (which is the actual popup bounding box), but then the arrow element will not move with the popup.
As stated, I can't modify these elements in a way of grouping them togheter (Actually I don't even have access to the source, doing it in developer console), so how can I solve this? I would like to keep using JQuery UI, but if not possible I'm open to alternatives.
I've tried multiple selectors, but it won't move the arrow div :
$( ".dialogArrow, #popupDiv" ).draggable({ scroll: false });
Example code :
<div class="dialogArrow" style="height:0; width: 100%; background: red">I'm the parent but my hitbox is wrong
<div id="popupDiv" style="height: 200px; width: 200px; background: green">actual hitbox</div>
<div>i need to move togheter too</div>
</div>
JSFiddle : https://jsfiddle.net/hvkh7mmq/5/
You can make use of the handle option (demo). Like so:
$(function() {
$(".dialogArrow").draggable({
handle: "div#popupDiv",
scroll: false
});
});
Working example: https://jsfiddle.net/Twisty/hvkh7mmq/3/
I did not see a point to your selector, since you want to drag the parent element, not assign .draggable() to both elements. Since the parent has no render-able HTML, it can't be clicked upon in essence. So using the handle option, we can specify something that can be clicked.
Additional
If you inspect the element after dragging, you will see something like:
<div class="dialogArrow ui-draggable" style="height: 0px; width: 100%; background: red none repeat scroll 0% 0%; position: relative; left: 107px; top: 30px;">
<div id="popupDiv" style="height: 200px; width: 200px; background: green; cursor: inherit;" class="ui-draggable-handle">actual hitbox</div>
<div id="other div that needs to move togheter"></div>
</div>
The structure is not changed. All 3 elements are moved.

How to MouseOver behind an object?

I'm trying to mouseover an image which is behind an another image.
Is there any way to render the front image like it is not there, so I can mouseover the other image behind it?
Example can be seen here:
I can't mouseover the characters which are behind the logo boundingbox.
You can set the CSS property pointer-events: none on the obstructing object... but be aware that pointer events are all or nothing; mouseovers and hovers will pass right through, but so will clicks.
Here is a description of the value, from the Mozilla Developer's Network:
none: The element is never the target of mouse events; however, mouse events may target its descendant elements if those descendants have pointer-events set to some other value. In these circumstances, mouse events will trigger event listeners on this parent element as appropriate on their way to/from the descendant during the event capture/bubble phases.
I've put together a little example. In this example, I'm using onmouseover and onmouseout, since that's what you use on your website, but you could just as easily use the CSS :hover pseudo-selector. Here's a jsfiddle version of the example, and the stack snippet is below.
.hoverable {
width: 100px;
height: 100px;
background-color: blue;
}
.obscuring {
/* this first line is the important part */
pointer-events: none;
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background-color: red;
opacity: 0.5;
}
<div class="hoverable" onmouseover="this.style.backgroundColor = 'green'" onmouseout="this.style.backgroundColor = 'blue'"> </div>
<div class="obscuring"> </div>
You can create some invisible divs on top of the whole thing and put the hover behaviour on them. Then control the characters position with the position of the invisible divs.
Hope it makes sense.

div onclick only in viewable area

here is the scenario:
<div style="position: absolute; left: 10px; top: 10px; width:50%; height: 50%; border: 1px solid #000000" onclick="alert(0)">
<textarea style="position: absolute; left: 10px; top: 10px; width:50%; height: 50%; border: 1px solid #FF0000" ondblclick="alert(1)"></textarea>
</div>
The main problem is that the textarea's ondblclick event does not get triggered.
What happens is that if i try to doubleclick in the textarea the div onclick is triggered. I want the onclick of the div to happen ONLY if i click in the area of the div that is not covered by the textarea. How can I achieve that ?
Thanks in advance!
Try reading up on event delegation and adding handlers unobtrusively
Basically you can assign one click or dblclick handler to the div element. Within that handler you can determine the originating element and take the necessary action(s). The links should provide you with further information about that.
edit a basic example (using jquery and one handler function)
Just cancel the event. For traditional event attaching, you have to put return false; in the end, but I'd advice to use some more modern ways to attach event listeners (namely, addEventListener or attachEvent for IE8 and older).
You can use timers to detect intent.
Set a timer when click occurs which will get executed if no subsequent clicks occur.
On double-click clear the timer and execute your default double-click functionality.
As below,
var dblClickIntentTimer = null;
elem.click(function(){
dblClickIntentTimer = setTimeout(function() {
//Wait for 100 ms and then execute 'click' functionality here
}, 100);
});
elem.dblclick(function(){
clearTimeout(dblClickIntentTimer);
//Do double-click functionality here
});

Categories

Resources