I'm pretty new to the world of jQuery and having some difficulty with a cart feature I am trying to add to a website.
I have created a function to add an element (based on its id) to the cart. This works fine. However when I try to reverse it (say someone clicks on the cart icon again to remove it) the cart count increases more and the class doesn't change back.
You will see in my code I am changing the classes for visual representation (unselected = svg with no fill & selected = svg with fill).
I have tried toggling the class, removing and adding the class but I can't think of much more. Any help would be greatly appreciated!
$(document).ready(function() {
var cart = [];
$("a.addToCart").click(function(event) {
var pressedId = event.target.id;
$("#cart_button").removeClass("hidden");
$("#" + pressedId).removeClass("addToCart");
$("#" + pressedId).addClass("addedToCart");
cart.push(pressedId)
$('.cart--counter').html(cart.length);
});
});
$(document).ready(function() {
$("a.addedToCart").click(function(event) {
var unpressedId = event.target.id;
$("#" + unpressedId).addClass("addToCart");
$("#" + unpressedId).removeClass("addedToCart");
cart.splice( $.inArray(unpressedID,cart) ,1 );
$('.cart--counter').html(cart.length);
});
});
Here is an example of the HTML with a class and ID.
<a id="12" class="addToCart">
Again, for clarification: the class changes appropriately from "addToCart" to "addedToCart" but is not reversible & the array is successfully updated with appropriate "ID" but can not be removed again.
Your issue is that when you add your event handlers, there are no elements with class addedToCart, so no event handlers get assigned. You need to use a delegated event handler instead:
var cart = [];
$(document).ready(function() {
$(document).on('click', "a.addToCart", function(event) {
var pressedId = event.target.id;
$("#cart_button").removeClass("hidden");
$("#" + pressedId).removeClass("addToCart");
$("#" + pressedId).addClass("addedToCart");
cart.push(pressedId)
$('.cart--counter').html(cart.length);
$('#cart').html(cart.toString());
});
});
$(document).ready(function() {
$(document).on('click', "a.addedToCart", function(event) {
var unpressedId = event.target.id;
$("#" + unpressedId).addClass("addToCart");
$("#" + unpressedId).removeClass("addedToCart");
cart.splice($.inArray(unpressedId, cart), 1);
$('.cart--counter').html(cart.length);
$('#cart').html(cart.toString());
});
});
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a id="12" class="addToCart">Item 12</a><br />
<a id="13" class="addToCart">Item 13</a>
<div class="cart--counter">**</div>
<br />
<div id="cart"></div>
<br />
<div id="cart_button" class="hidden">cart button</div>
Related
Here is my example.
By clicking the add button, I add a user card. "Clear button" removes all cards. How to remove cards one by one clicking on the "close" icon in each card?
HTML file
<div class="header">
<button id="clear" class="button clear">Clear</button>
<button id="button" class="button add">Add user</button>
</div>
<div id="content">
</div>
JS file
var root = 'https://jsonplaceholder.typicode.com';
var index = 0;
$.ajax({
url: root + '/posts/1/comments',
method: 'GET'
}).then(function(data) {
$("#button").click(function() {
var notificationMessage = "Oops, there are no more user cards to display";
if (index >= data.length ) {
return alert(notificationMessage);
}
$("#content").append('<div id="card"><div class="title"><div class="image"></div><div id="name">'
+ data[index].name + '</div><span id="close"></span></div><div id="description">'
+ data[index].body + '<a href="mailto:" id="email">'
+ data[index].email + '</a></div></div>'
);
index++;
// remove all cards from a list and return index equally [0], to be able add user card again.
$("#clear").click(function() {
$("#card").remove();
index = 0;
});
});
});
//How to remove card by clicking on the close button?
have you try to use class in card element?
because id selector only get first matching element
$.ajax({
url: root + '/posts/1/comments',
method: 'GET'
}).then(function(data) {
$("#button").click(
function() {
var notificationMassage = "Oops, there are no more user cards to display";
if (index >= data.length ) {
return alert(notificationMassage);
}
$("#content").append('<div class="card"><div class="title"><div class="image"></div><div class="name">'
+ data[index].name + '</div><span class="close"></span></div><div class="description">'
+ data[index].body + '<a href="mailto:" id="email">'
+ data[index].email + '</a></div></div>'
);
index++;
// remove all cards from a list and return index equally [0], to be able add user card again.
$("#clear").click(function() {
$("#content").html('');
index = 0;
});
});
to remove one by one add this code
// remove one cards from a list.
$("#content").on("click", ".close", function() {
$(this).closest('div.card').remove();
});
First of all you need to change id to to class.
And here is solution:
codepen.io/ivanchuda/pen/xRjyJp
First of all, ids should be unique. I recommend changing yours into classes.
$("#content").append('<div class="card"><div class="title"><div class="image"></div><div class="name">'
+ data[index].name + '</div><span class="close"></span></div><div id="description">'
+ data[index].body + '<a href="mailto:" id="email">'
+ data[index].email + '</a></div></div>'
);
Now that we have all close icons with class close, we can add the following listener for all .close buttons to remove only the card which contains them.
$(document).on('click', '.close', function(){
$(this).closest('.card').remove(); // remove only closest '.card'
});
First off, I would change the ID on the divs to class instead since you are generating multiple cards. IDs should be unique. Then I would change the code to add one more line to your close-span:
<span class="close" onclick="$(this).parent().parent().remove()"></span>
Try like this
See the updated codeopen
Change the id to class .And match with parent() of parent()
on() more important
$(document).on("click",".close",function() {
$(this).parent().parent().remove()
});
You can use this code to implement what you want:
$("body").on("click", ".close", function(e) {
$(this).closest('.card').remove();
});
Note: Remember that use only single ID on a single page, instead use classes to make it work
See this CodePen
// jQuery on() method description
.on( events [, selector ] [, data ], handler )
See more about jQuery's on() method.
Hope this helps!
The short and not elegant answer is:
$("#content").on("click", "span[id=close]", function() {
$(this).closest("div[id=card]").remove();
});
This should work, but you need to do a better job than this. Your HTML is invalid, since id is expected to be unique and you use the very same id for different items. You could use classes instead, or make sure that the identifier is unique. Note that your SEO will instantly improve if you make your HTML valid. If you use classes instead of not-unique ids, then the script above will change to this one:
//content is unique, therefore it can remain an id
$("#content").on("click", "span.close", function() {
$(this).closest("div.card").remove();
});
I'm aware that this issue was addressed many times, that's why I read most of the topics on this problem that were already opened on Stack Overflow but none of the suggestions have helped me.
I have a list of div elements, each containing a hyperlink and a span element with additional information. The span elements are initially hidden and they need to be toggled whenever the sibling anchor element is clicked.
<div class="politician">
<a href="">
Антонијо Милошоски
</a>
<span class="additional" style="display: none">
2013ВМРО-ДПМНЕ1997-1
</span>
</div>
<div class="politician">
<a href="">
Силвана Бонева
</a>
<span class="additional" style="display: none">
2013ВМРО-ДПМНЕ1991-1
</span>
</div>
Here's the jQuery code I have written to handle the toggling of the hidden elements:
$('.politician a').click(function (e) {
e.preventDefault();
var $this = $(this).parent().find('span');
$(".politician span").not($this).hide();
$this.toggle();
});
My problem was already stated in the title. I'm expecting the hidden elements to be shown, but instead the page gets refreshed. I guess there has to be something wrong with the way I'm using the preventDefault() method.
EDIT
Here is the piece of code that generates the div.politician elements.
function populateList(politicians) {
var politlist = $("#list").html("");
for (var i in politicians) {
var person = politicians[i];
var politinfo = "<div class=\"politician\">" + person.name + " " + person.surname + "<span class=\"additional\" style=\"display: none\">" + person.lastserved;
for (var j in person.member)
{
var membership = person.member[j]
politinfo += membership.party + membership.enrol + membership.leave;
}
politinfo += "</span></div>";
$(politinfo).appendTo(politlist);
}
}
Since you're adding elements dynamically, you need to use event delegation:
$('#list').on('click', '.politician a', function(e) {
// your code
});
This is happending because your html is not loaded when you add click event listener to it.
Wrap your code in document.ready function, like this:
$(function(){
$('.politician a').click(function (e) {
var $this = $(this).parent().find('span');
$(".politician span").not($this).hide();
$(this).toggle();
e.preventDefault();
});
});
http://plnkr.co/edit/gist:1986619?p=preview
I have a click function setup whereby when you click on the .click div, it takes the data-hook attribute, and add it as a data-filter attribute to the .button div, this works fine, but after each click it is replacing the data-filter attribute with the new one, ideally I want to add a new value to the attribute with each click, separating each value with a comma.
Here's a jsFiddle demo: http://jsfiddle.net/neal_fletcher/pSZ2G/
HTML
<div class="button">THIS</div>
<div class="click" data-hook="one">CLICK</div>
<div class="click" data-hook="two">CLICK</div>
<div class="click" data-hook="three">CLICK</div>
<div class="click" data-hook="four">CLICK</div>
<div class="click" data-hook="five">CLICK</div>
jQuery:
$(".click").click(function () {
var thing = $(this).attr("data-hook");
$('.button').attr('data-filter', thing);
});
If this is at all possible? Any suggestions would be greatly appreciated!
You can store the previous value and can concatinate with new clicked value, something like.
$(".click").click(function () {
var thing = $(this).attr("data-hook");
var earData = $('.button').attr('data-filter');
if(typeof earData != 'undefined'){
$('.button').attr('data-filter', earData + ","+thing);
}else{
$('.button').attr('data-filter', thing);
}
});
DEMO
$(".click").click(function () {
var thing = $(this).attr("data-hook");
var prevValue = $('.button').attr('data-filter');
if(prevValue){
$('.button').attr('data-filter', prevValue +','+thing)
}
else{
$('.button').attr('data-filter', thing)
}
});
$(".click").click(function () {
var thing = $(this).attr("data-hook")||'';
var df = $('.button').attr('data-filter')||'';
$('.button').attr('data-filter', df+','+thing)
});
on a side note.. I hope you don't have any other elements with a .button class in it.. if you're looking to update a single target, you should reference by an id attrib instead.
I m new to jquey.I m facing a problem to attach data to particular inner div's. I am writing a demo code for the problem that i faced which did the same behaviour as original one. I have to small div inside a big div and i want to store (for some further processing) and show some data to small div's based on user input.
[html code]
<div id="ctrl-1001" class="big">
<div id="m1" class="small"></div>
<div id="m2" class="small"></div>
</div>
<div id="input" class="control-group module">
<label class="control-label">Module Name</label>
<div class="controls">
<select id="ModuleName" name="DSname" class="input-large">
<option>TitleImage</option>
<option>SearchBox</option>
<option>CategoryLinks</option>
<option selected>BannerSlides</option>
</select>
</div>
<button id="sa">save</button>
</div>
[jquery code]
$('.small').click(function(){
$('#input').show();
var myId = $(this).attr("id");
var myParentId = $(this).parents('.big').attr('id');
var uniqueId = '#'+myParentId+' #'+myId;
create(uniqueId);
});
function create(uniqueId){
$('#input').show();
$('#ModuleName').change(function(){
var name = this.value;
$('#sa').click(function(){
save_name(name,uniqueId);
});
});
}
function save_name(name,uniqueId){
var div = $(uniqueId)[0];
jQuery.data(div,'store',name);
//alert(uniqueId);
//var val = jQuery.data(div,'store');
$(uniqueId).text(name);
$('#input').hide();
}
But the problem is when I click on second div to store some data the first div also changes the value which second one contains. demo on Jsfiddle
It is because when you click the first time one change handler is added to the select with targeting #m1 element, then again when you click on #m2 a new change handler is added without removing the first one, so when you click the button both these code gets executed.
So try
$('.small').click(function () {
var uniqueId = '#' + this.id;
create(uniqueId);
});
function create(uniqueId) {
$('#input').show();
//remove previously added handlers
//take a look at namespaced event handlers
//also there is no need to have a change handler for the select element
$('#sa').off('click.create').on('click.create', function () {
var name = $('#ModuleName').val();
save_name(name, uniqueId);
});
}
function save_name(name, uniqueId) {
var div = $(uniqueId);
//you can use the .data() method instead of the static jQuery.data() method
div.data('store', name);
//alert(uniqueId);
var val = div.data('store');
$(uniqueId).text(name);
$('#input').hide();
}
Demo: Fiddle
But a more jQueryish solution might look like
var $smalls = $('.small').click(function () {
var uniqueId = '#' + this.id;
$smalls.filter('.active').removeClass('active');
$(this).addClass('active');
$('#input').show();
});
$('#sa').on('click', function () {
var name = $('#ModuleName').val();
save_name(name, '.small.active');
});
function save_name(name, target) {
var div = $(target);
//you can use the .data() method instead of the static jQuery.data() method
div.data('store', name);
//alert(uniqueId);
var val = div.data('store');
div.text(name);
$('#input').hide();
}
Demo: Fiddle
I am trying to convert a bunch of menu dropdowns into multiple elements. I have been able to do this when theres only one dropdown on the page but once I add the others, my script seems to run through each menu multiple times. I am new to Javascript/Jquery but I was wondering if there was a way to make it only input to its parent element?
Here is my current script that works for a single dropdown:
$('.mylinks li').each(function() {
var inputClass = $('.mylinks .link').html().toLowerCase();
$('body').prepend('<select class="'+inputClass+'" onchange="window.location.href=this.options[this.selectedIndex].value"></select>');
$('a').each(function() {
var linkName = $(this).html();
var linkVal = $(this).attr('href');
$('select').append('<option value="'+linkVal+'">'+linkName+'</option>');
});
});
HTML
<div class="mylinks">
<ul>
<li>
Drop 1
Link 1
Link 2
Link 3
</li>
<li>
Drop 2
Link 1
Link 2
Link 3
</li>
</ul>
</div>
I have an example of this error here as well: http://jsfiddle.net/UdTcF/
You can try this code:
$(document).ready(function () {
$('.mylinks li').each(function () {
var inputClass = $('.mylinks a').html().toLowerCase();
var select = $('<select class="' + inputClass + '" onchange="window.location.href=this.options[this.selectedIndex].value"></select>');
$('body').prepend(select);
$(this).find('a').each(function () {
var linkName = $(this).html();
var linkVal = $(this).attr('href');
select.append('<option value="' + linkVal + '">' + linkName + '</option>');
});
});
});
Use a variable select to save the <select> you want to add, and late can add <option> to this variable using select.append().
And use $(this).find('a') instead of $('a') to find <a> in certain <li> but not all <a>.
Here is jsfiddle.
Here:
$('a').each,
you're selecting all a elements. I think that you want to select just only those in the current li. SO, just replace add:
$('a',this).each,
it will select only a elements which are children of this, eg the li element.