Basic jquery toggleClass not working in es6 class - javascript

I have a menu that I want to show when an icon is clicked. I have the menu hidden by default when the page loads. I am using jQuerys toggleClass() method. When I click the icon the show class is never added to the .menu. The menu class highlights in the browser dev tools each time I click but no class is being added to it.
If I use the addClass() method then the class is added but I want to be able to toggle the show class so the menu is able to be shown and hidden while clicking the same icon/element.
HTML
<i class="fa fa-ellipsis-v"></i>
<div class="menu">
<div id="context-menu">
Item 1
Item 2
Item 3
Item 4
</div>
</div>
Menu.js
class Menu {
constructor() {
this.menu = document.querySelector('.menu');
this.ellipsis = document.querySelector('.fa.fa-ellipsis-v');
this.callEvent();
}
callEvent() {
this.ellipsis.addEventListener('click',this.showMenu.bind(this));
}
showMenu(e){
e.preventDefault();
$('.menu').toggleClass('show');
}
}
CSS
.menu {
display:none;
}
.show{
display:block;
}

This shouldn't be an answer but it really can't be a comment. I used your code, added a little css to make things viewable and guessed at the html (but that shouldn't make a difference). The code works as expected.
class Menu {
constructor() {
this.menu = document.querySelector('.menu');
this.ellipsis = document.querySelector('.fa.fa-ellipsis-v');
this.callEvent();
}
callEvent() {
this.ellipsis.addEventListener('click',this.showMenu.bind(this));
}
showMenu(e){
e.preventDefault();
$('.menu').toggleClass('show');
}
}
var menu = new Menu();
.menu {
display:none;
background-color: blue;
height: 100px;
width: 100px;
}
.show{
display:block;
}
.fa-ellipsis-v {
font-weight: bold;
font-size: 20px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="menu"></div>
<span class="fa fa-ellipsis-v">...</span>

See below. I'm using display:flex instead of display:block for layout purposes.
class Menu {
constructor() {
this.menu = document.querySelector('.menu');
this.ellipsis = document.querySelector('.fa.fa-ellipsis-v');
this.callEvent();
}
callEvent() {
this.ellipsis.addEventListener('click', () => {
$('.menu').toggleClass('show');
});
}
}
const dummy = new Menu();
.menu {
display: none;
}
.show {
display: flex;
}
nav {
display: flex;
}
ul {
list-style: none;
margin: 0;
justify-content: space-around;
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<nav>
<i class="fa fa-ellipsis-v"></i>
<ul class="menu">
<li>This</li>
<li>is</li>
<li>a</li>
<li>menu</li>
</ul>
</nav>

Related

How to hide navigation bar on link click?

I have 3 buttons and a responsive hamburger menu. Everything works as expected, but I can't think of a way to make a navigation bar go away as soon as I click on a button.
The program is supposed to work like this: clicking hamburger menu activates 3 buttons, whenever user clicks on any of those 3 buttons it hides the buttons and only leaves the button that was clicked.
This is the wanted outcome:
This is my code so far.
html:
<div class="selectSection">
<button type="button" data-number="1" class="active">1</button>
<button type="button" data-number="2">2</button>
<button type="button" data-number="3">3</button>
</div>
<div class="hamburger">
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
</div>
<div>
<div class="content" data-number="1">
<p>1st page</p>
</div>
<div class="content" data-number="2">
<p>2nd page</p>
</div>
<div class="content" data-number="3">
<p>3rd page</p>
</div>
</div>
css
.content:not(:first-child) {
display: none;
}
.active {
color: orange !important;
}
.hamburger {
display: none;
}
#media all and (max-width: 800px) {
.hamburger {
display: inline-block;
cursor: pointer;
z-index: 7;
}
.hamburger .line {
width: 30px;
height: 3px;
background: black;
margin: 6px 0px;
}
.selectSection {
display: none;
overflow: hidden;
}
.selectSection.active {
display: block;
}
}
js
// change active class, show the clicked element only and hide the others
// grab all the buttons
let Buttons = document.querySelectorAll(".selectSection button");
// loop through the buttons using for..of
for (let button of Buttons) {
// listen for a click event
button.addEventListener("click", (e) => {
// et = event target
const et = e.target;
// slect active class
const active = document.querySelector(".active");
// check for the button that has active class and remove it
if (active) {
active.classList.remove("active");
}
// add active class to the clicked element
et.classList.add("active");
// select all classes with the name content
let allContent = document.querySelectorAll(".content");
// loop through all content classes
for (let content of allContent) {
// display the content if the class has the same data-attribute as the button
if (
content.getAttribute("data-number") ===
button.getAttribute("data-number")
) {
content.style.display = "block";
}
// if it's not equal then hide it.
else {
content.style.display = "none";
}
}
});
}
hamburger = document.querySelector(".hamburger");
hamburger.onclick = function () {
navBar = document.querySelector(".selectSection");
navBar.classList.toggle("activate");
};
This is the demo:
https://codepen.io/f4kermak3r/pen/ExRPKzJ
you are using the wrong css class in your js file. At line 44, you must change navBar.classList.toggle("activate") to navBar.classList.toggle("active"). That should work.

TypeError: Cannot read properties of null (reading 'classList')

I am working in a nextjs application. I was just trying to make a dropdown.
This is my full code:
import React from 'react'
import Link from 'next/link'
import styles from './header.module.css'
const Header = () => {
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
const myFunction =()=>{
document.getElementById(styles.myDropdown).classList.toggle("show");
}
// Close the dropdown menu if the user clicks outside of it
if (typeof window !== "undefined") {
window.onclick = function (event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
}
return (
<div className={styles.header}>
<div className={styles.logoLink}>
<img src="images/itacs.png" alt="" className={styles.logo} />
</div>
<div className={styles.services}>
<ul>
<li><Link href="/page">Docs</Link></li>
<li><Link href="/page">Learn</Link></li>
<li><Link href="/page">Projects</Link></li>
<li><Link href="/page">Blog</Link></li>
<div className={styles.dropdown}>
<button onClick={myFunction} className={styles.dropbtn}>Dropdown</button>
<div id={styles.myDropdown} className={styles.dropdownContent}>
Link 1
Link 2
Link 3
</div>
</div>
</ul>
</div>
<form action="" className={styles.headerForm}>
<a href="/" className={styles.logIn}>Log In</a>
<a href="/" className={styles.getStarted}>Get Started</a>
</form>
</div>
)
}
export default Header
Here I have just added the classlist in the id of div!
I am trying to show the below div when the button is clicked as a dropdown menu.
I am not able to figure this out!
For anyone who is wondering what is there present in css file :
/* dropdown */
/* Dropdown Button */
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdownContent {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdownContent a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
.dropdownContent a:hover {background-color: #ddd}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
.show {display:block;}
Any Help would be appreciated!
It should be <div className="dropdown"> instead of <div class="dropdown"> and <div id={styles.myDropdown} className={styles.dropdownContent}>
You would also avoid doing vanilla js inside a react/next app.
You would instead have a react state like this:
const [dropdownToggled, toggleDropdown] = useState(false);
const handleClick = () => {
toggleDropdown(!dropdownToggled);
};
And have a condition on whether your jsx have a className hidden that sets display: none
something like this:
<div
className={`${styles.dropdownContent}
${dropdownToggled ? styles.hidden : ""}`}
>
Link 1
Link 2
Link 3
</div>
To make the dropdown close when the user clicks outside, you would have a div like this:
<div
className={styles.backdrop}
onClick={() => toggleDropdown(true)}
></div>
that is styled like this:
.backdrop {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
}
Now since this div takes the whole screen and is positioned absolute when the user clicks anywhere on the page the onClick will fire and toggle the dropdown.
Working CodeSandbox.
import React, { useState } from 'react'
import Link from 'next/link'
import styles from './header.module.css'
const Header = () => {
const [dropdownToggled, toggleDropdown] = useState(false);
const handleClick = () => {
toggleDropdown(!dropdownToggled);
console.log("boy");
};
// Close the dropdown menu if the user clicks outside of it
if (typeof window !== "undefined") {
window.onclick = function (event) {
if (!event.target.matches('#dropbtn')) {
var dropdowns = document.getElementsByClassName(styles.dropdownContent);
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
}
return (
<div className={styles.header}>
<div className={styles.logoLink}>
<img src="images/itacs.png" alt="" className={styles.logo} />
</div>
<div className={styles.services}>
<ul>
<li><Link href="/page">Docs</Link></li>
<li><Link href="/page">Learn</Link></li>
<li><Link href="/page">Projects</Link></li>
<li><Link href="/page">Blog</Link></li>
<div className={styles.dropdown}>
<button onClick={handleClick} id="dropbtn" className={styles.dropbtn}>Dropdown</button>
<div
className={`${styles.dropdownContent} ${dropdownToggled ? styles.show : ""}`}
>
Link 1
Link 2
Link 3
</div>
</div>
</ul>
</div>
<form action="" className={styles.headerForm}>
<a href="/" className={styles.logIn}>Log In</a>
<a href="/" className={styles.getStarted}>Get Started</a>
</form>
</div>
)
}
export default Header
Yea finally configured it out. Thanks to whygee and Ingo Steinkie
If you use variables to set the id and className in the markup, you should probably use the same variables in your script, like
document.getElementById(`${styles.myDropdown}`).classList.toggle("show");
[Edit] or without the unnecessary redundant template string:
document.getElementById(styles.myDropdown).classList.toggle("show");
Assuming that styles.myDropdown is a string (not an object).
Otherwise your code does not ensure that the id and className will be the same.

Nested element in button element are not clickable

I am having this problem, I created a button, and inside I have a for Icon, and inside the element I have span to style the text next to the Icon (the Icon from is humberger from awesome font)
the issue is:
in javascript, I created an onclick function for the button element using the ID btnm, but when I click on the text or the icon in the button does work though when I click around the text and the icon in the button the onclick works fine.
I cannot understand why the icon and text are in the button.
please help
document.addEventListener('DOMContentLoaded', function(){
var menubtn = document.getElementById('btnm');
var mobilemenu = document.getElementById('navigation-mobile');
// When the user clicks on the button, open the modal
menubtn.onclick = function() {
if (mobilemenu.style.display == 'block') {
mobilemenu.style.display = "none";
}
else {
mobilemenu.style.display = 'block';
}
}
}
.mobile-menu-btn {
float: right;
display: block;
padding: 3px 3px 0px 0px;
}
.humberger {
background-color: $identity-color;
font-size: 20px;
border: $identity-color;
border: none;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
.menu-pargraph {
font-size: 14px;
vertical-align: middle;
padding-left: 5px;
margin: 0;
width: 100%;
}
<div class ="mobile-menu-btn">
<button class="humberger" id="btnm">
<i class="menu-btn fas fa-bars">
<span class="menu-pargraph">Menu</span>
</i>
</button>
</div>
<div id="navigation-mobile">
<ul>
<li>home</li>
<li>video</li>
<li>contact</li>
</ul>
</div>
Explanations in comments below. You had the id (and click listener) on the div, not the button and your 'Menu' text was probably looking funky b/c it was inside the icon element, inheriting the icon font family.
<div class ="mobile-menu-btn">
<button class="humberger" id="btnm"> <!-- put the id here -->
<i class="menu-btn fas fa-bars"></i>
<span class="menu-pargraph">Menu</span> <!-- move outside of the fontawesome icon -->
</button>
</div>
Also you can make your life easier with the show/hide using a class
css:
#navigation-mobile{
display:none;
/* and whatever other styles you have here */
}
.show {
display:block;
}
then in your script:
menubtn.onclick = function() {
mobilemenu.classList.toggle('show');
}
You missed a ")" in your JS code.
document.addEventListener('DOMContentLoaded', function(){
var menubtn = document.getElementById('btnm');
var mobilemenu = document.getElementById('navigation-mobile');
// When the user clicks on the button, open the modal
console.log("ok")
}
) // Here you have to add parenthesis

Having trouble hiding menu when resizing and when button is pressed

I'm using this code:
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
to hide my side menu and display a button when I resize window. I also want to show and hide menu when the button is pressed. To do that I'm using this code:
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "none") {
sideMenu.style.display = "block";
}
else {
sideMenu.style.display = "none";
}
}
When I hide with button the menu does not reappear when I resize window. I believe this is happening because the javaScript changes the primary style to display: none, so once it's out of range it applies the primary style. Now it's display: none so it doesn't appear again. How can I get it to work how I intend it to? Also, it takes two clicks to show menu for some reason.
<ul id="side-menu">
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
html just in case you need it.
You must check if the display === "block" first to fix the multiple click issue.
Included media query to manage window width that is greater than 850px to show list and hide button.
EDIT: updated snippet to use the list provided in the original question.
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "block") {
sideMenu.style.display = "none";
}
else {
sideMenu.style.display = "block";
}
}
#media screen and (min-width: 850px) {
#side-menu {
display: block;
}
button {
display: none;
}
}
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
<div id="side-menu">
<ul>
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
</div>
<button onclick="showMenu()">click me</button>
//swap none with block to fix double button press
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "block") {
sideMenu.style.display = "none";
}
else {
sideMenu.style.display = "block";
}
}
/* add this to fix menu show*/
#media screen and (min-width: 850px) {
#side-menu {
display: block !important;
}
button {
display: none;
}
}
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
<div id="side-menu">
<ul>
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
</div>
<button onclick="showMenu()">click me</button>
Thanks ksa and StackSlave

How to fix alignment issue of text center in addition to other element on hover

I have some ul li element. Here on hover of each element one new element is adding on the right side of the text. The alignment of the text is center but on hover when a new element is added on right side of it its alignment is getting changed. My problem is here, Alignment of text/new element should not effect on adding new element on hover. Here is the code below https://stackblitz.com/edit/angular-emvs2v?file=src%2Fstyles.css
home.component.html
<div style="width:50%" class="text-center box">
<ul>
<li [class.btn-success]="selectedIndex === 1" (mouseout)="removeIndex(1)"
(mouseover)="setIndex(1)">Home <span class="float-right test">==></span>
</li>
<li [class.btn-success]="selectedIndex === 2" (mouseout)="removeIndex(2)"
(mouseover)="setIndex(2)">Contact Us <span
class="float-right test">==></span></li>
<li [class.btn-success]="selectedIndex === 3" (mouseout)="removeIndex(3)"
(mouseover)="setIndex(3)">Production<span
class="float-right test">==></span></li>
</ul>
</div>
<button (click)="getSelect()">Submit</button>
home.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
data: any;
selectedIndex = 1;
constructor () { }
ngOnInit () {
}
setIndex (index: number) {
this.selectedIndex = index;
}
removeIndex (index: number) {
this.selectedIndex = null;
}
getSelect () {
this.selectedIndex = 1;
}
}
css
ul li {
list-style-type: none;
}
.test {
display: none;
}
.btn-success .test {
display: block;
}
.text-center {
text-align: center;
}
.float-right {
float: light;
}
By using display:none and display:block, you are removing the item from the DOM, causing surrounding items to move.
You can fix this by using opacity:0 and opacity:1, instead.
You can also use the :hover pseudo-class to greatly simply the code.
ul li {
list-style-type: none;
}
.test {
opacity: 0;
float: right;
}
.btn-success:hover .test {
opacity: 1;
}
<div style="width:150px;">
<ul>
<li class="btn-success">Home <span class="test">==></span></li>
<li class="btn-success">Contact Us <span class="test">==></span></li>
<li class="btn-success" >Production<span class="test">==></span></li>
</ul>
</div>
You need to take the new element outside of the usual flow, e.g. using position: absolute;
Change your CSS to:
ul li{
list-style-type: none;
}
.test{
display: none;
}
.btn-success .test{
display: block;
}
.text-center{
text-align: center;
}
li {
position: relative;
}
.float-right{
position: absolute;
right: 0;
top: 0;
}
You can check the working example here: https://angular-kcnrcg.stackblitz.io

Categories