this is html
i'm a complete beginner as i started learning js since last two month,
please help me to solve this problem
<h1>Best Song Collection</h1>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn"><i class="far fa-play-circle playbtn"></i></span>
<span class="btn"><i class="far fa-pause-circle pausebtn"></i></span>
</div>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn"><i class="far fa-play-circle playbtn"></i></span>
<span class="btn"><i class="far fa-pause-circle pausebtn"></i></span>
</div>
</div>
</div>
js
let pausebtn = document.querySelector(".pausebtn");
let playbtn = document.querySelector(".playbtn")
let btn = document.querySelectorAll(".btn");
function change(element){
if(element.classList==="fa-play-circle"){
element.classList.remove("fa-play-circle");
element.classList.add("fa-pause-circle");
}
}
btn.addEventListner('click',change());
First of all, if you pass a callback function, do not call it. There you need to do it as so btn.addEventListner('click', change);. (Also, there is a typo in addEventListener)
Second of all, I would change the logic of both your HTML and JS. There is no need to keep two spans inside each .songItem div, you can keep only one and just change the class that is responsible for the icon when a user clicks on the button. You will have less code and it will be more readable. Also, you don't need to put a i tag inside a span, you can pass the icons class directly to the span. What is more, it is more convenient to use const instead of let, because you do not intend to change the value of the variables.
You can achieve it by the code written below, I also attach a codepen with a working example.
const pauseIconClassName = 'fa-pause-circle'
const playIconClassName = 'fa-play-circle'
const btns = document.querySelectorAll('.btn')
function onChange (event) {
// get the button elememt from the event
const buttonElement = event.currentTarget
// check if play button class is present on our button
const isPlayButton = buttonElement.classList.contains(playIconClassName)
// if a play button, remove the play button class and add pause button class
if (isPlayButton) {
buttonElement.classList.remove(playIconClassName)
buttonElement.classList.add(pauseIconClassName)
// if a pause button, remove pause button class and add play button class
} else {
buttonElement.classList.remove(pauseIconClassName)
buttonElement.classList.add(playIconClassName)
}
// You can also use .toggle function on classList as mentioned by the person in other answer
}
// query selector all returns a list of nodes, therefore we need to iterate over it and attach an event listener to each button seperatly
btns.forEach(btn => {
btn.addEventListener('click', onChange)
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet"/>
<h1>Best Song Collection</h1>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn far fa-play-circle"></span>
</div>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn far fa-play-circle"></span>
</div>
You probably want to toggle the button so I made an example for that. When you press the play button it will show the pause and when you press the pause button it shows play.
When the button is clicked both fa-play-circle and fa-pause-circle are toggled to alter the button icon when clicked.
You made a few mistakes in your code.
The addEventListner() contains a typo. It should be addEventListener()
You store the result of the change() function (which does not exist since it does not return anything) instead of attaching the function as an event handler. So dont call the function.
Your element variable does not contain an element but the event object so you need to call the target or currentTarget property first.
document.querySelectorAll(".btn").forEach(element => element.addEventListener('click', (event) => {
let iElement = event.currentTarget.querySelector('i');
iElement.classList.toggle("fa-play-circle");
iElement.classList.toggle("fa-pause-circle");
}));
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet"/>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn"><i class="far fa-play-circle playbtn"></i></span>
</div>
<div class="songItem">
<span class="songName">love you zindagi</span>
<span class="btn"><i class="far fa-play-circle playbtn"></i></span>
</div>
pass change to click listener, don't call change function.
btn.addEventListner('click', change);
const pausebtn = document.querySelector(".pausebtn");
const playbtn = document.querySelector(".playbtn");
const btn = document.querySelectorAll(".btn");
function change(element) {
if (element.classList === "fa-play-circle") {
element.classList.remove("fa-play-circle");
element.classList.add("fa-pause-circle");
}
}
btn.addEventListner("click", change);
At first glance, it looks like a syntax issue.
Try to not invoke a function and as args, you should receive an event.
So it will look something like this:
let pausebtn = document.querySelector(".pausebtn");
let playbtn = document.querySelector(".playbtn")
let btn = document.querySelectorAll(".btn");
function change(event){
if(event.target.classList==="fa-play-circle"){
event.target.classList.remove("fa-play-circle");
event.target.classList.add("fa-pause-circle");
}
}
btn.addEventListner('click', change);
EDIT: In HTML you have both buttons for play and pause, you should have just one and change the icon with js toggle.
Semantic tip, use button tag for buttons.
Related
Goal: Change style of an element in a forEach loop
Issue: Style not being applied
In my loop, if I console.log(element), I do get the right list of filtered elements.
Running this works, but I want my function to modify every element that match my filter:
let contentPreview = document.querySelectorAll('.o_last_message_preview');
contentPreview[0].style.color = 'yellow'
All elements are correctly assigned.
function changeNotificationColor() {
// Notification button that opens list of notifications
let notifyButton = document.querySelector('.dropdown-toggle.o-no-caret[title="Conversations"]');
notifyButton.addEventListener('click', function () {
// List of notifications - each notification is contained in a .o_last_message_preview class
let contentPreview = document.querySelectorAll('.o_last_message_preview');
contentPreview.forEach(function (element) { if (element.innerText.includes('Marine')) {element.style.color = 'yellow'}})
})
}
changeNotificationColor();
HTML Notifications Dropdown button:
<a class="dropdown-toggle o-no-caret" data-toggle="dropdown" data-display="static" aria-expanded="true" title="Conversations" href="#" role="button">
<i class="o_mail_messaging_menu_icon fa fa-comments" role="img" aria-label="Messages"></i> <span class="o_notification_counter badge badge-pill">366</span>
</a>
HTML template of a notification node (each notification creates one of these nodes):
<div class="o_preview_info">
<div class="o_preview_title">
<span class="o_preview_name">
You have been assigned to Backorder xx
</span>
<span class="o_preview_counter">
(1)
</span>
<span class="o_last_message_date ml-auto mr-2"> 3 minutes ago </span>
</div>
<div class="o_last_message_preview">
Marine
</div>
<span title="Mark as Read" class="o_discuss_icon o_mail_preview_mark_as_read fa fa-check"></span>
</div>
I don't know what your issue is, but it's not in the code that you showed; this works fine:
let contentPreview = document.querySelectorAll('.o_last_message_preview');
contentPreview.forEach(function (element) { if (element.innerText.includes('Marine')) {element.style.color = 'yellow'}})
<div class="o_last_message_preview">This contains Marine</div>
<div class="o_last_message_preview">This does not</div>
<div class="o_other_message_preview">This has a different class</div>
I have a button that shows a bootstrap modal, it has an onclick attribute set to a function,
The button:
<span style="color:blue;margin-left: 2rem;" data-id="{{student.id}}" id="{{student.id}}"
type="button" data-bs-toggle="modal" data-bs-target="#grade-modal"
onClick="getEnrolledSubjects(this.getAttribute('data-id'))">
<i class="fas fa-plus"></i>
</span>
My javascript function:
function getEnrolledSubjects(id){
var modal = document.getElementById('grade-modal')
modal.addEventListener('shown.bs.modal', function(){
console.log(id)
}
}
at first, it looks fine because it will only log the id once, but when I close the modal and open it again, it will log 2 times, then 3 times, and so on... it goes incrementally. how can i fix this?
as Bootstrap Modal documentation
You can Use event.relatedTarget:
<span style="color:blue;margin-left: 2rem;" data-id="{{student.id}}" id="{{student.id}}" type="button" data-bs-toggle="modal" data-bs-target="#grade-modal">
<i class="fas fa-plus"></i>
</span>
without onClick event
const modal = document.getElementById('grade-modal')
modal.addEventListener('shown.bs.modal', function(event){
const button = event.relatedTarget
const id = button.getAttribute('data-id');
console.log(id)
})
I'm trying to change an existing element on click but I'm struggling to find the logic (very new to this)
I'm trying to switch the below span innerHTM on click. I have "minus" when the filter is not click and I want to add a plus when it is active, see below:
<section class="section-center" id="products-filter">
<div class="products">
<h1>SHOP THE <br />FLAVOURS</h1>
</div>
<button class="toggle-filter" id="toggle-category-filters">
filter
<span id="filter-btn-span"><i class="far fa-minus-square"></i></span>
</button>
</section>
JS:
const toggleFilterBt = document.getElementById('toggle-category-filters');
const categoriesHolder = document.getElementById('categories-holder');
const filterText = document.getElementById('filter-btn-span');
toggleFilterBt.addEventListener('click', () => {
categoriesHolder.classList.toggle('categories-show');
filterText.innerHTML = '<i class="far fa-plus-square"></i>';
});
When clicked the button does change to the plus sign, but how do I make it go back to minus when the button is clicked again?
You can check element classList
toggleFilterBt.addEventListener('click', () => {
categoriesHolder.classList.toggle('categories-show');
filterText.innerHTML = categoriesHolder.classList.contains('categories-show') ? '<i class="far fa-plus-square"></i>' : '<i class="far fa-minus-square"></i>';
});
$(".filter-btn-span").html('<i class="...."></i>');
is how i did it with jQuery (you put it in your event listener) and fill the i class with the one you want)
Add an id to your icon.
Get the icon element by id.
Add and remove between icon classes by checking that icon's class.
Here is the working example:
const toggleFilterBt = document.getElementById('toggle-category-filters');
const toggleIcon = document.getElementById('toggleIcon');
toggleFilterBt.addEventListener('click', () => {
if (toggleIcon.classList.contains('fa-minus-square')) {
toggleIcon.classList.remove('fa-minus-square');
toggleIcon.classList.add('fa-plus-square');
} else {
toggleIcon.classList.remove('fa-plus-square');
toggleIcon.classList.add('fa-minus-square');
}
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
crossorigin="anonymous" />
<section class="section-center" id="products-filter">
<div class="products">
<h1>SHOP THE <br />FLAVOURS</h1>
</div>
<button class="toggle-filter" id="toggle-category-filters">
filter
<span id="filter-btn-span"><i class="far fa-minus-square" id="toggleIcon"></i></span>
</button>
</section>
I'm doing automate in applescript but use Javascript in which I want to click the exact button class ("boost-button") inside a bigger class ("product-item") that contains a string I want. I want to click about 5 of them, each in every ("product-item").
It's like: Do javascript "If getElementByClassName('product-item')[0].innerHTML contains 'The String I Need to Find' then click button class 'boost-button' inside that class"
Because the element number in getElementByClassName('product-item')[0].innerHTML and the getElementByClassName('boost-button')[0].click doesn't go together, they don't click the exact same Class Button.
Does anyone know how to do that? Thanks!
you can use this code
var btn = document.querySelector(".product-item").querySelector(".boost-button")
or just use
var btn = document.querySelector(".product-item .boost-button")
to setup Click Event And Got All Of Your Buttons ...
var btnCollections = document.querySelectorAll(".product-item .boost-button");
btnCollections.forEach(btn => { btn.addEventListener("click", event => EventHandler(event)); });
function EventHandler(event) {
console.log(event.target.textContent)
}
// Auto Click
document.querySelector(".auto-click").addEventListener("click",_=>{
var btnCollections = document.querySelectorAll(".product-item .boost-button");
btnCollections.forEach(btn => btn.click());
} );
<div class="product-item">
<button class="boost-button"> test 1 </button>
<button class="boost-button"> test 2 </button>
<button class="boost-button"> test 3 </button>
</div>
<div class="product-item">
<button class="boost-button"> test 4 </button>
<button class="boost-button"> test 5 </button>
<button class="boost-button"> test 6 </button>
</div>
<button class="auto-click"> Auto Click </button>
Other Way :
and for your click problem read click documentation and use event.target
This code will replace what is shown inside <button></button> with selected icon from dropdown list.
This works good, only problem is that after clicking on selected element, icon inside that element will for some reason disappear? Why does this happen? I want <li> to be unchanged
http://codepen.io/filaret/pen/PGJEAL
HTML:
<div class="input-group-btn">
<button type="button" class="btn" data-toggle="dropdown">
<i class="fa fa-book"></i>
</button>
<ul class="dropdown-menu">
<li><i class="fa fa-book"></i> Something 111</li>
<li><i class="fa fa-newspaper-o"></i> Something 2222</li>
</ul>
</div>
jQuery:
var $selectWrapper = $('.input-group-btn');
$selectWrapper.find(".dropdown-menu li").click(function() {
// Get <i class="fa"></i>
var $selectedIcon = $(this).find('.fa');
// Put it inside <button></button>
$selectWrapper.find(".btn").html($selectedIcon);
});
You need to clone the icon using clone() like following
var $selectedIcon = $(this).find('.fa').clone();
instead of
var $selectedIcon = $(this).find('.fa');
UPDATED CODEPEN
Otherwise since you have i tag in dropdown and button tag and that only class change, why don't you just copy the class, it's more efficient, faster and easy to understand in your code.
jQuery(document).ready(function($) {
"use strict";
var $selectWrapper = $('.input-group-btn');
var $buttonIcon = $('.btn i');
$selectWrapper.find(".dropdown-menu li").click(function() {
// Get <i class="fa"></i>
var $selectedIcon = $(this).find('.fa');
// get icon classes
var classes = $selectedIcon.attr("class");
// Put the class in the button i tag
$buttonIcon.attr('class', classes);
});
});
See code pen: http://codepen.io/anon/pen/ORxQPZ