item.addEventListener runs automatically - javascript

I'm learning JS by following Wes Bos's class. I'm trying to select buttons and display information every time the user clicks on them. So I add an event listener, however, the fallback function seems to be executed automatically when it is located inside the event listener. I don't understand why 'hello' is displayed automatically while the function youClickTheButton is executed only when the user clicks on a button (see the below code).
Why does this happen?
const myButtons = document.querySelectorAll('.cards button');
const modalOuter = document.querySelector('.modal-outer');
function youClickTheButton(event) {
console.log(event);
modalOuter.classList.add('open');
}
myButtons.forEach(item => item.addEventListener('click', youClickTheButton));
myButtons.forEach(item => item.addEventListener('click', console.log('hello')));
// whenever you click on the button it will open a pop up with a picture with the description
// whenever you click outside of this pop up it should close itself use .closest()
// populate the modal with name and description of the card so you don't have to modify the .html file
// you could also close it by simply pressing escape
const myButtons = document.querySelectorAll('.cards button');
const modalOuter = document.querySelector('.modal-outer');
function youClickTheButton(event) {
console.log(event);
modalOuter.classList.add('open');
}
myButtons.forEach(item => item.addEventListener('click', youClickTheButton));
myButtons.forEach(item => item.addEventListener('click', console.log('hello')));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title></title>
<link rel="stylesheet" href="../../base.css">
</head>
<body>
<div class="cards">
<div class="card number1" data-description="Wes is cool">
<img src="https://picsum.photos/200?random=1" alt="Wes Bos">
<h2>Wes Bos</h2>
<button>Learn more →</button>
</div>
<div class="card number2" data-description="Scott is neat!">
<img src="https://picsum.photos/200?random=2" alt="Wes Bos">
<h2>Scott Tolinski</h2>
<button>Learn more →</button>
</div>
<div class="card number3" data-description="Kait is beautiful!">
<img src="https://picsum.photos/200?random=3" alt="Wes Bos">
<h2>Kait Bos</h2>
<button>Learn more →</button>
</div>
<div class="card number4" data-description="Snickers is a dog!">
<img src="https://picsum.photos/200?random=4" alt="Wes Bos">
<h2>Snickers the dog</h2>
<button>Learn more →</button>
</div>
</div>
<div class="modal-outer ">
<div class="modal-inner ">
<p>You clicked on the 1st one</p>
</div>
</div>
<style>
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 20px;
padding: 2rem;
}
.card {
background: white;
padding: 1rem;
border-radius: 2px;
}
.card img {
width: 100%;
}
.card h2 {
color: black;
}
.modal-outer {
display: grid;
background: hsla(50, 100%, 50%, 0.7);
position: fixed;
height: 100vh;
width: 100vw;
top: 0;
left: 0;
justify-content: center;
align-items: center;
/* Hide this modal until we need it */
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
.modal-outer img {
width: 100%;
}
.modal-outer.open {
opacity: 1;
pointer-events: all;
}
.modal-inner {
max-width: 600px;
min-width: 400px;
padding: 2rem;
border-radius: 5px;
min-height: 200px;
background: white;
transform: translateY(-200%);
transition: transform 2s;
}
.modal-outer.open .modal-inner {
transform: translateY(0);
}
</style>
<script src="./click-outside_5.js"></script>
</body>
</html>

Check the difference between your two item.addEventListener()s. In the first one, you pass down a function, while in the second one, you call one (no parentheses vs. parentheses).
If you pass down a callback function (i.e. first case), you don't invoke it immediately, you just say that "Here is this function I created, run it every time someone clicks on any of these buttons."
If you want to log from your second function, you need to pass a function, not the result of the function:
myButtons.forEach(item => item.addEventListener('click', () => console.log('hello')))
// OR
function logHello() {
return console.log('hello')
}
myButtons.forEach(item => item.addEventListener('click', logHello));
You can read more about it on MDN.
Anyway, you should not loop over the buttons twice, but I think you're just testing things out at the moment. console.log('hello') could be in your youClickTheButton() function.

Related

Undo does not work for a replaced content on a div in html

I am trying to create a code that works when you put it on the google search bar, that is a must and i created a div you can edit, also i created a reset button that replaces the content on the div with the default text, but when I try to press ctrl + z it does not go back, and i don't know how to make it work
-I cannot get rid of the: data:text/html, part because it wouldn't work in the search bar for google
-i do have to have all the code types in just one document, because i have to copy paste it all on the google search bar
function reset() {
div_1.innerHTML = '<p> Default text<p>';
}
.div_1 {
display: block;
background-color: rgba(255, 0, 0, 0.5);
height: 80%;
position: relative;
width: 60%;
position-left: 100px;
}
<div contenteditable="true" class="div_1" id="div_1">
<p> Default text<p>
</div>
<button onclick="reset()">reset</button>
function reset() {
div_1.innerHTML = ''; //set the inner HTML to empty string
}
.div_1 {
display: block;
background-color: rgba(255, 0, 0, 0.5);
height: 80%;
position: relative;
width: 60%;
position-left: 100px;
}
<div contenteditable="true" class="div_1" id="div_1">
<p> Default text<p>
</div>
<button onclick="reset()">reset</button>
I think you are trying to make the form empty when you press reset button.
So you have to change the inner HTML to an empty string in order to do that.
I hope it helped
i was able to find an option with the memento pattern and creating an event for the ctrl + z input on the keyboard
function copy(){
inp1.select();
navigator.clipboard.writeText(inp1.value);
ctn.innerHTML = inp1.value;
}
var mementos = [];
function reset() {
mementos.push(document.getElementById('div_1').innerHTML);
div_1.innerHTML= '<p>caller name: </p><p>reason for the call:</p><p>CTN: <div class="ctn" id="ctn"></p><p><br></p><p></p>';
}
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 'z') {
var lastMemento = mementos.pop();
div_1.innerHTML = lastMemento;
}
});
function undo() {
var lastMemento = mementos.pop();
div_1.innerHTML = lastMemento;
}
input{
width:200px;
height: 100%;
}
.div_1{
display: block;
background-color:rgba(255, 0, 0, 0.5);
height:400px;
position: relative;
width: 400px;
padding-left: 2px;
}
button{
position: relative;
}
.ctn {
display: inline;
background-color: red;
}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Notes</title>
</head>
<body>
<link rel="stylesheet" href="syles.css">
<input placeholder="(000)-000-0000" maxlength="10" id="inp1">
<button onclick="reset()">reset</button>
<button onclick="copy()">copy</button>
<button onclick="undo()">Undo</button>
<div contenteditable="true"class="div_1" id="div_1">
<p>caller name: </p><p>reason for the call:</p><p>CTN: <div class="ctn" id="ctn"></p><p><br></p><p></p>
</div>
</body>
</html>

"style.display = 'flex/none'" not working

So I thought it would be pretty simple to implement an if statement to have an element appear or disappear at the click of a button.
After a couple of hours now, I have not gotten further than getting the element to disappear. It registers the second click(tested with a console.log), but the display property does not change back to 'flex'.
I've also already tried different variations of 'getElementById' and 'querySelector' during my sentence.
const edit = document.getElementById('edit-btn');
const fill = document.querySelector('#filler');
edit.addEventListener('click', popInOut(fill))
function popInOut(e){
if(e.style.display=='flex'){
e.style.display='none'
}else if(e.style.display=='none'){
e.style.display='flex'
}
}
The 'filler' element is a bootstrap column with this styling.
#filler{
display:flex;
flex-direction: column;
background-color: #1c1f22;
position:absolute;
top:40%;
height:50%;
}
hey it is your query selector which is causing the problem
and also you can use your filler directly in function because its declared
in global scope
const edit = document.getElementById("edit-btn");
const filler = document.getElementById("filler");
edit.addEventListener("click", fix);
function fix() {
if (filler.style.display === "none") {
filler.style.display = "flex";
} else {
filler.style.display = "none";
}
}
body {
font-family: sans-serif;
}
#filler {
display: flex;
/* flex-direction: column; */
background-color: whitesmoke;
position: absolute;
top: 30%;
left: 20%;
height: 50%;
gap: 1rem;
}
#filler div:nth-child(even) {
background: turquoise;
}
#filler div:nth-child(odd) {
background: yellowgreen;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
<link href="style.css"/>
</head>
<body>
<div id="app">
<div id="filler">
<div>Hare krishna</div>
<div>Radhe Shyam</div>
<div>Sita Ram</div>
</div>
<button id="edit-btn">Edit</button>
</div>
<script src="index.js"></script>
</body>
</html>

href link not working with innerHTML script with "onmouseover change text" and onmouseout

My goal is to have text change onmouseover from "hello" (without a link) to "Google" and provide an 'href' on the resulting "Google" text, and then revert to "hello" onmouseout without a link.
The code below works in changing the text from "hello" to "Google" but,
the link on "Google" does not work (even though I can right-click on "Google" and open the link on another tab)
the text does not change back to "hello" onmouseout.
Thanks for your help in advance!
Here is my code:
<style>
.container {
margin-top: 6vw;
margin-left: 40%;
margin-right: 40%;
}
</style>
<div class="container">
<h1>
<div class="hello" id="hello1" onmouseover="changeText()" onmouseout="changeText(this,'Hello.')">Hello.</div>
</h1>
</div>
<script>
function changeText() {
if (document.getElementById("hello1")) {
a = document.getElementById("hello1")
a.innerHTML = 'Google'
}
}
</script>
try this way onmouseout="this.innerHTML='Hello.';"
function changeText() {
if (document.getElementById("hello1")) {
a = document.getElementById("hello1")
a.innerHTML = 'Google'
}
}
.container {
margin-top: 6vw;
margin-left: 40%;
margin-right: 40%;
}
<div class="container">
<h1>
<div class="hello" id="hello1" onmouseover="changeText()" onmouseout="this.innerHTML='Hello.';">Hello.</div>
</h1>
</div>
By changing a class of a parent tag, any and all child tags can be affected via CSS. Having the HTML ready when the page loads and then hiding it is better than constantly creating and destroying HTML for trivial effects.
The events "mouseenter" and "mouselrave" are handled by a property event handler and an event listener. Either one is sufficient, but avoid using attribute event handlers:
<div onmouselame="lameAttributeEventHandler()">...</div>
Details are commented in the example below
// Reference the <header>
const hdr = document.querySelector('.title');
/* This is a property event handler
// Whenever the mouse enters within the borders of
// the <header>:
// '.google' class is added
// '.hello' class is removed
*/
hdr.onmouseenter = function(event) {
this.classList.add('google');
this.classList.remove('hello');
};
/* This is an even listener
// Whenever the mouse exits the <header> the
// opposite behavior of the previous handler
// happens
*/
hdr.addEventListener("mouseleave", function(event) {
this.classList.add('hello');
this.classList.remove('google');
});
.title {
height: 50px;
margin-top: 3vh;
border: 3px solid black;
text-align: center;
}
h1 {
margin: auto 0;
}
.hello span {
display: inline-block;
}
.hello a {
display: none;
}
.google a {
display: inline-block;
}
.google span {
display: none;
}
<header class="title hello">
<h1>
<span>Hello</span>
Google
</h1>
</header>
You can try this, May it help u to solve the problem
<!DOCTYPE html>
<head>
<title>change text on mouse over and change back on mouse out
</title>
<style>
#box {
float: left;
width: 150px;
height: 150px;
margin-left: 20px;
margin-top: 20px;
padding: 15px;
border: 5px solid black;
}
</style>
</head>
<html>
<body>
<div id="box" onmouseover="changeText('Yes, this is Onmouseover Text')" onmouseout="changeback('any thing')" >
<div id="text-display" >
any thing
</div>
</div>
<script type="text/javascript">
function changeText(text)
{
var display = document.getElementById('text-display');
display.innerHTML = "";
display.innerHTML = text;
}
function changeback(text)
{
var display = document.getElementById('text-display');
display.innerHTML = "";
display.innerHTML = text;
}
</script>
</body>
</html>

How to deactivate button once clicked Javascript

I want to stop incrementing the number of individual likes if the photo was liked(clicked) once, and increment the total number of likes for each individual photo liked(clicked)
individual photo likes likesAfterAddition
global photo likes globalNumberOfLikes
For the moment it is increasing every time I click in both individual and global likes, I know it is not the right logic!
What logic can I use please?
//increment likes on click
function incrementLikesOnClick() {
const heartIcons = Array.from(document.getElementsByClassName('heartIcon')); // multiple heart icons
heartIcons.forEach((likeIcon, index) => likeIcon.addEventListener('click', () => {
const individualLikeBox = document.getElementsByClassName('under-photo-info');
const totalLikesDivBox = document.getElementById("likesBox");
likeIcon.classList.add('activeRed');
let likesAfterAddition = likesTable[index] + 1; // add 1 like to the individual current photo
likesTable.splice(index, 1, likesAfterAddition); // replace the old value from the Array with the new value
let sum = likesTable.reduce(function(a, b){return a + b;}); // return the sum of the array
let globalNumberOfLikes = sum; // the sum of the array
individualLikeBox[index].innerHTML = `<span'>${likesAfterAddition}</span>`
totalLikesDivBox.innerHTML = `<div class="Likes">${globalNumberOfLikes}<i class="fas fa-heart"></i></div>`
console.log(likesTable)
}))
}
instead of using for loop to set event listeners which is not efficient
you can use the feature of bubbling, so when any of dom element is clicked, the event will bubble up of its parent elements sequentially till it reaches the parent dom
//increment likes on click
function incrementLikesOnClick() {
document.addEventListener("DOMContentLoaded", function(event) {
// Your code to run since DOM is loaded and ready
document.addEventListener('click', () => {
let clicked = event.target;
//element with class heartIcon is clicked and it doesnt have activeRed class
if(clicked.classList.contains('heartIcon') && !clicked.classList.contains('activeRed')){
let productContainer = clicked.parentElement.parentElement; // till you reach the product container
const individualLikeBox = productContainer.getElementsByClassName('under-photo-info');
const totalLikesDivBox = productContainer.getElementById("likesBox");
clicked.classList.add('activeRed');
// ..whatever extra logic you want to add
}
});
});
}
If the like icon is a button (which I assume it is). U can just add a 'disabled' attribute to it as part of the event handler (for the 'click' eventListener).
'When present, it specifies that the button should be disabled.
A disabled button is unusable and un-clickable.' (source)
I would calculate the total likes based on the presence of an "active" class on each button.
const totalLikesEl = document.querySelector('#total-likes');
const updateTotalLikes = () => {
totalLikesEl.textContent = document.querySelectorAll('.like.active').length;
};
const toggleLike = (e) => {
const button = e.currentTarget.classList.toggle('active');
updateTotalLikes();
};
document.querySelectorAll('.like').forEach(likeBtn => {
likeBtn.addEventListener('click', toggleLike);
});
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
}
.cards {
display: flex;
flex-direction: row-wrap;
justify-content: center;
}
.card {
display: flex;
flex-direction: column;
padding: 0.25em;
margin: 0.5em;
border: thin solid grey;
}
.card-content {
background: grey;
width: 6em;
height: 6em;
}
.card-actions {
display: flex;
flex-direction: row;
justify-content: flex-end;
margin-top: 0.5em;
}
.like > .fa-heart {
color: grey;
}
.like.active > .fa-heart {
color: red;
}
.example-1 .card-content {
background: rgb(63,94,251);
background: radial-gradient(circle, rgba(63,94,251,1) 0%, rgba(252,70,168,1) 100%);
}
.example-2 .card-content {
background: rgb(251,63,94);
background: radial-gradient(circle, rgba(251, 63,94,1) 0%, rgba(168,252,70,1) 100%);
}
.example-3 .card-content {
background: rgb(94,63,251);
background: radial-gradient(circle, rgba(94,63,251,1) 0%, rgba(70,252,168,1) 100%);
}
.status {
text-align: center;
margin-top: 0.5em;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet"/>
<div class="cards">
<div class="card example-1">
<div class="card-content"></div>
<div class="card-actions">
<button class="like">
Like <i class="fas fa-heart"></i>
</button>
</div>
</div>
<div class="card example-2">
<div class="card-content"></div>
<div class="card-actions">
<button class="like">
Like <i class="fas fa-heart"></i>
</button>
</div>
</div>
<div class="card example-3">
<div class="card-content"></div>
<div class="card-actions">
<button class="like">
Like <i class="fas fa-heart"></i>
</button>
</div>
</div>
</div>
<div class="status">
<strong>Total Likes:</strong>
<span id="total-likes">0</span>
</div>

Troubles when closing div by clicking outside it

I am working on creating a website and I am stuck on a certain function I am trying to build. I am trying to slide back a div to its original place if anyplace outside the div is clicked. I've looked everywhere on stack but to no avail. What happens to me is that the background clicks remain active at all times, I only need it to be active when the div has slid to become sort of a popup.
Here is my jsfiddle: https://jsfiddle.net/DTcHh/10567/
Here is the jquery for one of the divs (the rest are similar)
var text = 1;
$('.login1').click(function(e){
e.preventDefault();
$('.loginform_hidden').toggleClass('loginform_visible');
$(".animateSlide").toggle(300, function(){
$(this).focus();
});
if(text == 1){
$(".div1").toggleClass("animateSlide col-xs-12");
$('.login1').html('Go Back');
$('.imageOne').toggleClass('animateSlideTop');
// If an event gets to the body
$('.div2, .div3, .patientAccess').toggle("fast");
document.addEventListener('mouseup', function(event){
var box = document.getElementsByClassName('animateSlide');
if (event.target != box && event.target.parentNode != box){
$('.div2, .div3, .patientAccess').toggle("fast");
$(".div1").toggleClass("animateSlide ");
text=0;
}
});
text = 0;
} else {
$(".div1").toggleClass("animateSlide");
$('.login1').html('Start Animation');
$('.imageOne').toggleClass('animateSlideTop');
$('.div2, .div3, .patientAccess').toggle("fast");
text = 1;
}
});
$(".div1").on('blur', function() {
$(this).fadeOut(300);
});
EDIT: The jsfiddle now incorporates what I have been trying to utilize.
As a demonstration, I built a simplified version of what I think you're aiming to achieve.
I'm using the "event.target" method described in this answer.
Since you are using CSS transitions, I'm using jQuery to detect the end of those transitions using a method found here.
I've given all boxes a class of "animbox" so that they can all be referenced as a group. I've also given each box its own ID so it can be styled individually with CSS.
I've commented the code in an attempt to explain what's going on.
// define all box elements
var $allBoxes = jQuery('.animbox');
// FUNCTION TO SHOW A SELECTED BOX
function showBox($thisBox) {
$allBoxes.hide(); // hide all boxes
$thisBox.show().addClass('animateSlide'); // show and animate selected box
$('div.login', $thisBox).text("Go Back"); // change the selected box's link text
}
// FUNCTION TO RETURN BOXES TO THE DEFAULT STATE
function restoreDefaultState() {
var $thisBox = jQuery('div.animbox.animateSlide'); // identify an open box
if ($thisBox.length) { // if a box is open...
$thisBox.removeClass('animateSlide'); // close this box
$thisBox.one('webkitTransitionEnd'+
' otransitionend'+
' oTransitionEnd'+
' msTransitionEnd'+
' transitionend', function(e) { // when the box is closed...
$allBoxes.show(); // show all boxes
$('div.login', $thisBox).text("Start Animation"); // change the link text
});
}
}
// CLICK HANDLER FOR ALL "login" TRIGGERS
$('div.login').click(function(e) {
var $thisBox = $(this).closest('div.animbox'); // identify clicked box
if (!$thisBox.hasClass('animateSlide')) { // if the box is not open...
showBox($thisBox); // open it
} else { // otherwise...
restoreDefaultState(); // restore the default state
}
});
// CLICK HANDLER TO RESTORE DEFAULT STATE WHEN CLICK HAPPENS OUTSIDE A BOX
$('body').click(function(evt) {
if ($(evt.target).hasClass('animbox') || // if a box is clicked...
$(evt.target).closest('div.animbox').length > 0) { // or a child of a box...
return; // cancel
}
restoreDefaultState(); // restore the default state
});
div.container-fluid {
background-color: #464646;
}
.v-center {
display: table;
height: 100vh;
}
.content {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.patientAccess {
transition: all .5s;
background: white;
height: 200px;
width: 90%;
position: absolute;
opacity: 0.7;
margin-top: -100px;
}
.patientAccess p {
font-size: 1.5em;
font-weight: bold;
}
div.animbox {
transition: all .5s;
position: absolute;
cursor: pointer;
width: 90%;
height: 100px;
opacity: 0.7;
}
div#animbox1 {
background: #e76700;
}
div#animbox2 {
background: #74b8fe;
}
div#animbox3 {
background: #848484;
}
div.login {
color: white;
font-size: 1em;
cursor: pointer;
}
div#animbox1.animateSlide {
width: 200px;
height: 300px;
margin-left: 100px;
opacity: 1;
}
div#animbox2.animateSlide {
width: 250px;
height: 450px;
margin-left: -25px;
margin-top: -150px;
}
div#animbox3.animateSlide {
width: 150px;
height: 150px;
opacity: .5;
margin-left: -100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<div class="container-fluid">
<div class="row-fluid">
<div class="col-xs-12 v-center">
<div class="content text-center">
<div class="col-xs-2 animated slideInRight "></div>
<div class="col-xs-2 animated slideInRight ">
<div class="patientAccess">
<p>Patient Resource Access</p>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox1">
<div class="login">Start Animation</div>
<div class="loginform_hidden "></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox2">
<div class="login">Start Animation</div>
<div class="registrationform_hidden"></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox3">
<div class="login">Start Animation</div>
</div>
</div>
</div>
</div>
</div>
</div>
You can namespace an event handler using this syntax:
$("#myElement").on("click.myEventHandlerName", function() { ... });
At any point, you can remove the event handler again by calling
$("#myElement").off("click.myEventHandlerName", "#myElement");

Categories