Onclick Console Message Not Firing (javascript) - javascript

I'm building a simple flexbox navigation, when the screen size is below 980px a mobile version of the menu shows.
I'm building the javascript to do this - does anyone know why my console.log message won't show when the mobile version of the menu is clicked?
It's driving me around the twist.
You have to reduce the window below 980px to see what i mean.
https://codepen.io/emilychews/pen/eezYox?editors=1111
var mobileMenuButton = document.querySelector('#mobile-menu')
var mobileMenuItems = document.querySelector('#nav-menu')
// TOGGLE MOBILE MENU
var mobileMenu = false
if (mobileMenu === false) {
function showMobileMenu() {
mobileMenuButton.onclick(function() {
console.log("clicked");
})
mobileMenu = true
}
}
* {
padding: 0;
margin: 0;
}
p {
color: white;
}
header {
width: 100%;
}
#main-nav {
width: inherit;
height: 100px;
background: red;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 10px 5% 10px 5%;
align-items: center;
}
#logo-wrapper {
width: 150px;
height: 75px;
background-color: grey;
}
#nav-menu {
display: flex;
margin-left: auto;
}
#main-nav ul li {
list-style-type: none;
padding: 5px 10px;
background: pink;
margin: 0 5px;
}
#mobile-menu {
display: none;
}
#media only screen and (max-width: 980px) {
#mobile-menu {
display: block;
background: blue;
padding: 5px 10px;
box-sizing: border-box;
cursor: pointer;
z-index: 99;
}
#main-nav ul {
display: none;
}
}
<header>
<nav id="main-nav">
<div id="logo-wrapper"></div>
<ul id="nav-menu">
<li class="menu-item menu-item-1"><a>Home</a></li>
<li class="menu-item menu-item-2"><a>About</a></li>
<li class="menu-item menu-item-3"><a>Contact</a></li>
</ul>
<div id="mobile-menu"><a>Menu</a></div>
</nav>
</header>

Well there are few problems, You never call showMobileMenufunction, so event is never binded to that element. onclick is not a function. I believe You want something like:
var mobileMenuButton = document.querySelector('#mobile-menu')
var mobileMenuItems = document.querySelector('#nav-menu')
// TOGGLE MOBILE MENU
var mobileMenu = false
mobileMenuButton.addEventListener('click', function() {
toggleMobileMenu();
})
function toggleMobileMenu() {
if (mobileMenu === false) {
console.log("clicked");
mobileMenu = true
} else {
console.log("not clicked");
mobileMenu = false
}
}

Related

Open an element under a button when the button is clicked in React

Having this design:
There is a table with some rows, when a row is clicked, that kebab button (3 vertical dots) is visible.
When the button is clicked it should open an element which has some data in it - in this case a list of actions.
The part with showing the kebab button is working:
{
id: 'my-button',
Cell: ({ cell }: CellProps<MyCell>) => {
if (cell.row.index === selectedIndex) {
return (
<div>
<Button
icon={<ThreeDots />}
onClick={toggleModal}
/>
</div>
);
}
return <div></div>;
}
}
when the row is clicked, the 3-dots button is visible. There is also a boolean which is initially set to false but toggles its value when the button is clicked (toggleModal).
But how can that element with the list added under the button?
Done something like:
{isModalOpened ? <div className='absolute'>test</div> : null}
Or maybe is there any online solution to fix this?
To fix this issue, you just need to use:
event.stopPropagation();
Please check my demo below:
function rowClick() {
const status = document.getElementById("actions").style.display;
document.getElementById("actions").style.display =
status === "block" ? "none" : "block";
}
function btnClick(event) {
event.stopPropagation();
const status = document.getElementById("nav").style.display;
document.getElementById("nav").style.display =
status === "block" ? "none" : "block";
}
.row {
width: 80%;
display: flex;
align-items: center;
justify-content: space-between;
background: lightblue;
padding: 10px 20px;
}
.actions {
display: none;
position: relative;
z-index: 1;
}
nav {
display: none;
position: absolute;
top: 50px;
right: 0;
z-index: 10;
background: white;
border: 1px solid grey;
min-width: 170px;
}
nav p {
padding: 10px;
border-bottom: 1px solid grey;
margin: 0;
}
nav p:last-child {
border-bottom: 0;
}
.btn {
display: inline-block;
width: 50px;
height: 50px;
line-height: 50px;
background: green;
text-align: center;
cursor: pointer;
color: white;
}
<div class='row' onclick="rowClick()">
This is a row <div class="actions" id="actions"><span class="btn" onclick="btnClick(event)">⁝</span><nav id="nav"><p>Do this</p><p>Do that</p></nav></div></div>

JavaScript If and else statement w/function calls not producing expected result

I have a mobile menu that includes four list items. When you click on the "Features" list item, another unordered list is supposed to populate below it, and when you click it again, it's supposed to close it.
Here's my issue:
Inside the addEventListener function, I am calling two other functions (displayType and displayTypeCheck) inside the if, and else statement. When I do this and click on the "Features" list item, it opens but does not close when I click it again.
If I don't use the displayType and displayTypeCheck functions in the if and else statement and click on the "Features" list item, the UL will both open and close.
Why does the if and else statement that calls the other two functions not work, and how do I get it to work?
In the provided Javascript code below, the if and else statement that's commented out works, and the block that's not commented out is the code that doesn't entirely work.
const menuIcon = document.querySelector(".mobile-menu-icon");
const mobileMenu = document.querySelector(".mobile-menu");
const closeMenuIcon = document.querySelector(".close-menu-icon");
const featuresMobile = document.querySelector(".features-mobile");
const featuresMobileDropdown = document.querySelector(".features-mobile-dropdown");
const overlay = document.querySelector(".overlay");
function displayType(element, displayValue) {
element.style.display = displayValue;
}
function displayTypeCheck(element, displayValue) {
element.style.display === displayValue;
}
menuIcon.addEventListener("click", function () {
displayType(mobileMenu, 'block');
displayType(overlay, 'block');
});
closeMenuIcon.addEventListener("click", function () {
displayType(mobileMenu, 'none');
displayType(overlay, 'none');
});
featuresMobile.addEventListener("click", function () {
// if (featuresMobileDropdown.style.display === "block") {
// featuresMobileDropdown.style.display = "none";
// } else {
// featuresMobileDropdown.style.display = "block";
// }
if (displayTypeCheck(featuresMobileDropdown, "block")) {
displayType(featuresMobileDropdown, "none");
} else {
displayType(featuresMobileDropdown, "block");
}
});
#import url("https://fonts.googleapis.com/css2?family=Epilogue:wght#500;700&display=swap");
:root {
--almostWhite: hsl(0, 0%, 98%);
--mediumGray: hsl(0, 0%, 41%);
--almostBlack: hsl(0, 0%, 8%);
--navDropDownColor: #e9ecef;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
body {
min-height: 100vh;
font-family: "Epilogue", sans-serif;
background-color: var(--almostWhite);
}
header {
padding: .9375rem 2.5rem .9375rem 2.5rem;
max-width: 100rem;
margin: auto;
}
header nav {
display: flex;
align-items: center;
justify-content: flex-end;
}
header nav ul li {
cursor: pointer;
}
.register {
border: .125rem solid var(--mediumGray);
padding: .625rem .9375rem;
border-radius: .8125rem;
}
.mobile-menu-icon {
height: 3.125rem;
}
.mobile-menu-icon {
display: block;
cursor: pointer;
}
.mobile-menu .mobile-nav-links {
margin-top: 4.375em;
padding-left: .9375em;
color: var(--mediumGray);
}
.mobile-menu ul li {
padding: .625em;
}
.mobile-menu .mobile-nav-links li ul {
margin-left: .625em;
margin-top: .625em;
display: none;
}
.mobile-menu {
background-color: white;
width: 18.75em;
height: 100vh;
position: absolute;
top: 0;
right: 0;
z-index: 2;
display: none;
}
.close-menu-icon {
margin-left: auto;
margin-right: 1.25em;
margin-top: 1.25em;
display: block;
cursor: pointer;
height: 3.125em;
}
.login-register-mobile-container {
color: var(--mediumGray);
width: 90%;
margin: 3.125em auto;
}
.login-register-mobile-container span {
display: block;
text-align: center;
cursor: pointer;
}
.login-register-mobile-container span:first-child {
margin-bottom: 1.25em;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(.1875rem);
z-index: 1;
display: none;
}
<header>
<nav>
<img class="mobile-menu-icon" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Hamburger_icon.svg/2048px-Hamburger_icon.svg.png" alt="" />
<div class="mobile-menu">
<img
class="close-menu-icon"
src="https://cdn4.iconfinder.com/data/icons/user-interface-131/32/close-512.png"
alt=""
/>
<ul class="mobile-nav-links">
<li class="features-mobile">Features
<ul class="features-mobile-dropdown">
<li>Todo List</li>
<li>Calenders</li>
<li>Reminders</li>
<li>Planning</li>
</ul>
</li>
<li class="company-mobile">Company</li>
<li>Careers</li>
<li>About</li>
</ul>
<div class="login-register-mobile-container">
<span class="login">Login</span>
<span class="register">Register</span>
</div>
</div>
</nav>
<div class="overlay"></div>
</header>
You forgot the return statement.
function displayTypeCheck(element, displayValue) {
return element.style.display === displayValue;
}
Otherwise the function will always return undefined which is a falsey value.
Within the displayTypeCheck function, you aren't returning the boolean result of the conditions.
Without the return statement, it is returning void
function displayTypeCheck(element, displayValue) {
return element.style.display === displayValue;
}

Changing background color doesn't work well

I am trying to change the background color of my webpage using a hamburger menu. There are 4 color options on my hamburger menu. I managed to get a change on the background when clicking on the color of my choice. But that change only happens once. When I clicked another color and come back to click that same color from earlier on, it doesn't respond. The color seems to change only once, and not more than that.
The repository to my GitHub code is here: https://github.com/tand100b/Winc_Academy
const changeColorButton1 = document.getElementById("color1");
changeColorButton1.addEventListener("click", function() {
changeClassRedBackground();
});
const changeColorButton2 = document.getElementById("color2");
changeColorButton2.addEventListener("click", function() {
changeClassOrangeBackground();
});
const changeColorButton3 = document.getElementById("color3");
changeColorButton3.addEventListener("click", function() {
changeClassPurpleBackground();
});
const changeColorButton4 = document.getElementById("color4");
changeColorButton4.addEventListener("click", function() {
changeClassGreenBackground();
});
const changeClassRedBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("red-background");
}
const changeClassOrangeBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("orange-background");
};
const changeClassPurpleBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("purple-background");
};
const changeClassGreenBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("green-background");
};
body {
background-color: pink;
}
.red-background {
background-color: red;
}
.orange-background {
background-color: orange;
}
.purple-background {
background-color: purple;
}
.green-background {
background-color: green;
}
.btn-toggle-nav {
width: 60px;
height: 20%;
background-color: #f98f39;
background-image: url("https://i.stack.imgur.com/tniUv.png");
background-repeat: no-repeat;
background-size: 60%;
background-position: center;
cursor: pointer;
}
.btn-toggle-nav:hover {
opacity: 0.5;
}
.navbar ul {
padding-top: 15px;
/* visibility: hidden; */
}
.navbar ul li {
line-height: 60px;
list-style: none;
background-color: white;
width: 300px;
padding-top: 0px;
padding-top: 0px;
}
.navbar ul li a {
display: block;
height: 60px;
padding: 0 10px;
text-decoration: none;
font-family: arial;
font-size: 16px;
}
.navbar {
background-color: red;
width: 50px;
padding: 0 5px;
height: calc(100vh-60px);
z-index: 1000;
}
.list {
margin-top: 0px;
}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<div class="btn-toggle-nav"></div>
<aside class="navbar">
<ul class="list">
<li><a id="color1" href="#">Red</a></li>
<li><a id="color2" href="#">Orange</a></li>
<li><a id="color3" href="#">Purple</a></li>
<li><a id="color4" href="#">Green</a></li>
</ul>
</aside>
Can someone please look at my code and suggest what I can do?
Firstly, I suggest declaring variable bodyElement only once at the top of the file because each time it would be the same body element:
const bodyElement = document.body
Next, we create function that will check if body has any style classes in its classList. If it's not empty (length more than one) we remove all classes, and do nothing otherwise:
const isBodyHasStyle = () => bodyElement.classList.length ? bodyElement.classList = '' : null
Then, on each button click we going to call our new function:
changeColorButton1.addEventListener("click", function() {
isBodyHasStyle()
changeClassRedBackground();
});
Do the same with other buttons.
You need to make sure that you don't have multiple classes conflicting with each other, also try to DRY your code, here is an alternative I came up with:
const changeColor = (e) => {
const bodyElement = document.querySelector('body');
const colorIdMap = {
"color1": "red-background",
"color2": "orange-background",
"color3": "purple-background",
"color4": "green-background"
}
bodyElement.className = colorIdMap[e.target.id];
}
const btns = document.querySelectorAll('.list li');
btns.forEach(btn => btn.addEventListener('click', changeColor))
An easier way to accomplish this is by setting a data attribute on the background, based on the selected color. Just add a color data value to each of the menu items and set the body background to that color.
const toggleMenu = (event) => {
event.target.closest('.navbar').classList.toggle('open');
};
const changeColor = (event) => {
document.body.dataset.background = event.target.dataset.color;
toggleMenu(event); /* do not call ~ to stay open */
};
document.querySelector('.btn-toggle-nav')
.addEventListener('click', toggleMenu)
document.querySelectorAll('.color-picker')
.forEach(e => e.addEventListener('click', changeColor));
/* CSS reset */
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
body { display: flex; background-color: #222; }
ul { list-style-type: none; margin: 0; }
body[data-background="red"] { background-color: red }
body[data-background="orange"] { background-color: orange }
body[data-background="purple"] { background-color: purple }
body[data-background="green"] { background-color: green }
body[data-background="default"] { /* Do not set the background-color */ }
a[data-color="red"] { color: red; }
a[data-color="orange"] { color: orange; }
a[data-color="purple"] { color: purple; }
a[data-color="green"] { color: green; }
a[data-color="default"] { color: #222; }
.list {
position: absolute;
display: none; /* hide menu (default) */
flex-direction: column;
gap: 0.5em;
padding: 0.5em;
width: 6em;
left: 2em;
background: #444;
}
.list li a { text-decoration: none; font-weight: bold; }
.list li a:hover { text-decoration: underline; }
.navbar {
position: relative;
width: 2em;
background-color: #444;
}
.navbar.open .list {
display: flex; /* show menu */
}
.btn-toggle-nav {
width: 2em;
height: 2em;
background-image: url("https://i.stack.imgur.com/tniUv.png");
background-repeat: no-repeat;
background-size: 60%;
background-position: center;
cursor: pointer;
}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<aside class="navbar">
<div class="btn-toggle-nav"></div>
<ul class="list">
<li><a class="color-picker" href="#" data-color="red">Red</a></li>
<li><a class="color-picker" href="#" data-color="orange">Orange</a></li>
<li><a class="color-picker" href="#" data-color="purple">Purple</a></li>
<li><a class="color-picker" href="#" data-color="green">Green</a></li>
<li><a class="color-picker" href="#" data-color="default">Default</a></li>
</ul>
</aside>

How to remove div re-positioning when zoom up? (shrink the browser)

I've made a simple slider that responses the mouseenter event.
The algorithm is when if the user moves its mouse pointer one of Appear menu contents, a div called .slate goes down.
My problem is in Chrome or Opera, when the user zoomed up by using CTRL + Mouse Wheel Up, the .slate is going to spills a bit and goes back up smoothly while Firefox doesn't:
I'm looking for a solution to remove this unwanted re-positioning except not using transition.
I've tried to give the transition more dynamically to resolve the problem. Add the transition when mouse entered to the Appear, remove it when mouse entered to Disappear.
But this one didn't work with an another new issue. The transition is going to ignore when I wag the mouse like this:
Are there any ways to resolve this problem?
CodePen: Original Code / Attempt 2
Snippet (Original):
'use strict';
class Slate {
constructor(header) {
this.header = document.querySelector(header);
this.slate = document.querySelector('.slate');
this.menu = this.header.querySelector('.menu');
this.contents = this.menu.querySelectorAll('.contents');
this.addEvent();
}
addEvent() {
this.contents.forEach((cur, idx) => {
cur.addEventListener('mouseenter', (e) => this.expand(e, idx));
})
}
expand(e, index) {
let lesser = (index < 2),
ternary = {
toggle: (lesser) ? this.slate.classList.add('toggle') : this.slate.classList.remove('toggle')
};
}
}
const proSlate = new Slate('header');
* {
margin: 0;
padding: 0;
font-family: Helvetica;
}
div, section, header {
position: relative;
}
ul, li {
list-style-type: none;
}
header, .slate {
width: 800px;
}
header {
height: 100px;
line-height: 100px;
background-color: rgba(69, 255, 0, .4);
}
.slate {
height: 400px;
line-height: 400px;
text-align: center;
color: white;
background-color: steelblue;
top: -25rem;
transition: top 500ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
z-index: -1;
font-size: 4rem;
}
.menu {
width: 100%;
display: flex;
}
.contents {
margin: 0 20px;
}
.toggle {
top: 0;
}
<header>
<ul class="menu">
<li class="contents">Appear</li>
<li class="contents">Appear</li>
<li class="contents">Disapper</li>
<li class="contents">Disapper</li>
</ul>
</header>
<div class="slate">
CONTEXT OF SLATE
</div>
Instead of using top, go for transform
'use strict';
class Slate {
constructor(header) {
this.header = document.querySelector(header);
this.slate = document.querySelector('.slate');
this.menu = this.header.querySelector('.menu');
this.contents = this.menu.querySelectorAll('.contents');
this.addEvent();
}
addEvent() {
this.contents.forEach((cur, idx) => {
cur.addEventListener('mouseenter', (e) => this.expand(e, idx));
})
}
expand(e, index) {
let lesser = (index < 2),
ternary = {
toggle: (lesser) ? this.slate.classList.add('toggle') : this.slate.classList.remove('toggle')
};
}
}
const proSlate = new Slate('header');
* {
margin: 0;
padding: 0;
font-family: Helvetica;
}
div,
section,
header {
position: relative;
}
ul,
li {
list-style-type: none;
}
header,
.slate {
width: 800px;
}
header {
height: 100px;
line-height: 100px;
background-color: rgba(69, 255, 0, .4);
}
.slate {
height: 400px;
line-height: 400px;
text-align: center;
color: white;
background-color: steelblue;
transform: translateY(-100%);
transition: transform 500ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
z-index: -1;
font-size: 4rem;
}
.menu {
width: 100%;
display: flex;
}
.contents {
margin: 0 20px;
}
.toggle {
transform: translateY(0);
}
<header>
<ul class="menu">
<li class="contents">Appear</li>
<li class="contents">Appear</li>
<li class="contents">Disapper</li>
<li class="contents">Disapper</li>
</ul>
</header>
<div class="slate">
CONTEXT OF SLATE
</div>

Translating jQuery to Vanilla JS issue

I was watching a tutorial that used jQuery and wanted to turn it into JS, but my code is broken - was hoping someone could help me with this:
Tutorial JS:
$(function() {
var btn = $('button');
var progressBar = $('.progressbar');
btn.click(function() {
progressBar.find('li.active').next().addClass('active');
})
})
Taken from URL:http://www.kodhus.com/kodity/codify/kod/mGXAtb
Here is my failed attempt at rewriting the jQuery using JavaScript DOM:
var btn1 = document.getElementsByTagName('BUTTON');
var progBar = document.getElementsByClassName('progressbar');
function clickMe1() {
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
return emlClass.nextElementSibling.addClass('active');
}
btn1.addEventListener("click", clickMe1, false);
where did I go wrong?
Working fiddle.
Your code will work after several changes check the notes below :
You've missed addClass() there it's a jQuery function, for vanilla JS use .classList.add() instead:
return emlClass.nextElementSibling.classList.add("active");
querySelectorAll(); will return a list of nodes you have to loop through them and add class, use :
var emlClass = progBar.querySelectorAll("li.active");
Instead of :
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
Then loop and add active class:
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
getElementsByTagName() and getElementsByClassName() will also returns a list of nodes with given name, you have to specify which one you want to pick (selecting the first in my example) :
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
Hope this helps.
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
function clickMe1() {
var emlClass = progBar.querySelectorAll("li.active");
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
}
btn1.addEventListener("click", clickMe1, false);
.container {
width: 100%;
}
.progressbar {
counter-reset: step;
margin: 0;
margin-top: 50px;
padding: 0;
}
.progressbar li {
list-style-type: none;
float: left;
width: 33.33%;
position: relative;
text-align: center;
}
.progressbar li:before {
content: counter(step);
counter-increment: step;
width: 30px;
height: 30px;
line-height: 30px;
border: 2px solid #ddd;
display: block;
text-align: center;
margin: 0 auto 10px auto;
border-radius: 50%;
background-color: white;
}
.progressbar li:after {
content: '';
position: absolute;
width: 100%;
height: 2px;
background-color: #ddd;
top: 15px;
left: -50%;
z-index: -1;
}
.progressbar li:first-child:after {
content: none;
}
.progressbar li.active {
color: green;
}
.progressbar li.active:before {
border-color: green;
}
.progressbar li.active + li:after {
background-color: green;
}
button {
position: relative;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 2px;
left: 50%;
margin-top: 30px;
transform: translate(-50%);
cursor: pointer;
outline: none;
}
button:hover {
opacity: 0.8;
}
<div class="container">
<ul class="progressbar">
<li class="active">Step 1</li>
<li>Step 2</li>
<li>Step 3</li>
</ul>
</div>
<button>Next step</button>
.querySelectorAll("li") will return an array (or an array-like object) with one or more <li> tags. So you need to either:
loop through every <li> in that list and do the rest,
or just take the first item from that list if you don't want to worry about there being more than one li in the page,
or use .querySelector (not .querySelectorAll) to just take the first <li> for you.
MDN

Categories