How to know how many class elements have been selected on click? - javascript

I'm working on wishlist, i have heart icon on each item, Now i want to display total number of item added in wishlist. What is proper way to do this?
$(function() {
$('body').on('click', '.fav-icon', function() {
var icon = $(this);
var icon_fa_icon = icon.attr('data-prefix');
if (icon_fa_icon === "far") {
icon.attr('data-prefix', 'fas');
$('.search-list-box .fav-icon').each(function() {
var fasLength = $(this).attr('data-prefix', 'fas');
var wishlistDiv = +$(fasLength).length;
$('.wishlist_count sup').text(wishlistDiv);
});
} else {
icon.attr('data-prefix', 'far');
}
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script defer src="https://use.fontawesome.com/releases/v5.6.3/js/all.js" integrity="sha384-EIHISlAOj4zgYieurP0SdoiBYfGJKkgWedPHH4jCzpCXLmzVsw1ouK59MuUtP4a1" crossorigin="anonymous"></script>
<div>
<span class="wishlist_count">
<i class="far text-orange fa-heart"></i>
<sup>0</sup>
</span>
</div>
<hr>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>

Part of your problem is with these lines:
var fasLength = $(this).attr('data-prefix', 'fas');
var wishlistDiv = +$(fasLength).length;
That first line is setting the data-prefix attribute to fas on all elements so they are all chosen on first click. As it's selecting all elements the count is wrong. To fix this you need to use an attribute selector:
var fasLength = $('[data-prefix="fas"]').length;
Finally you also need to amend the count of selected items when something is deselected, so the count logic should be run outside of the if condition. The calculation also does not need the each()loop.
The complete logic will then look like this:
$(function() {
$('body').on('click', '.fav-icon', function() {
var $icon = $(this).attr('data-prefix', function(i, v) {
return v == 'far' ? 'fas' : 'far';
});
var fasLength = $('[data-prefix="fas"]').length;
$('.wishlist_count sup').text(fasLength);
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script defer src="https://use.fontawesome.com/releases/v5.6.3/js/all.js" integrity="sha384-EIHISlAOj4zgYieurP0SdoiBYfGJKkgWedPHH4jCzpCXLmzVsw1ouK59MuUtP4a1" crossorigin="anonymous"></script>
<div>
<span class="wishlist_count">
<i class="far text-orange fa-heart"></i>
<sup>0</sup>
</span>
</div>
<hr>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>
<div class="search-list-box">
<i class="fav-icon far fa-heart text-orange"></i>
</div>

Related

Unable to target and remove appended element in jquery or Javascript

Here's what I'm trying to do here -
Take input from a form field and append the data in a div option-badges
The badges have X button that I'm using to remove the items clicked if needed
What's the problem?
With the code I've written, I'm unable to remove the said appended badge while I'm easily able to remove the badges which were there already.
Here's the code. Please help me with this. Thanking in anticipation.
$(document).ready(function() {
//take input data from first input field and display comma separated in second field
let dataList = [];
let dataString = "";
$("#addData").on('click', function() {
let data = $("#firstInput").val();
let dataBadge = '<span class="badge badge-secondary" style="margin-left: 5px;">' +
data + ' &nbsp <i id="newBadge" class="fa-solid fa-xmark" ></i></span>';
$('.option-badges').append(dataBadge);
$("#firstInput").val('');
})
//remove badge on clicking x
$(".option-badges > span > i").on("click", function() {
$(this).parent().remove();
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div class="option-badges">
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
</div>
-
Try with on off click like
$(document).off('click', '.option-badges > span > i');
$(document).on('click', '.option-badges > span > i', function () {
$(this).parent().remove();
})
$(document).ready(function() {
//take input data from first input field and display comma separated in second field
let dataList = [];
let dataString = "";
$("#addData").on('click', function() {
let data = $("#firstInput").val();
let dataBadge = '<span class="badge badge-secondary" style="margin-left: 5px;">' +
data + ' &nbsp <i id="newBadge" class="fa-solid fa-xmark" ></i></span>';
$('.option-badges').append(dataBadge);
$("#firstInput").val('');
})
//remove badge on clicking x
$(document).off('click', '.option-badges > span > i');
$(document).on('click', '.option-badges > span > i', function () {
$(this).parent().remove();
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div class="option-badges">
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
</div>
<input id="firstInput" type text />
<a id="addData">ADD </a>

Why MDCSelect:change is not working with javascript for material design

Why MDCSelect:change is not working when i call it before appending all options
MDCSelect:change is working when i put it after appending list BUT UI does not look good.
Question: How to make MDCSelect:change to working without harming ui look.
It works perfectly when i shuffle the code of those 2 lines
$('#select_dropdown').html(usersStr);
initializeSelect();
With the above code select UI does not look good when you click outside anywhere or simply
for a better view, I have created codepen here: https://codepen.io/eabangalore/pen/poNmBpm?editors=1010
var selectBoxMap = {};
function initializeSelect(){
var mdcSelectList = document.querySelectorAll(' .mdc-select');
if(mdcSelectList){
[].forEach.call(mdcSelectList,function(el){
var select = new mdc.select.MDCSelect(el);
el.setAttribute('ripple-attached', true);
var dropDownId = $(el).find('ul.mdc-list').attr('id');
selectBoxMap[dropDownId] = select;
});
}
}
$(async function(){
var results = await $.get('https://jsonplaceholder.typicode.com/users');
var usersStr = '';
for(var i = 0; i < results.length; i++){
var item = results[i];
usersStr += `<li class="mdc-list-item" data-id="${item.id}" role="option">
<span class="mdc-list-item__ripple"></span>
<span class="mdc-list-item__text" data-id="${item.id}">
${item.name}
</span>
</li>`
}
initializeSelect();
$('#select_dropdown').html(usersStr);
for(var key in selectBoxMap){
if(selectBoxMap[key]){
selectBoxMap[key].listen('MDCSelect:change', (e) => {
alert('dropdown changed');
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<head>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
</head>
<!-- select dropdown -->
<div class="mdc-select mdc-select--filled demo-width-class">
<div class="mdc-select__anchor" role="button" aria-haspopup="listbox" aria-expanded="false">
<span class="mdc-select__ripple"></span>
<span class="mdc-floating-label">Status</span>
<span class="mdc-select__selected-text-container">
<span id="" class="mdc-select__selected-text"></span>
</span>
<span class="mdc-select__dropdown-icon">
<span class="mdc-select__dropdown-icon-inactive material-icons">arrow_drop_down</span>
<span class="mdc-select__dropdown-icon-active material-icons">arrow_drop_up</span>
</span>
<span class="mdc-line-ripple"></span>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-list" id="select_dropdown" role="listbox" aria-label="listbox">
</ul>
</div>
</div>
Still i'm looking for solution, please help me thanks in advance!!
I've got the idea from this link
var selectBoxMap = {};
function initializeSelect(){
var mdcSelectList = document.querySelectorAll(' .mdc-select');
if(mdcSelectList){
[].forEach.call(mdcSelectList,function(el){
var select = new mdc.select.MDCSelect(el);
el.setAttribute('ripple-attached', true);
var dropDownId = $(el).find('ul.mdc-list').attr('id');
selectBoxMap[dropDownId] = select;
});
}
}
$(async function(){
var results = await $.get('https://jsonplaceholder.typicode.com/users');
var usersStr = '';
for(var i = 0; i < results.length; i++){
var item = results[i];
usersStr = `<li class="mdc-list-item" aria-selected="false" data-value=" ${item.name}" role="option">
<span class="mdc-list-item__ripple"></span>
<span class="mdc-list-item__text">
${item.name}
</span>
</li>`;
$('#select_dropdown').append(usersStr);
}
initializeSelect();
for(var key in selectBoxMap){
if(selectBoxMap[key]){
selectBoxMap[key].listen('MDCSelect:change', (e) => {
alert('dropdown changed');
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<head>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
</head>
<!-- select dropdown -->
<div class="mdc-select mdc-select--filled demo-width-class">
<div class="mdc-select__anchor" role="button" aria-haspopup="listbox" aria-expanded="false">
<span class="mdc-select__ripple"></span>
<span class="mdc-floating-label">Status</span>
<span class="mdc-select__selected-text-container">
<span id="" class="mdc-select__selected-text"></span>
</span>
<span class="mdc-select__dropdown-icon">
<span class="mdc-select__dropdown-icon-inactive material-icons">arrow_drop_down</span>
<span class="mdc-select__dropdown-icon-active material-icons">arrow_drop_up</span>
</span>
<span class="mdc-line-ripple"></span>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-list" id="select_dropdown" role="listbox" aria-label="listbox">
</ul>
</div>
</div>

No Console Log Output When Clicking Plus Icon in Unordered List

I have an ul (unordered list) which contains several li (list items) when I click on the + sign left to li, console log should output "description expanded" For the two first li, it works just fine, but not for any other li's. The html code by default includes only 2 li's. any li after that is added through the form. However, any new li does not produce the console log output. Which means they're not responding to clicks. I'm using jQuery to listen for click events. When clicking on the icon.
project link http://pctechtips.org/apps/todo/
//variables
//todoList array to hold (title, description) for every todo tiem
var todoList = []; //{title: "value", desc: "value"},
var numId = 2; //num is for desc paragraph id eg <p id="plus-3">
/*
* Script main body
*/
$(document).ready(function() {
//hide form when doc loads first time
$("#submit-form").hide();
//hide list item description <p>
$(".item-desc").hide();
//listener for show hide form functionality
$("#add-todo").click(function() {
toggleForm();
return false; //return false to prevent page reload
});
//listener for add new item form (submit button)
$(".btn").click(function() {
console.log("submit item");
addToList();
});
//listener for expanding li description
$(".plus").click(function() {
console.log("description expanded")
var plusId = $(this).attr("id"); //grabbing id of plus sign
showDescription(plusId);
return false;
});
});
//functionality for show / hide form
function toggleForm() {
if($("#submit-form").is(":hidden")) {
console.log("form exapnded");
$("#submit-form").show("slow");
$("#form-icon").removeClass("fa-plus-square-o");
$("#form-icon").addClass("fa-minus-square-o");
}
else {
console.log("form hidden");
$("#submit-form").hide("slow");
$("#form-icon").removeClass("fa-minus-square-o");
$("#form-icon").addClass("fa-plus-square-o");
}
}
//add new item to todo list items
function addToList() {
numId++;
//getting data from input fields
var todoTitle = $("#todo-title").val();
var todoDesc = $("#todo-desc").val();
//checking user input
if(todoTitle == "" || todoDesc == "") {
alert("fill in all fields!");
}
else {
console.log(todoTitle + "\n" + todoDesc);
//adding values to array
todoList.push({title: todoTitle, desc: todoDesc},);
//adding new li to ul
var ul = document.getElementById("list");
var li = document.createElement("li");
$(li).addClass("list-group-item justify-content-between align-items-center");
$(li).append(($('<i id="plus-'+numId+'" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>')));
$(li).append(($('<span class="left marg-left">'+todoTitle+'</span>')));
$(li).append(($('<i class="fa fa-trash-o right" aria-hidden="true"></i>')));
$(li).append(($('<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>')));
ul.appendChild(li);
}
}
//expanding description under for each todo
function showDescription(plusId) {
//getting the number from id
var num = plusId.substring(plusId.indexOf("-")+1);
//checking for hide / show description paragraph
if($("#desc-"+num).is(":hidden")) {
$("#desc-"+num).show("slow");
$("#desc-"+num).removeClass("fa-plus-square-o");
$("#desc-"+num).addClass("fa-minus-square-o");
}
else {
$("#desc-"+num).hide("slow");
$("#desc-"+num).removeClass("fa-minus-square-o");
$("#desc-"+num).addClass("fa-plus-square-o");
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>TodoList App</title>
<!-- bootstrap, fontawsome cdn -->
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- local stylesheet -->
<link rel="stylesheet" type="text/css" href="css/style.css">
<!-- jquery cdn -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<!-- local javascript -->
<script type="text/javascript" src="js/todo.js"></script>
</head>
<body>
<!-- navbar -->
<nav class="navbar navbar-expand-lg navbar-drak bg-dark mb-4">
<a class="navbar-brand" href="#"><i class="fa fa-thumb-tack" aria-hidden="true"></i> Todo<strong>List</strong></a>
</nav>
<!-- /navbar -->
<!-- todoList -->
<div class="container">
<div class="add-item text-white text-center col-sm-12 col-md-10 col-lg-8 mb-4">
<a id="add-todo" class="new-todo text-white text-center" href=""><i id="form-icon" class="fa fa-plus-square-o" aria-hidden="true"></i> Enter new todo item</a>
<div id="submit-form" class="form-hide text-center col-sm-12 col-md-12 col-lg-8">
<form class="">
<div class="form-group">
<input type="text" class="form-control" id="todo-title" placeholder="Todo Title" value="Pay Car Insurance">
</div>
<div class="form-group">
<input type="text" class="form-control" id="todo-desc" placeholder="Todo Description" value="This is to pay car insurance">
</div>
<button type="button" class="btn btn-primary btn-lg col-12">Submit Todo</button>
</form>
</div>
<!-- horizontal line -->
<hr>
<!-- list items -->
<h1 class="heading-4">Todo List Items</h1>
<ul id="list" class="list-group mt-4 pb-4">
<li class="list-group-item justify-content-between align-items-center">
<i id="plus-1" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>
<span class="left marg-left">Pay Car Insurance </span>
<i class="fa fa-trash-o right" aria-hidden="true"></i>
<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>
</li>
<p id="desc-1" class="item-desc bg-white">Helloooooooooo this is description</p>
<li class="list-group-item justify-content-between align-items-center">
<i id="plus-2" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>
<span class="left marg-left">Pay Car Insurance </span><i class="fa fa-trash-o right" aria-hidden="true"></i>
<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>
</li>
<p id="desc-2" class="item-desc bg-white">Helloooooooooo this is description</p>
</ul>
</div>
</div>
</body>
</html>
ok for dynamically added elements the even listener needs to be defined at the root / document level. so
$("class").on("click", function() { });
will not work. It needs to be
$(document).on("click", ".class", function() { });
Thanks to "MADDY BLACKLISTED" above pointed me in right directions
Use
$(document).on("click", ".plus", function() {
console.log("description expanded")
var plusId = $(this).attr("id"); //grabbing id of plus sign
showDescription(plusId);
return false;
});
Instead of having a static click listener defined at document load.

How to make a string of some specific values in the dom?

I have the following HTML:
<div>
<i class="fa fa-male ">:Before</i>
<i class="fa fa-like">:Before</i>
</div>
Now I want to make a string like this: male, like. How can I do that?
console.log(/fa-([^"]+)/.exec($('div').html()));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<i class="fa fa-male ">:Before</i>
<i class="fa fa-like">:Before</i>
</div>
You will need to loop after you select all icons. For example like this:
var str = $('.fa').map(function() {
return this.className.match(/fa-([^"]+)/)[1]
}).get()
.join(', ')
console.log(str)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<i class="fa fa-male">:Before</i>
<i class="fa fa-like">:Before</i>
</div>
Simply iterate over the the elements using map and extract (replace) the class name of the element.
var icons = document.getElementsByClassName('fa');
var str = Array.from(icons)
.map(c => c.classList.value.replace('fa fa-', ''))
.join(', ')
console.log(str)
<div>
<i class="fa fa-male">:Before</i>
<i class="fa fa-like">:Before</i>
</div>

How to toggle button icon and description javascript

here is my problem. I need on click to change button icon and on another click to go to original state, like +,- and span description like home/back
i dont know what to do. Pleas help.
Here is html...
<div class="navbar-left left">
<button class="toggle btn mr2 white " >
<i class="fa fa-home fa-2x "></i>
<span class="mobile-hide ">Home</a>
</button>
</div>
and bad js
if ($('.toggle').hasClass('fa fa-home fa-2x')) {
$('.toggle').toggleClass('fa fa-home ').html('<span class="mobile-hide ">Home</a>');
} else($('.toggle').hasClass('fa fa-home ')) {
$('.toggle').toggleClass('fa fa-home fa-2x ').html('<span class="mobile-hide ">Back</a>');
}
toggleMenu();
});
You can
jQuery(function($){
$('.toggle').click(function () {
var $i = $(this).find('i').toggleClass('fa-2x');
$(this).find('span.mobile-hide').html($i.hasClass('fa-2x') ? 'Home' : 'Back')
})
})
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="navbar-left left">
<button class="toggle btn mr2 white" >
<i class="fa fa-home fa-2x"></i>
<span class="mobile-hide">Home</span>
</button>
</div>
You can only use .hasClass() to check for a single class Name.
In order to check for many class names I guess is better get the class attribute string and check with .indexOf()
if ($('.toggle').attr("class").indexOf('fa fa-home fa-2x') != -1) {
The same happens with toggleClass. You have to break it down:
$('.toggle').toggleClass('fa').toggleClass('fa-home').toggleClass('fa-2x')
You might be able to achieve this effect with the ::after pseudo-element. Just change the content property as appropriate based on some class on the button.
A simplified example:
$(function () {
$('#toggle').click(function () {
$(this).toggleClass('on');
});
});
.icon::after {
content: '+';
}
.text::after {
content: 'Home';
}
.on .icon::after {
content: '-'
}
.on .text::after {
content: 'Back'
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<button id="toggle">
<i class="icon"></i>
<span class="text"></span>
</button>

Categories