So basically, I want to remove the appendChild element once it has been clicked. I tried to use this.remove(), but it does not work. I manually added some divs with h2 inside of it. When I clicked the div then, my code worked. When I clicked it, it did go away.
Code snippet
var div_children = document.getElementById("append-div").children;
var length = div_children.length;
for (var x = 0; x < length; x++){
div_children[x].addEventListener("click", function(){
this.remove();
});
}
function myfunction(){
var new_div = document.createElement("DIV");
new_div.innerHTML = "<h2>New div</h2>";
document.getElementById("append-div").appendChild(new_div);
}
#append-div{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#append-div div{
background-color: lightblue;
display: flex;
flex-direction: row;
border-radius: 45px;
border: 1px solid black;
width:fit-content;
height:fit-content;
}
#append-div div h2{
margin:20px;
}
<!DOCTYPE html>
<html>
<head>
<link = rel="stylesheet" type = "text/css" href="styles.css">
<title>Test</title>
</head>
<body>
<button class = "click-me" onclick = "myfunction()">Click Me!</button>
<div id = "append-div"></div>
</body>
</html>
The issue you were having before in the removal is that the first part of the code runs without any children and it never runs again even after you create new ones.
There's no need to loop through the children to add the event listener.
Just add it to the child right after you create the element.
function myfunction() {
var new_div = document.createElement("DIV");
new_div.innerHTML = "<h2>New div</h2>";
new_div.addEventListener("click", function() {
this.remove();
});
document.getElementById("append-div").appendChild(new_div);
}
#append-div {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#append-div div {
background-color: lightblue;
display: flex;
flex-direction: row;
border-radius: 45px;
border: 1px solid black;
width: fit-content;
height: fit-content;
}
#append-div div h2 {
margin: 20px;
}
<button class="click-me" onclick="myfunction()">Click Me!</button>
<div id="append-div"></div>
you could add the listener event when is created the element, as below:
function myfunction() {
var new_div = document.createElement("DIV");
new_div.innerHTML = "<h2>New div</h2>";
new_div.onclick = function () {
this.remove()
}
document.getElementById("append-div").appendChild(new_div);
}
<button class = "click-me" onclick = "myfunction()">Click Me!</button>
<div id = "append-div"></div>
Try doing this
document.getElementById("append-div").outerHTML = "";
It has support on cross browsers & IE 11+
https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML
Related
im trying to increment the id of an element everytime i click a button
im confused why its working when for innerHTML but not for id
my markup
<p id="demo"></p>
<button onclick="myfunction()">press me</button>
incrementing inner html
<script>
var a = 1;
function myfunction(){
document.getElementById("demo").innerHTML = a;
a++;
}
</script>
incrementing element variable id
<button onclick="myfunction()">press me</button>
<script>
var a = 1;
function myfunction(){
document.getElementById("demo").id = a;
a++;
}
</script>
Please enjoy this demo on storing an element into a variable for reuse. It looks like your issue was with trying to select the element by id after the id changed.
let cntr = 1;
const demo = document.getElementById("demo");
document.querySelector("button")
.addEventListener("click", function () {
const val = cntr % 4;
demo.id = "ele" + val;
cntr++;
});
.demo {
height: 5rem;
aspect-ratio: 1;
border-radius: 50%;
background: black;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
transition: background 1s;
}
#ele1 {
background: pink;
}
#ele2 {
background: lightblue;
}
#ele3 {
background: lightgreen;
}
<div id="demo" class="demo"><button>Clicky!</button></div>
I am trying to create a custom HTML component which creates tabs for every child element that it has. Here is the code for that custom component:
const code_window = document.getElementById("window");
class CodeWindow extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'
});
this.shadowRoot.appendChild(code_window.content.cloneNode(true));
this.code = this.shadowRoot.getElementById("code");
this.tabbar = this.shadowRoot.getElementById("tabbar");
this.code.addEventListener("slotchange", e => {
var elems = e.target.assignedNodes();
for (let i = 0; i < elems.length; i++) {
var tab = document.createElement("div");
tab.classList.add("tab");
var name = elems[i].getAttribute("name");
tab.innerHTML = name;
tab.setAttribute("name", name);
this.tabbar.appendChild(tab);
if (elems[i].hasAttribute("active")) this.activateTab(name);
tab.addEventListener("click", e => this.activateTab(e.target.getAttribute("name")));
}
if (!this.previous_tab && this.tabbar.children.length > 0) this.activateTab(this.tabbar.children[0].getAttribute("name"));
});
}
activateTab(name) {
if (this.previous_tab) {
this.previous_frame.removeAttribute("active");
this.previous_tab.removeAttribute("active");
}
var tabs = this.tabbar.children,
frames = this.code.assignedElements();
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].getAttribute("name") == name) {
tabs[i].setAttribute("active", "");
frames[i].setAttribute("active", "");
this.previous_frame = frames[i];
this.previous_tab = tabs[i];
break;
}
}
}
}
customElements.define("c-window", CodeWindow);
<template id="window">
<style>
:host {
display: flex;
flex-direction: column;
}
#titlebar {
display: flex;
background-color: green;
}
#tabbar {
flex-grow: 1;
display: flex;
}
#tabbar .tab {
display: flex;
align-items: center;
padding: 5px 10px;
background-color: #bbb;
}
#tabbar .tab[active] {
background-color: #fff;
}
#code {
flex-grow: 1;
display: block;
position: relative;
}
#code::slotted(*) {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 5px;
display: none;
}
#code::slotted(*[active]) {
display: block;
}
</style>
<div id="titlebar">
<div id="tabbar"></div>
</div>
<slot id="code" name="frames"></slot>
</template>
<c-window style="border: 2px solid green; height: 300px;">
<div slot="frames" name="Content 1">Contents of tab 1</div>
<div slot="frames" name="Content 2">Contents of tab 2</div>
</c-window>
There is a slot inside the custom component and I want that every time a child element is added, a tab should be added, if a child element is removed, the tab associated with that child should be removed.
But the slotchange event carries no information about which element has been added/removed, so currently, I have to loop through the slot.assignedElements() every time slotchange event is called and create tabs for each and every element. It means that for a particular child, duplicate tabs will be created, which can also be quite CPU intensive.
So, I was thinking if there is some way to get the information about the modified element so that the action can be performed on only the modified element. Is there any way of getting only the modified element? If not, what method can I apply for achieving this?
You are doing the oldskool Switch-DIVs approach for Tabs
You can do it all with one shadowDOM <slot ="active">
and one click handler
Needs some more work; but you get the slot="active" concept
<template id="TABS-MEISTER">
<style>
#bar { display:flex }
#bar div { width: 100px; background: lightgreen ; margin-right:1em ; cursor:pointer}
</style>
<div id="bar"></div>
<div style="clear:both"><slot name="active"></slot></div>
</template>
<tabs-meister>
<div title="Tab1">Tab #1</div>
<div slot="active" title="Tab2">Tab #2</div>
<div title="Tab3">Tab #3</div>
</tabs-meister>
<script>
customElements.define('tabs-meister', class extends HTMLElement {
constructor() {
let template = (id) => document.getElementById(id).content.cloneNode(true);
super()
.attachShadow({mode: 'open'})
.append(template(this.nodeName));
this.onclick = (evt) => {
if (this.activetab) this.activetab.removeAttribute("slot");
let tab = evt.composedPath()[0];
this.activetab = this.querySelector(`[title="${tab.title}"]`);
this.activetab.slot = 'active';
}
}
connectedCallback() {
let tabs = [...this.children].map(node => {
return `<div title=${node.title}>${node.title}</div>`;
}).join ``;
this.shadowRoot.querySelector("#bar").innerHTML = tabs;
}
});
</script>
I have an inner circle which tracks the position of my pointer, Now I want the circle color to change when it hovers on the h2 tag.
can anyone help??
I have tried searching few places but all were on "mouseover".
note: only when the inner-circle hovers on h2 not the mouse pointer, the inner circle's color should change.
<!doctype>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Roll Over Eyes</title>
<style>
body
{
display: flex;
align-items: center;
justify-content: center;
height: 900px;
border: 1px solid black;
}
.main-circle
{
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: 350px;
width: 350px;
border: 1px solid black;
border-radius: 10%;
}
#inner-circle
{
position: absolute;
height: 50px;
width: 50px;
border: 1px solid black;
border-radius: 50%;
background: #af4b23;
}
.message
{
display:none;
width: 75%;
}
</style>
</head>
<body>
<div class="main-circle">
<div id="inner-circle">
</div>
<h2 class="message">Your Outside the box</h2>
<h2 class="message">Your inside the box, now move the mouse to move the circle.</h2>
</div>
<script>
(function()
{
var ele= document.getElementById("inner-circle");
var hea= document.getElementsByClassName("message");
var body=document.body;
var height=body.clientHeight;
var width=body.clientWidth;
var move = function(event)
{
var x= event.clientX;
var y= event.clientY;
ele.style.left = ( x/width )*300;
ele.style.top = ( y/height )*300;
}
var display = function()
{
console.log("done");
hea[0].style.display="inline-block";
hea[1].style.display="none";
}
var hide = function()
{
console.log("done hiden");
hea[0].style.display="none";
hea[1].style.display="inline-block";
}
var effect = function()
{
ele.style.backgroundColor= "rgba(0,0,0,0.5)";
}
var deflt = function()
{
ele.style.backgroundColor= "#af4b23";
}
body.addEventListener("mousemove",function(){ move(event) },false);
body.addEventListener("mouseout",display,false);
body.addEventListener("mouseover",hide,false);
hea[1].addEventListener("mouseover",effect,false);
hea[1].addEventListener("mouseout",deflt,false);
})();
</script>
</body>
</html>
You can try this:
(function()
{
var ele= document.getElementById("inner-circle");
var hea= document.getElementsByClassName("message");
var body=document.body;
var height=body.clientHeight;
var width=body.clientWidth;
var move = function(event)
{
var x= event.clientX;
var y= event.clientY;
ele.style.left = ( x/width )*300;
ele.style.top = ( y/height )*300;
var e_pos = ele.getBoundingClientRect();
var h_pos = hea[1].getBoundingClientRect();
if(e_pos.bottom>=h_pos.top && e_pos.top<=h_pos.bottom && e_pos.right>=h_pos.left && e_pos.left<=h_pos.right){
ele.style.backgroundColor= "rgba(0,0,0,0.5)";
}else{
ele.style.backgroundColor= "#af4b23";
};
}
var display = function()
{
//console.log("done");
hea[0].style.display="inline-block";
hea[1].style.display="none";
}
var hide = function()
{
//console.log("done hiden");
hea[0].style.display="none";
hea[1].style.display="inline-block";
}
body.addEventListener("mousemove",function(){ move(event) },false);
body.addEventListener("mouseout",display,false);
body.addEventListener("mouseover",hide,false);
})();
in this answer i set background-color after setting left and top of ele. also i have removed two last eventListeners.
Look at the result online and change it yorself!
the border is added to detect h2's bounds.
I need to display the list and focus first list item in the list when user selects key 'm' on the keyboard. I tried calling focus() on the list item but it is not getting focus or it is not showing any effect. Below is the code.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>VOD</title>
<script src='js/index.js'>
</script>
<style>
html, body {
height:100%
}
#mid {
display: flex;
height: 100%;
width: 100%;
justify-content: stretch;
flex-flow: row nowrap;
z-index: 2;
}
#mid.hidden {
display: none;
}
#mid1, #mid2 {
display: flex;
flex: 1;
align-items: center;
}
#mid1 {
justify-content: center;
background-color: rgba(255, 255, 255, 0.5);
}
#mid2 {
background-color: rgba(255, 255, 255, 0.6);
}
#ulid {
list-style-type: none;
width: 100%;
margin: 0;
border: 0;
padding: 0;
}
.list-item {
width: 100%;
height: 150px;
border-style: solid;
border-width: 1px;
display:flex;
align-items: center;
justify-content: flex-start;
}
li:focus, li:active {
background-color: green;
}
</style>
</head>
<body>
<video id='vid' src='textMotion.mp4' autoplay loop></video>
<div id='mid' class='hidden'>
<div id='mid1'>
<h1>TEXT</h1>
</div>
<div id='mid2'>
<ul id='ulid'></ul>
</div>
</div>
</body>
</html>
JavaScript:
function displayMenu() {
var mid = document.getElementById('mid');
if(mid.classList.contains('hidden') == false) {
mid.classList.toggle("hidden");
let ulid = document.getElementById('ulid');
while(ulid.firstChild) {
ulid.removeChild(ulid.firstChild);
}
return;
}
var ulid = document.getElementById('ulid');
for(let index = 0; index < 3; index ++) {
let lItem = document.createElement('li');
lItem.classList.add('list-item');
lItem.setAttribute('id', 'li' + index);
var lineBreak = document.createElement('br');
lItem.appendChild(document.createTextNode('TEXT'));
lItem.appendChild(lineBreak);
lItem.appendChild(document.createTextNode('TEXT'));
ulid.appendChild(lItem);
}
mid.classList.toggle("hidden");
document.getElementById('li0').focus();
}
function changeChannel(e) {
console.log('received keyEvent : ' + e.keyCode);
let keyCode = e.keyCode;
if(keyCode == 77) {
displayMenu();
}
}
document.addEventListener('keydown', changeChannel);
Even though list is getting displayed when user presses 'm', list item is not getting focused.
below is the jsfiddle link
https://jsfiddle.net/t75gojd7/
Can anyone please help me to focus the list element.
It looks like adding a tabindex might work. Add this to the attributes.
lItem.setAttribute('tabindex', index);
Got the idea from here. Worked for some people not all.
What is happening here is that the element you are trying to focus is a div which doesn't actually remain in focus after click unlike a button or a input text field.
You can observe this behavior by pressing down the pointer on the div and not releasing it. Your CSS stylings will be applied.
I would suggest instead on :focus CSS class, you use some other pseudo CSS class. OR you can do event.preventDefault() on div click.
Quoting from MDN
If you call HTMLElement.focus() from a mousedown event handler, you must call event.preventDefault() to keep the focus from leaving the HTMLElement.
Also check out this ans Is it possible to focus on a <div> using JavaScript focus() function? which suggests adding tabindex attribute.
I'm creating a website that utilizes the HTML5 Drag and Drop API.
However, to increase the user experience, I'd like to prevent ghost images when a user drags non-draggable elements. Is this even possible?
Further, almost every element seems " draggable " by default. One can click and then quickly drag pretty much any element in a browser, which creates a ghost image along with a no-drop cursor. Is there any way to prevent this behaviour?
draggable="false" doesn't work.
user-select: none doesn't work.
pointer-events: none doesn't work.
event.preventDefault() on mousedown doesn't work.
event.preventDefault() on dragstart doesn't work either.
I'm out of ideas and so far it's proven incredibly difficult to find information about this online. I have found the following thread, but, again, draggable="false" doesn't seem to work in my case.
Below is a screenshot that demonstrates it doesn't work; of course you can't see my cursor in the screenshot, but you can see how I've dragged the numbers to the left despite that.
I believe the issue might have something to do with its parent having dragover and drop events associated with it. I'm still dumbfounded nonetheless.
HTML
...
<body>
...
<div id="backgammon-board-container">
<div class="column" id="left-column">
<div class="quadrant" id="third-quadrant">
<div class="point odd top-point" id="point-13-12"><text>13</text>
<div class="checker player-one-checker" id="checker-03" draggable="true"></div>
</div>
</div>
</div>
...
</div>
</body>
</html>
CSS
#backgammon-board-container {
height: 100vh;
width: 60vw;
position: absolute;
right: 0;
display: flex;
}
.column {
height: 100%;
display: flex;
flex-direction: column; /* column-reverse for player two perspective */
}
#left-column {
flex: 6;
}
.quadrant {
flex: 1;
display: flex;
}
.point {
flex: 1;
padding: 10px 0;
display: flex;
flex-direction: column;
align-items: center;
}
.checker {
z-index: 1;
width: 48px;
height: 48px;
border-radius: 50%;
}
text {
position: fixed;
font-family: impact;
font-size: 24px;
color: white;
display: flex;
justify-content: center;
align-items: center;
user-select: none;
pointer-events: none;
}
JS
const p1checkers = document.getElementsByClassName('player-one-checker');
const p2checkers = document.getElementsByClassName('player-two-checker');
const pointClass = document.getElementsByClassName('point');
function setTurn(player) {
if (player === 'p1') {
allowCheckerMovement = p1checkers;
disallowCheckerMovement = p2checkers;
} else {
allowCheckerMovement = p2checkers;
disallowCheckerMovement = p1checkers;
}
// enable checker control for player
for (var i = 0; i < allowCheckerMovement.length; i++) {
allowCheckerMovement[i].style.cursor = 'pointer';
allowCheckerMovement[i].setAttribute('draggable', true);
allowCheckerMovement[i].addEventListener('dragstart', start); // for drag-and-drop.js
allowCheckerMovement[i].addEventListener('dragend', stop); // for drag-and-drop.js
}
// disable checker control for player
for (var i = 0; i < disallowCheckerMovement.length; i++) {
disallowCheckerMovement[i].style.cursor = 'default';
disallowCheckerMovement[i].setAttribute('draggable', false);
disallowCheckerMovement[i].removeEventListener('dragstart', start); // for drag-and-drop.js
disallowCheckerMovement[i].removeEventListener('dragend', stop); // for drag-and-drop.js
}
// allow drag and drop
for (var i = 0; i < pointClass.length; i++) {
pointClass[i].addEventListener('dragover', allowDrop); // for drag-and-drop.js
pointClass[i].addEventListener('drop', droppedOn); // for drag-and-drop.js
}
}
function start(event) {
var checker = event.target;
event.dataTransfer.setData('text/plain', checker.id);
event.dataTransfer.effectAllowed = 'move';
window.requestAnimationFrame(function(){
checker.style.visibility = 'hidden';
});
}
function allowDrop(event) {
event.preventDefault();
}
function droppedOn(event) {
event.preventDefault();
var data = event.dataTransfer.getData('text/plain');
event.target.appendChild(document.getElementById(data));
}
function stop(event){
var element = event.srcElement;
window.requestAnimationFrame(function(){
element.style.visibility = 'visible';
});
}
This is the solution you're looking for. ;)
For anything that DOES need to be draggable, just add the 'enable-drag' CSS class.
$('*:not(".enable-drag")').on('dragstart', function (e) {
e.preventDefault();
return false;
});