How to target all elements with Jquery on click - javascript

Only first element getting clicked not all, how to get alert on all elements.
Jsfiddle
var btn = document.querySelector(".box i");
btn.onclick = function () {
alert('hello');
}
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>

Try querySelectorAll for select all then attract onclick to all element
var btnlist = document.querySelectorAll(".box i");
btnlist.forEach(element =>{element.onclick = function () {
alert('hello');
}});
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>

Despite the title of the question, you don't currently use jQuery in your code. So, I provide 2 solutions:
jQuery:
jQuery('.box i').click(function() {
alert('hello');
});
Pure JS
window.addEventListener('click', function(e) {
// or e.target.classList.contains('fa-address-book-o')
if (e.target.className === 'fa fa-address-book-o') { // Better to add some additional class to identify element, like "fireAlert" for instance.
alert('hello');
}
});
Alternatively, you could select icons with query selector and add individual event listeners to all of them in a loop, but it's bad for performance & generally not considered a good thing to do.

The reason why it only work on the first element is that using .querySelector() method will select only the first element the meet your selector criteria, to be able to select all the elements you have to use .querySelectorAll() which will return a NodeList which can iterate through like this:
var btns = document.querySelectorAll(".box i");
btns.forEach((el, i) => {
el.onclick = function () {
console.log(`Hello! ${i}`);
}
});
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true">1</i>
<i class="fa fa-address-book-o" aria-hidden="true">2</i>
<i class="fa fa-address-book-o" aria-hidden="true">4</i>
<i class="fa fa-address-book-o" aria-hidden="true">5</i>
</div>

Related

Error updating inner HTML element using vanilla Javascript

I have the following HTML element:
<ul id="list">
<!-- <li class="item">
<i class="fa fa-circle-thin co" job="complete" id="0"></i>
<i class="fa fa-circle-check co" job="complete" id="0"></i>
<p class="text">Drink Coffee</p>
<i class="fa fa-trash-o de" job="delete" id="0"></i>
</li> -->
</ul>
I am populating the li items using javascript as below:
const listItem = document.createElement('li');
listItem.className = 'item';
listItem.innerHTML = `
<i class="fa fa-circle-thin co" job="complete" id="0"></i>
<!-- <i class="fa fa-circle-check co" job="complete" id="0"></i> -->
<p class="text">${todoItem.title}</p>
<i class="fa fa-trash-o de" job="delete" id="0"></i>
`;
listElement.appendChild(listItem);
todoItem is an instance of a TodoItem object:
class TodoItem{
constructor(title, status){
this.title = title;
this.status = status;
//this.isDone = false;
}
}
This is working fine and I am getting the list populated. I have also managed to update the list items when clicked by striking it through like below:
target.parentElement.getElementsByClassName('text')[0].innerHTML = `<s>${todoItem.title}</s>`;
Now I am having problem updating the items to remove the strikethrough. I am trying below code.
const strikeElement = target.parentElement.getElementsByTagName('s')[0];
console.log(textElement)
console.log(strikeElement);
todoItem = new TodoItem(target.parentElement.getElementsByClassName('text')[0].innerHTML, itemStatus.pending);
textElement.replaceChildren();
console.log(target.parentElement.getElementsByClassName('text')[0])
target.parentElement.getElementsByClassName('text')[0].innerHTML = `${todoItem.title}`;
Here is what I get from console for the above code. Notice the insertion of tags everytime I click the list item.

Dynamically determine which button of a particular class has been clicked with jquery

A demo of my dilemma here
Let's say I have the following html:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<body>
<div class="main" id="thingSection">
<h1>
Test Header
</h1>
<button class="btn-icon"><i class="fa fa-fw fa-lg fa-windows"></i> <i class="fa fa-fw fa-lg fa-toggle-off"></i> <i class="fa fa-fw fa-lg fa-apple"></i></button>
<div class="content" id="content1">
Some content
</div>
</div>
<hr />
<div class="main" id="thingSection1">
<h1>
Another Test
</h1>
<button class="btn-icon"><i class="fa fa-fw fa-lg fa-windows"></i> <i class="fa fa-fw fa-lg fa-toggle-off"></i> <i class="fa fa-fw fa-lg fa-apple"></i></button>
<div class="content" id="content2">
Some content
</div>
</div>
<hr>
<div class="main" id="thingSection2">
<h1>
Another test, you say?
</h1>
<button class="btn-icon"><i class="fa fa-fw fa-lg fa-windows"></i> <i class="fa fa-fw fa-lg fa-toggle-off"></i> <i class="fa fa-fw fa-lg fa-apple"></i></button>
<div class="content" id="content3">
Some content
</div>
</div>
</body>
</html>
I am using the following jquery to change the toggle icon from FontAwesome from off to on:
$(function() {
$('.btn-icon').click(function() {
if ($(this).find($(".fa")).hasClass('fa-toggle-off')) {
$("i.fa-toggle-off").toggleClass('fa-toggle-on');
} else {
$("i.fa-toggle-on").toggleClass('fa-toggle-off');
}
});
});
When I click the button to toggle the icon, it works as expected, i.e. it changes all of the buttons on the page. However, I would like to dynamically determine which button has been pressed, and then change the content of a child div based on the position of the switch.
I want to avoid hardcoding id's for each button to avoid a ton of if/else statements in the script that must be updated each time I, say, add a new button or a new section. That is to say, I want to dynamically detect which button has been pressed, and affect only that button and its children.
I've noticed that console.log(this) yields only the HTML for the particular button that has been pressed, not all of the buttons.
I'm a novice with jquery. I haven't been able to find a solution to this problem yet, and I feel like there has to be a way to do this dynamically without hardcoding IDs.
EDIT: I've accomplished (partially) what I want to do with the following code:
$(function() {
$('.btn-icon').click(function() {
var t = $(this).find('.is-toggle');
if (t.hasClass('fa-toggle-off')) {
t.addClass('fa-toggle-on');
t.removeClass('fa-toggle-off');
}
else {
t.addClass('fa-toggle-off');
t.removeClass('fa-toggle-on');
}
});
});
Looks like I just didn't understand what exactly $(this) was (:
All you need is $(this) that selects the element that triggered the event. From there you can select down to the div you want.
EDIT: Here is how that might look in code, I pulled this from your fiddle and edited it
$(function() {
$('.btn-icon').click(function() {
$(this).children('.fa-toggle-off, .fa-toggle-on').toggleClass('fa-toggle-on fa-toggle-off');
});
});

How can I get two different events with "querySelectorAll" for each element?

I have a probleme with my code. Now if I click the first element, all elements will become red, if I click second time they will become green. I would like have two independent events for each element with class fa-heart. I will explain better: If I click the first time the first element DOM, only this element will become red, and if I click it second time, it will become green, and so for all the others. I apologize if my request is not clear. Thank you so much for your help.
<script src="https://kit.fontawesome.com/a1d70a0cda.js"></script>
<a onclick="change()"><i class="fas fa-heart"></i></a>
<a onclick="change()"><i class="fas fa-heart"></i></a>
<a onclick="change()"><i class="fas fa-heart"></i></a>
<script>
function change(){
var a = document.querySelectorAll('.fa-heart');
var qty = a.length;
var i = 0;
for(i; i<qty; i++){
if(a[i].style.color !== 'red'){
a[i].style.color = 'red';
}else{
a[i].style.color='green';
}
}
}
</script>
Add an individual listener to each <i> instead, and in the listener, check the current .style of the clicked element to figure out what to assign next:
document.querySelectorAll('.fa-heart').forEach((i) => {
i.addEventListener('click', () => {
i.style.color = i.style.color !== 'red'
? 'red'
: 'green';
});
});
<script src="https://kit.fontawesome.com/a1d70a0cda.js"></script>
<a><i class="fas fa-heart"></i></a>
<a><i class="fas fa-heart"></i></a>
<a><i class="fas fa-heart"></i></a>
Or, with event delegation:
document.addEventListener('click', (e) => {
if (!e.target.matches('.fa-heart')) {
return;
}
e.target.style.color = e.target.style.color !== 'red'
? 'red'
: 'green';
});
console.log('start');
setTimeout(() => {
console.log('adding dynamic elements');
document.body.innerHTML += `<a><i class="fas fa-heart"></i></a>
<a><i class="fas fa-heart"></i></a>
<a><i class="fas fa-heart"></i></a>`;
}, 1000);
<script src="https://kit.fontawesome.com/a1d70a0cda.js"></script>
If you must use inline handlers (which you shouldn't), pass the this (the clicked element) to the listener:
function change(i) {
i.style.color = i.style.color !== 'red'
? 'red'
: 'green';
}
<script src="https://kit.fontawesome.com/a1d70a0cda.js"></script>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>
Here you go. This will change the clicked one to green and others to red.
function change(clicked) {
document.querySelectorAll('a').forEach(el => el.setAttribute("style", "color:red"));
clicked.style.cssText ="color:green;";
}
<script src="https://kit.fontawesome.com/a1d70a0cda.js"></script>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>
<a onclick="change(this)"><i class="fas fa-heart"></i></a>

color icons upto the hover position

I have 10 circles (Fontawesome icons) horizontally placed. I want to fill colors to them when the user hover on any icon. For ex: if the user hovers on the 5th circle, all the circles upto the 5th circle should fill in color. (Something like in a rating system) How can i do it?
Following is the code which i render 10 circles.
export const RatePersonalityCard = ({}) => {
for (let score = 1; score < 11; score++) {
let scoreList = [];
scoreList.push(
<div className="trait_vote_single tooltip" style={{fontSize:'40px',color:'gray'}} onClick={() => handleClick(score)}>
{/*<div className="trait_vote_circle"></div>*/}
<i className="fa fa-circle-thin" aria-hidden="true"></i>
<a className="trait_value" style={{marginTop:'-34px',marginLeft:'-1px'}}>{score}</a>
<span className="tooltiptext2 unchange_div" style={{marginLeft: '-40px'}}>{starvalue}</span>
</div>
)
}
return (
<div className="">
<div className="single_trait_rate width_100 text_align_center">{userTraits.trait_name}</div>
<div className="trait_vote_div">
{scoreList}
</div>
</div>
);
};
You could create a hover event for each for every score list item that adds a class to the currently hovered item and everything prior. Then add a blur event to every item to remove the class.
function handleHover(e) {
let index = scoreList.indexOf(e.target);
for (let i = 0; i <= index; i++) {
scoreList[index].classList.add('highlight');
}
}
function handleBlur(e) {
scoreList.forEach(function(item) {
item.classList.remove('highlight');
});
}
No CSS example. I don't see great value in adding any JS to something that can simply done via CSS. If you also need a click event, it's as simple as 1 class on 1 span. I'd also recommend reading:
Decoupling Your HTML, CSS, and JavaScrip which my code does not do.
span .fa-star{
display: none;
}
span:hover > .fa-star{
color: yellow;
display: inline-block;
color: red;
}
span:hover > .fa-star-o{
display: none;
}
span { cursor: pointer }
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
</span>
</span>
</span>
</span>
</span>

How can I get the value of a jQuery selectable object in a ViewModel collection I passed to my view to be iterated through as an ordered list?

Convoluted question, I know. I'm working on a small MVC application for the purposes of my own learning and I'm stuck at this point after much SO scouring. My View is such (note that ItemList is a List):
#model PackItOut.ViewModels.IndexViewModel
<ol id="item-list-20">
#foreach (var i in Model.ItemList)
{
<li class="ui-widget-content">
#switch (i.Category)
{
case "Food":
<i class="fa fa-cutlery" aria-hidden="true"></i>
break;
case "Shelter":
<i class="fa fa-tree" aria-hidden="true"></i>
break;
case "First Aid":
<i class="fa fa-medkit" aria-hidden="true"></i>
break;
case "Clothing":
<i class="fa fa-child" aria-hidden="true"></i>
break;
case "Fluid":
<i class="fa fa-tint" aria-hidden="true"></i>
break;
case "Weather":
<i class="fa fa-bolt" aria-hidden="true"></i>
break;
default:
break;
}
#i.Name
</li>
}
</ol>
<button class="btn btn-danger change-item" id="remove-item-btn"><i class="fa fa-trash" aria-hidden="true"></i> Remove Item</button>
The Javascript is such:
$(document).ready(function() {
var theItemList = $("ol[id*='item-list-']");
$(theItemList).selectable({
selected: function(event, ui) {
$(ui.selected).addClass("ui-selected").siblings().removeClass("ui-selected");
},
stop: function () {
var hasSelection = $(".ui-selected");
if (hasSelection != null)
$(".change-item").css('visibility', 'visible');
else
$(".change-item").css('visibility', 'hidden');
}
});
$("#remove-item-btn").on("click", function (event) {
var targetItem = document.getElementsByClassName("ui-selected");
if (targetItem == null)
alert('Please select an item to remove.');
});
});
Ideally, in the .on("click") I'd like to pass in the object represented by the targeted item so I can remove the item from the ViewModel collection but I'm having trouble getting the actual object and not just the HTML. Any suggestions on not only this issue but any other issues you see in this snippet are always welcome. Thanks in advance.
I'm going to look into my crystal ball and predict the future. Once you complete the removal functionality, you're going to want to be able to add to the list as well, right? Good thing there's a NuGet package called BeginCollectionItem and related blog post by Steve Sanderson dedicated to this exact scenario - adding and removing items from a list in MVC.
I'm not going to write out a full solution because that's been done, but I recently implemented this myself using this package. There are several answers on SO involving this package that should help to get you started. This one is especially good.
In response to your specific question, however, you could do something like is mentioned in the linked answer to simply remove a div associated with a list item:
HTML/Razor:
#model PackItOut.ViewModels.IndexViewModel
<div id="editorRows">
<ol id="item-list-20">
#foreach (var i in Model.ItemList)
{
<div class="editorRow">
<li class="ui-widget-content">
#switch (i.Category)
{
case "Food":
<i class="fa fa-cutlery" aria-hidden="true"></i>
break;
case "Shelter":
<i class="fa fa-tree" aria-hidden="true"></i>
break;
case "First Aid":
<i class="fa fa-medkit" aria-hidden="true"></i>
break;
case "Clothing":
<i class="fa fa-child" aria-hidden="true"></i>
break;
case "Fluid":
<i class="fa fa-tint" aria-hidden="true"></i>
break;
case "Weather":
<i class="fa fa-bolt" aria-hidden="true"></i>
break;
default:
break;
}
#i.Name
</li>
<button class="btn btn-danger deleteRow"><i class="fa fa-trash" aria-hidden="true"></i> Remove Item</button>
</div>
}
</ol>
</div>
JavaScript:
$('#editorRows').on('click', '.deleteRow', function () {
$(this).closest('.editorRow').remove();
});
Although you will have to play with your HTML elements because you can't nest a <div> within an <ol>.

Categories

Resources