I have the same situation here, but it's not answered well. I have this code for a workaround:
window.addEventListener('load', () => {
// sticky profile notes
const notes = document.querySelector('#textarea-notes'); // Get textarea element
const headerDiv = document.createElement("div"); // Create a <div> element
headerDiv.id = 'div-header';
headerDiv.innerHTML = 'Add Notes'; // Insert instructions
// add header on top
notes.parentNode.insertBefore(headerDiv, notes);
// minimize sticky
headerDiv.addEventListener('click', e => {
// detect if cursor type is pointer
console.log(e.target.style.cursor);
});
});
#div-header {
padding: 10px;
cursor: move;
background-color: #ffffcc;
}
#div-header:after {
margin-left: 10px;
cursor: pointer;
content: 'button';
}
#textarea-notes {
background-color: #ffffcc;
width: 100%;
}
<textarea id="textarea-notes">
</textarea>
wherein I aim to check what type of mouse pointer the user has when clicking the div with the div element.
The problem is when I log the cursor type, it shows an empty space. How do I know the cursor type? And is there a better way to identify if the clicked element is a pseudo-element?
Since you can't detect events on pseudo elements you can insert separate elements into the headerDiv and check the target of the click event to accomplish the same objective. (Or only apply events to the new child elements)
Here I created two spans for "add notes" and "button" texts which get appended to the new div. A new css rule for the button span applies the margin and pointer cursor
window.addEventListener('load', () => {
// sticky profile notes
const notes = document.querySelector('#textarea-notes'); // Get textarea element
const headerDiv = document.createElement("div"); // Create a <div> element
headerDiv.id = 'div-header';
// Create two spans to insert in headerDiv
const notesTitle = document.createElement('span')
notesTitle.innerHTML = 'Add Notes'; // Insert instructions
// this span could also be a real <button>
const notesBtn = document.createElement('span');
notesBtn.textContent = 'button';
notesBtn.className = 'notes-btn'
headerDiv.append(notesTitle)
headerDiv.append(notesBtn)
// add header on top
notes.parentNode.insertBefore(headerDiv, notes);
// minimize sticky
headerDiv.addEventListener('click', e => {
let msg = 'Parent clicked';
if(e.target.matches('.notes-btn')){
msg = 'Button clicked';
}
console.log(msg)
});
});
#div-header {
padding: 10px;
cursor: move;
background-color: #ffffcc;
}
/*#div-header:after {
margin-left: 10px;
cursor: pointer;
content: 'button';
}*/
#div-header .notes-btn{
margin-left: 10px;
cursor: pointer;
}
#textarea-notes {
background-color: #ffffcc;
width: 100%;
}
<textarea id="textarea-notes">
</textarea>
Related
I just started studying JS and I'm currently simulating something that will apply to my project
Basically, I'm trying to generate new Divs with Button on it in order to do something.
And I applied the for loop on the button from the guide here
Turns out it works! but there's a bug where some buttons wont work whenever I generate more divs+button and I don't know why?
const btnCreate = document.querySelector(".myButton");
const changeBtn = document.getElementsByClassName("changeBtnStyle");
const newNewDiv = document.getElementsByClassName("newCDiv");
const createFunc = function() {
const parentDiv = document.querySelector(".parentDiv");
const newDiv = document.createElement("div");
const newChangeBtn = document.createElement("button");
parentDiv.appendChild(newDiv);
newDiv.appendChild(newChangeBtn);
newDiv.classList.add("newCDiv");
newChangeBtn.classList.add("changeBtnStyle")
newChangeBtn.innerHTML = "change"
for (let i = 0; i < changeBtn.length; i++) {
changeBtn[i].addEventListener("click", function() {
newNewDiv[i].classList.toggle("changeColor");
}, false);
}
};
btnCreate.addEventListener("click", createFunc);
.parentDiv {
margin: auto;
width: 300px;
height: 300px;
background-color: gray;
position: relative;
}
.newCDiv {
background: green;
width: 50px;
height: 50px;
position: relative;
}
.changeBtnStyle {
position: absolute;
}
.changeColor {
background: red;
}
.myButton {
margin: auto;
}
<button class="myButton">
Create Div w/ Button
</button>
<div class="parentDiv">
</div>
Here's the JSFiddle one
Every time you click on a generated button the for loop will add an event listener for each button. Even the ones that already have an event listener attached to them. So by doing that and then toggling the class, you call the classList.toggle() function more than once.
For example with 1 event listener, the toggle works fine. But with 2 event listeners you toggle and toggle again, resulting in an immediate on / off switch. 3 event listeners will toggle 3 times, on / off / on, having the right resulting but not working correctly.
So instead of looping each button again, just add the event listener only to the element that you've created in the createFunc function.
const btnCreate = document.querySelector(".myButton");
const changeBtn = document.getElementsByClassName("changeBtnStyle");
const newNewDiv = document.getElementsByClassName("newCDiv");
const createFunc = function() {
const parentDiv = document.querySelector(".parentDiv");
const newDiv = document.createElement("div");
const newChangeBtn = document.createElement("button");
parentDiv.appendChild(newDiv);
newDiv.appendChild(newChangeBtn);
newDiv.classList.add("newCDiv");
newChangeBtn.classList.add("changeBtnStyle")
newChangeBtn.innerHTML = "change"
newChangeBtn.addEventListener("click", function() {
newDiv.classList.toggle("changeColor");
}, false);
};
btnCreate.addEventListener("click", createFunc);
.parentDiv {
margin: auto;
width: 300px;
height: 300px;
background-color: gray;
position: relative;
}
.newCDiv {
background: green;
width: 50px;
height: 50px;
position: relative;
}
.changeBtnStyle {
position: absolute;
}
.changeColor {
background: red;
}
.myButton {
margin: auto;
}
<button class="myButton">Create Div w/ Button</button>
<div class="parentDiv"></div>
I want to dynamically append a child to its parent multiple times when I click the button.
let btn = document.querySelector('.btn');
let starContainer = document.querySelector('.star__container');
let starWin = document.createElement('div');
starWin.classList.add('star__win');
starWin.innerText = 'Test';
btn.addEventListener('click',addItem);
function addItem(){
starContainer.appendChild(starWin);
}
<div class="star__container"></div>
<button class='btn'>Click</button>
You need to create your starWin element each time the addItem method is called. Now, you append the same element several times. It won't be cloned.
let btn = document.querySelector('.btn');
let starContainer = document.querySelector('.star__container');
btn.addEventListener('click', addItem);
function addItem() {
starContainer.appendChild(createElement());
}
function createElement() {
let starWin = document.createElement('div');
starWin.classList.add('star__win');
starWin.innerText = 'Test';
return starWin;
}
<div class="star__container"></div>
<button class='btn'>Click</button>
<div class="star__container"></div>
<button class='btn'>Click</button>
let btn = document.querySelector('.btn');
let starContainer = document.querySelector('.star__container');
btn.addEventListener('click',addItem);
function addItem(){
let starWin = document.createElement('div');
starWin.className = 'star__win';
starContainer.appendChild(starWin);
}
Update
Issue
Expectation: A <div> should to be appended to DOM for each click of a button.
Result: The first click of the button appends a <div> to DOM, but thereafter any further clicking of said button elicits nothing.
Diagnosis: All code concerning the creation of <div> is not within a function, the only time it will run is at page load. When the handler function is triggered by a button click, it finds that <div> that was made at page load and successfully appends the <div> to the DOM. When user clicks the button again, nothing happens because the <div> was made only once.
Solution: Place all of the aforementioned code in the handler function addItem()
Demo 1
let btn = document.querySelector('.starBtn');
btn.addEventListener('click', addItem);
function addItem(event) {
const box = document.querySelector('.starBox');
let star = document.createElement('b');
star.classList.add('stellar');
star.innerText = '⭐';
box.appendChild(star);
}
body {
font-size: 3rem
}
.starBox {
word-wrap: break-word;
}
.starBtn {
position: fixed;
top: 0;
left: 0;
font: inherit;
}
<article class="starBox"></article>
<button class='starBtn'>🤩</button>
Not sure what the problem is, don't care really. If you take a look at this demo it'll help with whatever issue you may have. Details are commented line-by-line in the demo. Apologies in advance -- I'm bored ...
🥱
I'll come back and post a decent answer later. Review the demo in Full Page mode.
Demo 2
// Reference the <form>
const STARS = document.forms.starFactory;
// Define the counter
let s = 0;
// Register the form to the click event
STARS.onclick = makeStar;
// Handler function passes event object
function makeStar(event) {
// Define an array of characters✱
let galaxy = ['★', '☆', '✨', '✩', '✪', '⚝', '✫', '✭', '✯', '✰', '✴', '⭐', '🌟', '🌠', '💫', '🟊', '🤩'];
/*
- "this" is the form
- Collect all <input>, <button>, <output>, etc into a
NodeList
*/
const field = this.elements;
/*
- event.target is always the tag the user interacted with
- In this case it's the <button> because this handler
will not accept but that <button>
*/
const clicked = event.target;
/*
- The NodeList `field` can reference form tags by
suffixing the tag's #id or [name]
- The <fieldset> and <output> are referenced
*/
const jar = field.starJar;
const cnt = field.count;
/*
- By using a simple `if` condition strategically we can
control what and how tags behave when a registered
event.
- The remainder of the handler is explained at the very
end.
*/
if (clicked.id === 'STARt') {
s++;
const star = document.createElement('S');
let index = Math.floor(Math.random() * galaxy.length);
let ico = galaxy[index];
star.textContent = ico;
star.className = 'star';
star.style.zIndex = s;
star.style.left = Math.floor(Math.random() * 85) + 1 +'%';
star.style.bottom = Math.floor(Math.random() * 90) + 1 + '%';
jar.appendChild(star);
cnt.value = s;
}
}
/*
- increment `s` by one
- create a <s>trikethrough tag (aka <s>tar tag JK)
- generate a random number in the range of 0 to 15
- get a character from galaxy Array at the index number
determined from the previous step.
- render the text character in the <s>tar
- assign the class .star to <s>tar
- assign `z-index` to <s>tar (Note: it increases every
click which insures that tags won't collide)
- randomly assign `left` in the range of 1 to 85 to <s>tar
- randomly assign `bottom` in the range of 1 to 90 to
<s>tar
- append <s>tar to #starJar
- increment #count value
*/
:root,
body {
font: 400 5vw/1 Verdana;
background: #123;
}
#starFactory {
display: flex;
justify-content: center;
align-items: center;
}
#starJar {
position: relative;
display: flex;
flex-flow: row wrap;
justify-content: end;
width: 50vw;
height: 50vw;
border: 5px inset rgba(255,255,0,0.3);
border-bottom-left-radius: 12vw;
border-bottom-right-radius: 12vw;
color: gold;
}
legend {
position: relative;
z-index: 5150;
width: max-content;
font-size: 1.5rem;
color: goldenrod;
}
#STARt {
position: relative;
z-index: 5150;
font-size: 1.5rem;
background: none;
padding: 0;
border: 0;
cursor: pointer;
}
#count {
position: relative;
z-index: 9999;
font-size: 1.25rem;
width: 5vw;
overflow-x: visible;
color: cyan;
}
s.star {
position: absolute;
text-decoration: none;
font-size: 1.5rem;
background: none;
padding: 0;
margin: 0;
border: 0;
}
<form id='starFactory'>
<fieldset id="starJar">
<legend>starJar
<button id='STARt' type='button'>
✴️ <output id='count'></output>
</button>
</legend>
</fieldset>
</form>
i make profile form, i clicked this, form is show but hidden instally
I want to click the link if the form appears without disappearing again, and if clicked outside in the form, from hidden and the web position stay without scrolling to up
i code used
$('.profile-link').click(function(e) {
$(".profile-frm").addClass("show-prfrm");
});
$(document).mouseup(function(e) {
var container = $(".profile-frm");
var clickfuncion = $('.profile-link').click;
if (container.is(':visible')) {
// if the target of the click isn't the container nor a descendant of the container
if (!container.is(e.target) && container.has(e.target).length === 0) {
e.preventDefault();
$('body').width($('body').width());
container.removeClass("show-prfrm");
}
}
});
I think the only tricky part is to put a click handler on the document and do different things when the target element is the button, the menu, or anything else.
const button = document.querySelector('button');
const menu = document.querySelector('#menu');
document.addEventListener('click', event => {
menu.classList.add('hide');
if (event.target == button || event.target == menu)
menu.classList.remove('hide');
});
#menu {
position: absolute;
top: 50;
border: 1px solid #555;
background-color: #555;
border-radius: 10px;
height: 175px;
width: 100px;
}
.hide {
display: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<button>Menu</button>
<div id="menu" class="hide"></div>
I have seen this code ( http://jsfiddle.net/eMNfd/21/ ), but I want to know how to make the new div can be created to the right of the blue, that is, in horizontal mode.
document.getElementById("text").onclick = function () {
var ok = true;
if (ok === true) {
var div = document.createElement('div');
div.className = 'new-rect';
//div.style.backgroundColor = "black";
document.getElementsByTagName('body')[0].appendChild(div);
}
};
.new-rect {
background: black;
width: 20%;
height: 30px;
}
<div id="text" style="width:20%;height:30px;background-color:blue;"></div>
Thanks to all.
You can use float for this (has to be set on all divs to work), you can also use inline-block:
document.getElementById("text").onclick = function () {
var ok = true;
if (ok === true) {
var div = document.createElement('div');
div.className = 'new-rect';
//div.style.backgroundColor = "black";
document.getElementsByTagName('body')[0].appendChild(div);
}
};
body {
font-size: 0; /* to get rid of the space between the divs */
white-space: nowrap; /* to prevent wrapping on multiple lines */
}
div {
display: inline-block; /* to add divs horizontally */
}
.new-rect {
background: black;
width: 20%;
height: 30px;
}
<div id="text" style="width:20%;height:30px;background-color:blue;"></div>
I would like to keep a div visible while the mouse is in the bounds of the div, the code works until it hovers over the input. I would like a sign up form appear onmouseover and when the sign in is complete and the mouse moves off the div is no longer visible. jsFiddle Demo
HTML
<div class="members">
Members
<div id="sign-up-form" class="sign-up-form">
<input type="text" name="firstName">
</div>
</div>
JS
var signUp = document.getElementById('signUp');
var signUpForm = document.getElementById('sign-up-form');
signUp.onmouseover = function(){
signUpForm.style.display = 'block';
}
signUpForm.onmouseout = function(){
signUpForm.style.display = 'none';
}
CSS
#signUp{
position: relative;
background-color: red;
color: white;
padding: 6px;
}
#sign-up-form{
display: none;
position:absolute;
top: 32px;
left: 8px;
background-color: rgba(0,83,159,0.6);
padding: 15px;
}
I would do it this only with CSS:
#sign-up-form {
display: none;
}
.members:hover #sign-up-form {
display: block;
}
This example uses mouseover and mouseout event listeners and a function that will listen to all children elements before changing the display of the signUpForm element.
function outVis(event) {
var e = event.toElement || event.relatedTarget;
if (e.parentNode == this || e == this) {
return;
}
signUpForm.style.display = 'none';
}
http://jsfiddle.net/9xhb532v/1/