jQuery - append changes using checkboxes - javascript

Instead of adding the item to the list using an add button and then removing the appended item using a remove button, how do I make them the same button (or input) so that if it is checked the item is appended to the list and if it is unchecked it is removed from the list?
I need the add and remove to be the same button so that I can remove the item from the list by either unchecking the item button OR the appended item's button.
// Wish Function
var wish = {
items: []
};
var update_product = function(product) {};
$(function() {
//Add to wish
var addToWish = function(product, qty) {
qty = qty || 1;
var wish = getWish();
var indexOfId = wish.items.findIndex(x => x.id == product.id);
if (indexOfId === -1) {
wish.items.push({
id: product.id,
img: product.img,
name: product.name,
});
$parent = $("#" + product.id).closest(".items__wish");
$parent
.find(".wish-icon")
.addClass("active")
.attr("data-prefix", "fas");
} else {
wish.items[indexOfId].qty++;
wish.items[indexOfId].stock = Number(product.stock);
}
//Update popup wish
updateWish(wish);
};
var getProductValues = function(element) {
var productId = $(element)
.closest(".items__wish")
.find(".item__tile")
.attr("id");
var productImg = $(element)
.closest(".items__wish")
.find(".item__img")
.attr("src");
var productName = $(element)
.closest(".items__wish")
.find(".item__title")
.html();
return {
id: productId,
img: productImg,
name: productName,
};
};
$(".my-wish-add").on("change", function() {
var product = getProductValues(this);
addToWish({
id: product.id,
img: product.img,
name: product.name,
});
});
//Update wish html to reflect changes
var updateWish = function(wish) {
//Add to shopping wish dropdown
$(".wishlist__items").html("");
for (var i = 0; i < wish.items.length; i++) {
$(".wishlist__items").append(
"<li>" +
'<div class="my-wish-item">' +
"<img src='" +
wish.items[i].img +
"' />" +
'<div class="wish-main">' +
'<div class="wish-name">' +
wish.items[i].name +
"</div>" +
'<div class="my-wish-remove-container">' +
'<input type="checkbox" id="my-wish-remove' +
i +
'" class="my-wish-remove" aria-hidden="true">' +
"<i class='fas fa-heart'></i>" +
"</div>"
);
//Remove from wish on id
var removeFromWish = function(id) {
var wish = getWish();
var wishIndex = wish.items.findIndex(x => x.id == id);
wish.items.splice(wishIndex, 1);
$parent = $("#" + id).closest(".items__wish");
$parent
.find(".wish-icon")
.first()
.removeClass("active")
.attr("data-prefix", "far");
//Update popup wish
updateWish(wish);
};
(function() {
var currentIndex = i;
$("#my-wish-remove" + currentIndex).on("change", function() {
$(this)
.closest("li")
.hide(400);
setTimeout(function() {
wish.items[currentIndex].stock = "";
update_product(wish.items[currentIndex]);
removeFromWish(wish.items[currentIndex].id);
}, 400);
});
})();
}
};
//Get Wish
var getWish = function() {
var myWish = wish;
return myWish;
};
});
body {
font-family: "Font Awesome\ 5 Pro";
font-weight: 900;
}
img {
width: 50px;
}
.wishlist__list {
position: absolute;
right: 0;
}
.wishlist__items li {
list-style: none;
}
<script src="https://pro.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-id="wishlist">
<div class="wishlist__list">
<ul class="wishlist__items">
</ul>
</div>
</div>
<div class='products'>
<div class="items__wish">
<div id='1' class='item__title item__tile'>Product 1</div>
<img class="item__img" src="https://www.iconasys.com/wp-content/uploads/2017/06/360-Product-Photography-White-Background-Acrylic-Riser-08.jpg">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>
</div>
<div class="items__wish">
<div id='2' class='item__title item__tile'>Product 2</div>
<img class="item__img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoqpSgkG4AQDQOe33jI1NiW3GW2JSB-_v36aREsVyFQH55JFOJ">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>

if your aim is only to manage wished list by checkboxes this code should be sufficient.
var addedProducts = [];
$(document).on('click', '.items__wish', function() {
var item = $(this);
var itemIndex = item.index();
if (item.parents('.wishlist__items').length > 0) {
itemIndex = parseInt(item.attr('data-index'))
}
if (item.find('.my-wish-add').prop('checked') && addedProducts.indexOf(itemIndex) < 0) {
if (item.parents('.wishlist__items').length == 0) {
item.clone().attr('data-index', itemIndex).appendTo($('.wishlist__items'))
addedProducts.push(itemIndex)
}
}
else if (item.find('.my-wish-add').prop('checked')==false && addedProducts.indexOf(itemIndex) >= 0) {
$('.products .items__wish').eq(itemIndex).find('.my-wish-add').prop('checked', false);
$('.wishlist__items .items__wish[data-index="' + itemIndex + '"]').remove();
addedProducts.splice( addedProducts.indexOf(itemIndex), 1 );
}
});
body {
font-family: "Font Awesome\ 5 Pro";
font-weight: 900;
}
img {
width: 50px;
}
.wishlist__list {
position: absolute;
right: 0;
}
.wishlist__items li {
list-style: none;
}
<script src="https://pro.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-id="wishlist">
<div class="wishlist__list">
<ul class="wishlist__items">
</ul>
</div>
</div>
<div class='products'>
<div class="items__wish">
<div id='1' class='item__title item__tile'>Product 1</div>
<img class="item__img" src="https://www.iconasys.com/wp-content/uploads/2017/06/360-Product-Photography-White-Background-Acrylic-Riser-08.jpg">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>
</div>
<div class="items__wish">
<div id='2' class='item__title item__tile'>Product 2</div>
<img class="item__img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoqpSgkG4AQDQOe33jI1NiW3GW2JSB-_v36aREsVyFQH55JFOJ">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>

Update: You may consider moving removeFromWish() to the same scope as addToWish() so that it is accessible to other functions.
You can use jquery to see if the checkbox is checked, then either append the item or remove the item from the list accordingly.
$(".my-wish-add").on("change", function() {
var product = getProductValues(this);
if ($(this).is(":checked")) {
addToWish({
id: product.id,
img: product.img,
name: product.name,
});
} else {
removeFromWish(product.id);
}
});
Making these two changes should be able to solve your problem. If you want to uncheck the checkbox upon removal of the list item, you can also try the following:
(function() {
var currentIndex = i;
$("#my-wish-remove" + currentIndex).on("change", function() {
$(this)
.closest("li")
.hide(400);
setTimeout(function() {
wish.items[currentIndex].stock = "";
update_product(wish.items[currentIndex]);
removeFromWish(wish.items[currentIndex].id);
// uncheck (productID - 1)th checkbox
$(".my-wish-add").eq(wish.items[currentIndex].id - 1).prop("checked", false);
}, 400);
});
})();
Unchecking a checkbox like this may not be very clear. I hope you get the basic idea and adapt this code so that it fits your style.
[Updated] Demo:
// Wish Function
var wish = {
items: []
};
var update_product = function(product) {};
$(function() {
//Add to wish
var addToWish = function(product, qty) {
qty = qty || 1;
var wish = getWish();
var indexOfId = wish.items.findIndex(x => x.id == product.id);
if (indexOfId === -1) {
wish.items.push({
id: product.id,
img: product.img,
name: product.name,
});
$parent = $("#" + product.id).closest(".items__wish");
$parent
.find(".wish-icon")
.addClass("active")
.attr("data-prefix", "fas");
} else {
wish.items[indexOfId].qty++;
wish.items[indexOfId].stock = Number(product.stock);
}
//Update popup wish
updateWish(wish);
};
//Remove from wish on id
var removeFromWish = function(id) {
var wish = getWish();
var wishIndex = wish.items.findIndex(x => x.id == id);
wish.items.splice(wishIndex, 1);
$parent = $("#" + id).closest(".items__wish");
$parent
.find(".wish-icon")
.first()
.removeClass("active")
.attr("data-prefix", "far");
//Update popup wish
updateWish(wish);
};
var getProductValues = function(element) {
var productId = $(element)
.closest(".items__wish")
.find(".item__tile")
.attr("id");
var productImg = $(element)
.closest(".items__wish")
.find(".item__img")
.attr("src");
var productName = $(element)
.closest(".items__wish")
.find(".item__title")
.html();
return {
id: productId,
img: productImg,
name: productName,
};
};
$(".my-wish-add").on("change", function() {
var product = getProductValues(this);
if ($(this).is(":checked")) {
addToWish({
id: product.id,
img: product.img,
name: product.name,
});
} else {
removeFromWish(product.id);
}
});
//Update wish html to reflect changes
var updateWish = function(wish) {
//Add to shopping wish dropdown
$(".wishlist__items").html("");
for (var i = 0; i < wish.items.length; i++) {
$(".wishlist__items").append(
"<li>" +
'<div class="my-wish-item">' +
"<img src='" +
wish.items[i].img +
"' />" +
'<div class="wish-main">' +
'<div class="wish-name">' +
wish.items[i].name +
"</div>" +
'<div class="my-wish-remove-container">' +
'<input type="checkbox" id="my-wish-remove' +
i +
'" class="my-wish-remove" aria-hidden="true">' +
"<i class='fas fa-heart'></i>" +
"</div>"
);
(function() {
var currentIndex = i;
$("#my-wish-remove" + currentIndex).on("change", function() {
$(this)
.closest("li")
.hide(400);
setTimeout(function() {
wish.items[currentIndex].stock = "";
update_product(wish.items[currentIndex]);
$(".my-wish-add").eq(wish.items[currentIndex].id - 1).prop("checked", false);
removeFromWish(wish.items[currentIndex].id);
}, 400);
});
})();
}
};
//Get Wish
var getWish = function() {
var myWish = wish;
return myWish;
};
});
body {
font-family: "Font Awesome\ 5 Pro";
font-weight: 900;
}
img {
width: 50px;
}
.wishlist__list {
position: absolute;
right: 0;
}
.wishlist__items li {
list-style: none;
}
<script src="https://pro.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-id="wishlist">
<div class="wishlist__list">
<ul class="wishlist__items">
</ul>
</div>
</div>
<div class='products'>
<div class="items__wish">
<div id='1' class='item__title item__tile'>Product 1</div>
<img class="item__img" src="https://www.iconasys.com/wp-content/uploads/2017/06/360-Product-Photography-White-Background-Acrylic-Riser-08.jpg">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>
</div>
<div class="items__wish">
<div id='2' class='item__title item__tile'>Product 2</div>
<img class="item__img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoqpSgkG4AQDQOe33jI1NiW3GW2JSB-_v36aREsVyFQH55JFOJ">
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>

Here's a much cleaner implementation of the required functionality using buttons. You can just as easily change it to use checkboxes instead.
Pro-tip: While I understand you might have specific requirements, I'd recommend using a component based design approach and considering using pure JavaScript instead of third party libraries like jQuery.
$(function() {
$("li button").click(function(event) {
let targetList = '';
if ($(event.target).closest(".list").attr('id') === 'product-list') {
targetList = '#wish-list ul';
targetLabel = 'Remove';
} else {
targetList = '#product-list ul';
targetLabel = 'Add';
}
event.target.innerHTML = targetLabel;
$(event.target).closest("li").appendTo(targetList);
})
$("#btn-display-list").click(function() {
alert(JSON.stringify(getListInfo('#wish-list')));
})
});
function getListInfo(type) {
const list = [];
$(type + " li").each(function(i, target) {
list.push({
id: $(target).attr("id"),
img: $(target).find("img").attr("src"),
name: $(target).find("h4").html()
})
})
return list;
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
color: #ddd;
font-weight: lighter;
}
.container {
display: flex;
}
.list {
width: 50%;
}
ul {
padding: 0px;
}
li {
list-style-type: none;
}
li img,
li div {
display: inline-block;
margin-bottom: 10px;
vertical-align: top;
}
li img {
max-width: 70px;
}
li h4 {
margin: 0px;
}
h4,
h3 {
font-weight: lighter;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="product-list" class="list">
<h3>Product Catalog</h3>
<ul>
<li id='prod-001'>
<img class="item__img" src="https://www.iconasys.com/wp-content/uploads/2017/06/360-Product-Photography-White-Background-Acrylic-Riser-08.jpg">
<div>
<h4>product 1</h4>
<button>Add</button>
</div>
</li>
<li id='prod-002'>
<img class="item__img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoqpSgkG4AQDQOe33jI1NiW3GW2JSB-_v36aREsVyFQH55JFOJ">
<div>
<h4>product 2</h4>
<button>Add</button>
</div>
</li>
</ul>
</div>
<div id="wish-list" class="list">
<h3>Wishlist</h3>
<ul>
</ul>
</div>
</div>
<hr/>
<button id="btn-display-list">Show Wishlist</button>

Related

Why is my text output from next() and prev() toggle incorrect?

When clicking the arrows to change the displayed option, the incorrect options is shown.
The user should be able click on the option menu to toggle it open/cosed and be able to click on a option to select it. Alternatively, the arrows could be used to toggle through the options instead.
This is the problematic code:
<script>
$("#arrow_left_physics").click(function() {
var $selected = $(".left_menu_option_selected").removeClass("left_menu_option_selected");
var divs = $("#left_menu__variant_physics").children();
divs.eq((divs.index($selected) - 1) % divs.length).addClass("left_menu_option_selected");
$("#left_menu_open .button-text").text($($selected).text());
});
$("#arrow_right_physics").click(function() {
var $selected = $(".left_menu_option_selected").removeClass("left_menu_option_selected");
var divs = $selected.parent().children();
divs.eq((divs.index($selected) + 1) % divs.length).addClass("left_menu_option_selected");
$("#left_menu_open .button-text").text($($selected).text());
});
</script>
$("#menu_open").click(function() {
$("#menu").toggle();
});
$(".menu_option").click(function() {
if ($(this).hasClass(".menu_option_selected")) {} else {
$(".menu_option").removeClass("menu_option_selected");
$(this).addClass("menu_option_selected");
$("#menu_open .button_text").text($(this).text());
}
});
$("#arrow_left").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) - 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($($selected).text());
});
$("#arrow_right").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) + 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($($selected).text());
});
.menu_open {
Cursor: pointer;
}
.menu {
display: none;
position: absolute;
border: 1px solid;
}
.menu_option {
Cursor: pointer;
Padding: 5px;
}
.menu_option:hover {
Background-Color: black;
Color: white;
}
.menu_option_selected {
color: green;
Background-color: #00ff0a4d;
}
.menu_option_selected:hover {
color: green;
}
.arrow {
Cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="arrow" type="button" id="arrow_left" value="❮" />
<input class="arrow" type="button" id="arrow_right" value="❯" />
</div>
<div>
<button class="menu_open" id="menu_open">
<span class="button_text">option1</span>
</button>
</div>
<div class="menu" id=menu>
<div class="menu_option menu_option_selected">option1</div>
<div class="menu_option">option2</div>
<div class="menu_option">option3</div>
<div class="menu_option">option4</div>
<div class="menu_option">option5</div>
<div class="menu_option">option6</div>
</div>
-It seems that the first click of the arrows isn't working and that the index function is incorrect somewhere.
The problem is this line:
$("#menu_open .button_text").text($($selected).text());
$($selected) is the option that was previously selected, so you're showing the text of the previous option, not the current option. (BTW, there's no need to wrap $selected in $(), since it's already a jQuery object.)
You should use $(".menu_option_selected").text() instead of $($selected).text() to get the current option.
You should also make the initial text of the button option1, so it matches the selected option.
$("#menu_open").click(function() {
$("#menu").toggle();
});
$(".menu_option").click(function() {
if ($(this).hasClass(".menu_option_selected")) {} else {
$(".menu_option").removeClass("menu_option_selected");
$(this).addClass("menu_option_selected");
$("#menu_open .button_text").text($(this).text());
}
});
$("#arrow_left").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) - 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($(".menu_option_selected").text());
});
$("#arrow_right").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) + 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($(".menu_option_selected").text());
});
.menu_open {
Cursor: pointer;
}
.menu {
display: none;
position: absolute;
border: 1px solid;
}
.menu_option {
Cursor: pointer;
Padding: 5px;
}
.menu_option:hover {
Background-Color: black;
Color: white;
}
.menu_option_selected {
color: green;
Background-color: #00ff0a4d;
}
.menu_option_selected:hover {
color: green;
}
.arrow {
Cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="arrow" type="button" id="arrow_left" value="❮" />
<input class="arrow" type="button" id="arrow_right" value="❯" />
</div>
<div>
<button class="menu_open" id="menu_open">
<span class="button_text">option1</span>
</button>
</div>
<div class="menu" id=menu>
<div class="menu_option menu_option_selected">option1</div>
<div class="menu_option">option2</div>
<div class="menu_option">option3</div>
<div class="menu_option">option4</div>
<div class="menu_option">option5</div>
<div class="menu_option">option6</div>
</div>
Just another version, refactoring your javascript code with some Arrow functions.
const setButtonText = () => {
$("#menu_open .button_text").text(
$(".menu_option_selected").text()
);
}
const moveSelection = direction => {
var selected = $(".menu_option_selected")
var options = $("#menu").children()
var newIndex;
if (direction == 'right') {
newIndex = (options.index(selected) + 1) % options.length
} else {
newIndex = (options.index(selected) - 1) % options.length
}
selected.removeClass("menu_option_selected")
options.eq(newIndex).addClass("menu_option_selected")
setButtonText()
}
// inizilize menu button_text
setButtonText()
$("#arrow_left").click(() => moveSelection('left'));
$("#arrow_right").click( () => moveSelection('right'));
$("#menu_open").click( () => $("#menu").toggle());
$(".menu_option").click( function() {
$(".menu_option_selected").removeClass("menu_option_selected")
$(this).addClass("menu_option_selected")
setButtonText()
});

jQuery show / hide notification if read

I'm trying to show/hide the .notification indicator when all of the .activity__item is marked as read. They can be marked read by clicking each individual item's .activity__button, or by clicking the button to mark all item's as read.
Using the function below I tried identifying whether each item has received the read state (getting the .activity__button--read class) and then hiding the notification if all of the items have been read. This doesn't seem to work here.
Is there an efficient way to show/ hide the notification indicator when all items have been read either by
Clicking them individually or
Marking all as read by clicking
the button?
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
} });
var open = 'fas fa-envelope-open';
var close = 'fas fa-envelope';
$(".activity__button[data-status]").off().on('click', function() {
var status = $(this).data('status');
if (status == 'unread') {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
} else {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
}
});
$('.mark').off().on('click', function() {
var status = $(this).data('status');
if (!status || status == 'unread') {
$(this).closest(".activity__header").find(".notification").hide();
$(this).html('Mark all unread').data('status', 'read');
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
});
} else {
$(this).html('Mark all read').data('status', 'unread');
$(this).closest(".activity__header").find(".notification").show();
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
$(this).closest(".activity__header").find(".notification").show();
});
}
});
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
}
});
.activity__header {
display: flex;
}
.activity__item {
position: relative;
height: 100px;
width: 300px;
border: 1px solid whitesmoke;
margin-top: -1px;
}
.activity__button {
cursor: pointer;
padding: 1rem;
font-size: 21px;
}
.activity__button svg {
color: #f8971d;
}
.activity__button.activity__button--read svg {
color: #47a877;
}
.activity__item--read {
background: #fafafa !important;
}
button {
padding: 12px;
margin: 1rem;
}
.notification {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #cb6f74;
color: #fff;
font-size: 10px;
font-weight: 600;
}
<script src="https://pro.fontawesome.com/releases/v5.8.1/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="activity__header">
<button class="mark" data-status="unread">Mark as Read</button>
<div class="notification"></div>
</div>
<div>
<div class="activity__item">
<div class="activity__button" data-status="unread"><i class="fas fa-envelope"></i>
</div>
</div>
<div class="activity__item">
<div class="activity__button" data-status="unread"><i class="fas fa-envelope"></i>
</div>
</div>
<div class="activity__item activity__item--read">
<div class="activity__button activity__button--read" data-status="read">
<i class="fas fa-envelope-open"></i>
</div>
</div>
<div class="activity__item">
<div class="activity__button" data-status="unread">
<i class="fas fa-envelope"></i>
</div>
</div>
</div>
</div>
data-status"read"`?
One way would be to check the state of all items each time they are updated
You could use a function like this
function updateNotificationIcon(){
var $activity_items = $('.activity__item'),
all_read = true;
// Loop through each .activity__item
$activity_items.each(function(){
// If item does NOT have the "read" class, set all_read to false
if(!$(this).hasClass('activity__item--read')){
all_read = false;
}
});
if(all_read){
$('.notification').hide();
}else{
$('.notification').show();
}
}
Then just run that function after each change to one of the item's "read" state
In your case I would update your javascript as so:
var open = 'fas fa-envelope-open';
var close = 'fas fa-envelope';
$(".activity__button[data-status]").off().on('click', function() {
var status = $(this).data('status');
if (status == 'unread') {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
} else {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
}
// Add here
updateNotificationIcon();
});
$('.mark').off().on('click', function() {
var status = $(this).data('status');
if (!status || status == 'unread') {
$(this).closest(".activity__header").find(".notification").hide();
$(this).html('Mark all unread').data('status', 'read');
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
});
} else {
$(this).html('Mark all read').data('status', 'unread');
$(this).closest(".activity__header").find(".notification").show();
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
$(this).closest(".activity__header").find(".notification").show();
});
}
// Add here
updateNotificationIcon();
});
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
}
});
function updateNotificationIcon() {
var $activity_items = $('.activity__item'),
all_read = true;
// Loop through each .activity__item
$activity_items.each(function() {
// If item does NOT have the "read" class, set all_read to false
if (!$(this).hasClass('activity__item--read')) {
all_read = false;
}
});
if (all_read) {
$('.notification').hide();
} else {
$('.notification').show();
}
}

jQuery - pre-set array values for add-to-cart

I have a basic add-to-cart that allows for adding and removing cart items using checkboxes.
I want to be able to pre-set some of the items to be in the cart by getting the item's id or data-wish attribute and adding it to the array for the items.
var wish = {
items: ["handbag", "backpack"]
};
How do I allow for items to be pre-selected so that they appear in the cart and the .my-wish-add button is :checked (for the icon's checked state animation).
// Wish Function
var wish = {
items: []
};
var update_product = function(product) {};
$(function() {
//Add to wish
var addToWish = function(product, qty) {
qty = qty || 1;
var wish = getWish();
var indexOfId = wish.items.findIndex(x => x.id == product.id);
if (indexOfId === -1) {
wish.items.push({
id: product.id,
img: product.img,
name: product.name,
location: product.location,
price: product.price
});
$parent = $("#" + product.id).closest(".items__cart");
$parent
.find(".wish-icon")
.addClass("active")
.attr("data-prefix", "fas");
} else {
wish.items[indexOfId].stock = Number(product.stock);
}
//Update popup wish
updateWish(wish);
};
//Remove from wish on id
var removeFromWish = function(id) {
var wish = getWish();
var wishIndex = wish.items.findIndex(x => x.id == id);
wish.items.splice(wishIndex, 1);
$parent = $("#" + id).closest(".items__cart");
$parent
.find(".wish-icon")
.first()
.removeClass("active")
.attr("data-prefix", "far");
//Update popup wish
updateWish(wish);
};
var getProductValues = function(element) {
var productId = $(element)
.closest(".items__cart")
.find(".item__tile")
.attr("id");
var productImg = $(element)
.closest(".items__cart")
.find(".item__img")
.attr("src");
var productName = $(element)
.closest(".items__cart")
.find(".item__title")
.html();
var productPrice = $(element)
.closest(".items__cart")
.find(".cost")
.html();
var productLocation = $(element)
.closest(".items__cart")
.find(".item__location")
.html();
var productTax = $(element)
.closest(".items__cart")
.find(".circle")
.html();
return {
id: productId,
img: productImg,
name: productName,
location: productLocation,
price: productPrice,
tax: productTax
};
};
$(".my-wish-add").on("change", function() {
var product = getProductValues(this);
if ($(this).is(":checked")) {
addToWish({
id: product.id,
img: product.img,
name: product.name,
location: product.location,
price: product.price,
tax: product.tax
});
} else {
removeFromWish(product.id);
}
});
//Update wish html to reflect changes
var updateWish = function(wish) {
$(".wishlist__items").html("");
for (var i = 0; i < wish.items.length; i++) {
$(".wishlist__items").append(
"<li class='wish__item'>" +
'<div class="wish__thumb">' +
"<img src='" +
wish.items[i].img +
"' />" +
"</div>" +
'<div class="wish__info">' +
'<div class="wish__header">' +
'<div class="wish-name">' +
wish.items[i].name +
"</div>" +
"</div>" +
' <div class="wish__value">' +
"<span>Price: </span> $ " +
wish.items[i].price +
"</div>" +
"</div>" +
'<div class="wish__remove">' +
'<label class="wish__label">' +
'<input type="checkbox" id="my-wish-remove' +
i +
'" class="my-wish-remove" aria-hidden="true">' +
"<i class='fas fa-heart'></i>" +
"</div>" +
"</div>"
);
(function() {
var currentIndex = i;
$("#my-wish-remove" + currentIndex).on("change", function() {
$(this)
.closest("li")
.hide(400);
setTimeout(function() {
wish.items[currentIndex].stock = "";
update_product(wish.items[currentIndex]);
$("#" + wish.items[currentIndex].id)
.parents()
.find($(".wish-btn > input"))
.prop("checked", false);
removeFromWish(wish.items[currentIndex].id);
}, 400);
});
})();
}
};
//Get Wish
var getWish = function() {
var myWish = wish;
return myWish;
};
});
.wish__item {
display: flex;
}
.my-wish-add {
font-family: "Font Awesome\ 5 Pro";
font-weight: 900;
color: #6394f8;
}
.wish-btn {
position: relative;
cursor: pointer;
}
.wish-btn input {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.wish-icon.active {
color: green;
}
.active i.fa.fa-wishlist__list {
color: #6394f8;
}
.my-wish-remove {
font-size: 20px;
cursor: pointer;
color: rgb(109, 109, 109);
}
.my-wish-remove:hover {
color: #464646;
}
.items__wish {
border: 1px solid;
width: 150px;
}
.wish__info {
flex: 1;
border: 2px solid;
}
.wish__thumb {
display: flex;
}
.wish__thumb img {
height: 30px;
}
.wish-main {
flex: 1;
}
img {
width: 50px;
}
.wishlist__list {
margin: 20px 0;
float: right;
background: #fff;
width: 320px;
position: absolute;
border: 2px solid;
border-radius: 3px;
padding: 20px;
right: 7.5%;
}
.wishlist__items li {
list-style: none;
}
.wishlist__list-empty img {
width: 100px;
}
<script src="https://pro.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-id="wishlist">
<div class="wishlist__list">
<ul class="wishlist__items">
</ul>
</div>
</div>
<div class='products'>
<div class="items__cart">
<div id='headphones' class='item__title item__tile' data-wish="headphones">Product 1</div>
<img class="item__img" src="https://www.iconasys.com/wp-content/uploads/2017/06/360-Product-Photography-White-Background-Acrylic-Riser-08.jpg">
<div>
<span>$</span>
<span class='cost'>500</span>
</div>
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></input></label>
</div>
<div class="items__cart">
<div id='backpack' class='item__title item__tile' data-wish="backpack">Product 2</div>
<div>
<h4 class="count">200</h4>
</div>
<img class="item__img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoqpSgkG4AQDQOe33jI1NiW3GW2JSB-_v36aREsVyFQH55JFOJ">
<div>
<span>$</span>
<span class='cost'>460</span>
</div>
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></label>
</div>
<div class="items__cart">
<div id='handbag' class='item__title item__tile' data-wish="handbag">Product 3</div>
<h4 class="count">400</h4>
<img class="item__img" src="https://qph.fs.quoracdn.net/main-qimg-de7d9680c4460296e461af9720a77d64">
<div>
<span>$</span>
<span class='cost'>212</span>
</div>
<label class="wish-btn">
<input type="checkbox" name="wish-check" class='my-wish-add'><i class="wish-icon far fa-heart"></i></label>
</div>

How to delete an item from a drag and drop menu

I'm trying to add an Delete button function to a drag and drop shopping cart. I have the button in place but I can not call a function that seems to work. I'm very novice.
Im not sure if were the function should appear because the list is created from a drag and drop menu
Below is the code so far - any help would be greatly appreciated
thanks
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>HTML 5 Drag and Drop Shopping Cart</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.products1 { grid-area: products1; }
.menu1 { grid-area: menu1; }
.menu2 { grid-area: menu2; }
.menu3 { grid-area: menu3; }
.menu4 { grid-area: menu4; }
.grid-container {
display: grid;
grid-template-areas:
'products1 menu1 menu2 menu3 menu4'
;
grid-gap: 5px;
background-color: #2196F3;
padding: 5px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 20px;
}
#item-container{
width: 280px;
padding: 10px;
border: 5px solid gray;
margin:20px auto;
text-align: center;
font-size: 20px;
}
ul, li{
list-style: none;
margin: 2px;
padding: 0px;
cursor: grabbing;
}
section#cart ul{
height: 600px;
overflow: auto;
background-color: #cccccc;
}
</style>
<script src="jquery-3.3.1.min.js"></script>
<script>
function addEvent(element, event, delegate ) {
if (typeof (window.event) != 'undefined' && element.attachEvent)
element.attachEvent('on' + event, delegate);
else
element.addEventListener(event, delegate, false);
}
addEvent(document, 'readystatechange', function() {
if ( document.readyState !== "complete" )
return true;
var items = document.querySelectorAll("section.products ul li");
var cart = document.querySelectorAll("#cart ul")[0];
function updateCart(){
var total = 0;
var term = 48;
var rate = 7;
var amount = 15090;
var cart_items = document.querySelectorAll("#cart ul li")
for (var i = 0; i < cart_items.length; i++) {
var cart_item = cart_items[i];
var quantity = cart_item.getAttribute('data-quantity');
var price = cart_item.getAttribute('data-price');
var payment = amount*((((rate/12)/100)*((1+((rate/12)/100))**term))/(((1+((rate/12)/100))**term)-1));
var sub_total = parseFloat(quantity * parseFloat(price));
cart_item.querySelectorAll("span.sub-total")[0].innerHTML = + sub_total.toFixed(2);
total += sub_total*((((rate/12)/100)*((1+((rate/12)/100))**term))/(((1+((rate/12)/100))**term)-1));
newpayment=total+payment
}
document.querySelectorAll("#cart span.total")[0].innerHTML = total.toFixed(2);
document.querySelectorAll("#cart span.newpayment")[0].innerHTML = newpayment.toFixed(2);
}
function addCartItem(item, id) {
var clone = item.cloneNode(true);
clone.setAttribute('data-id', id);
clone.setAttribute('data-quantity', 1);
clone.removeAttribute('id');
var fragment = document.createElement('span');
fragment.setAttribute('class', 'quantity');
fragment.innerHTML = '<button id="butt" onclick="one(this);">delete item</button> $';
clone.appendChild(fragment);
fragment = document.createElement('span');
fragment.setAttribute('class', 'sub-total');
clone.appendChild(fragment);
cart.appendChild(clone);
}
function updateCartItem(item){
var quantity = item.getAttribute('data-quantity');
quantity = parseInt(quantity) + 1
item.setAttribute('data-quantity', quantity);
var span = item.querySelectorAll('span.quantity');
span[0].innerHTML = ' x ' + quantity;
}
function onDrop(event){
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
var id = event.dataTransfer.getData("Text");
var item = document.getElementById(id);
var exists = document.querySelectorAll("#cart ul li[data-id='" + id + "']");
{
addCartItem(item, id);
}
updateCart();
return false;
}
function onDragOver(event){
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
return false;
}
addEvent(cart, 'drop', onDrop);
addEvent(cart, 'dragover', onDragOver);
function onDrag(event){
event.dataTransfer.effectAllowed = "move";
event.dataTransfer.dropEffect = "move";
var target = event.target || event.srcElement;
var success = event.dataTransfer.setData('Text', target.id);
}
for (var i = 0; i < items.length; i++) {
var item = items[i];
item.setAttribute("draggable", "true");
addEvent(item, 'dragstart', onDrag);
};
});
</script>
</head>
<body>
<div id="page">
<div class="grid-container">
<div class="products1">
<section id="products" class="products">
<h1></h1>
<ul>
<li id="product-1" data-price="3999.00"><div id="item-container">Product 1<br> descr<br>descr </div></li>
<li id="product-2" data-price="1895"><div id="item-container">Product 2<br> descr<br>descrip</div></li>
<li id="product-3" data-price="2.99"><span>Product 3</span></li>
<li id="product-4" data-price="3.50"><span>Product 4</span></li>
<li id="product-5" data-price="4.25"><span>Product 5</span></li>
<li id="product-6" data-price="6.75"><span>Product 6</span></li>
<li id="product-7" data-price="1.99"><span>Product 7</span></li>
</ul>
</section>
</div>
<div class="menu1">
<section id="cart" class="shopping-cart">
<h1>Preferred</h1>
<ul>
</ul>
<p> $<span class="total">0.00</span></p>
<p> $<span class="newpayment">0.00</span></p>
</section>
</div>
<div class="menu2">
<section id="cart" class="shopping-cart">
<h1>Value</h1>
<ul>
</ul>
<p> $<span class="total">0.00</span></p>
</section>
</div>
<div class="menu3">
<section id="cart" class="shopping-cart">
<h1>Basic</h1>
<ul>
</ul>
<p> $<span class="total">0.00</span></p>
</section>
</div>
<div class="menu4">
<section id="cart" class="shopping-cart">
<h1>Economy</h1>
<ul>
</ul>
<p> $<span class="total">0.00</span></p>
</section>
</div>
</div>
</div>
</body>
</html>

can't get the right index result with an ajax call

I was trying to iterate the 'streamers' array by the variable showindex but failed,it just shows the first element "monstercat" and last element "amazhs" of the array, using debug in chrome and showindex in the displayResult function always is 0 and 9, can't figure out why. Any ideas?
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
streamers.forEach(function(streamer, index) {
showindex = index;
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamer,
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
});
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
}
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
It's because the calls are all happening at the same time so instantly showindex = 9 a way around this would be to do the incrementation in displayResult though it could still go wrong (but it's less likely).
You probably could change your code entirely to make it use promises which would be a lot safer.
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
streamers.forEach(function(streamer, index) {
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamer,
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
});
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
showindex++;
}
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
Here's another way to do it, it doesn't use foreach but iterates through the array another way. This way is a bit slower but means it doesn't get ahead of itself (you can actually see each one pop in)
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
var logo = "";
var channelName = "";
var showindex = 0;
//Work out if there are any streamers left in the array
function calcStreamers() {
if (showindex < (streamers.length - 1)) {
//if there are add 1 and go get it
showindex++;
streamersGet();
} else {
//if not just stop
return false
}
};
//The get function
function streamersGet() {
$.ajax({
type: 'GET',
jsonp: "callback",
url: 'https://api.twitch.tv/kraken/streams/' + streamers[showindex],
headers: {
'Client-ID': 'd50b88uvtwlhdfrqi3vj3k1hm3izkyx'
},
success: displayResult
});
};
function displayResult(data) {
var outstring = "";
if (data.stream !== null) {
channelName = data.stream.channel.display_name;
logo = data.stream.channel.logo;
} else {
logo = "https://placeholdit.imgix.net/~text?txtsize=6&txt=50%C3%9750&w=50&h=50";
channelName = streamers[showindex];
}
outstring +=
"<li class='streamer'>" +
"<img class='streamer-icon' src='" + logo + "'/>" +
"<p class='streamer-name'>" +
"<a href='http://twitch.tv/" + channelName + "' target='_blank'>" + channelName + "</a></p>" +
"<span class='streamer-status'>" +
"<i class='fa fa-exclamation'></i></span></li>"
$("#showBox").append(outstring);
//Once the data has been added to the page go and check if there are more to add
calcStreamers();
}
//Initally start by getting the first result
streamersGet();
});
ul {
padding: 0;
margin: 0;
}
.tab-content {
border: 1px solid #ddd;
border-top: none;
}
.streamer {
list-style-type: none;
padding: 10px;
}
.streamer-icon {
width: 50px;
}
.streamer-name {
display: inline-block;
margin-left: 10px;
}
.streamer-status {
float: right;
padding-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row col-md-4 col-md-offset-4">
<ul class="nav nav-tabs" role="tablist">
<li class="active">all
</li>
<li>online
</li>
<li>offline
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="all">
<ul id="showBox">
</ul>
</div>
<div class="tab-pane" id="online">
<ul></ul>
</div>
<div class="tab-pane" id="offline">
<ul></ul>
</div>
</div>
</div>
</div>
You wanted to iterate through the array correct?
var streamers = ['monstercat', 'sivhd', 'cryaotic', 'nightblue3', 'picoca_lol', 'freecodecamp', 'trick2g', 'riotgamesbrazil', 'riotgames', 'amazhs'];
$(document).ready(function() {
$(streamers).each(function(index, streamer){
console.log(streamer+" "+index);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Categories