Make all selected css circles active - javascript

I am trying to create a progress bar of css circles, in which after clicking on every circle like 1, 2, 3 all the three circles and their connected line will be filled by red color and if go back like 3, 2, 1 then color should be removed.
HTML :
<div class="row well" id="rows">
<ul id="progressbar" class="progressbar">
<li class="cir danger">THOUGHFUL</li>
<li class="cir">PASSION</li>
<li class="cir">POWER OF DESIGN</li>
<li class="cir">BUILDING RELATIONSHIPS</li>
<li class="cir">ENHANCE HUMAN INTERATION</li>
</ul>
</div>
JS :
var header = document.getElementById("rows");
var bar = document.getElementsByClassName("progressbar");
var btns = header.getElementsByClassName("cir");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function () {
var danger = document.getElementsByClassName("danger");
danger[0].className = danger[0].className.replace("danger", "");
this.className += " danger";
});
}
Sample Img:
Referring to above imag, if i click on circle 3 then circle 1,2,3 should be in red color and then if i click circle 2 then circle 3 should be white and 1 & 2 should be red, vice versa.
I have tried to achieve it by JS but classnotfound error .
Any help for this would be appreciated.

Every time a circle is clicked, grab its data-id and activate all circles of an equal or lesser data-id.
let circles = document.querySelectorAll(".circle")
circles.forEach(el => {
el.addEventListener("click", (e) => {
let id = e.target.dataset.id
circles.forEach(el2 => {
if(el2.dataset.id <= id){
el2.classList.add("active")
}else{
el2.classList.remove("active")
}
})
})
})
.circled{display:flex}
.circle{
border-radius:50%;
width:50px;
height:50px;
border: solid 2px #333;
display:inline-flex;
align-items:center;
justify-content:center;
position:relative;
margin-left: 44px;
cursor:pointer;
}
.circle:not(:first-of-type)::before{
height: 2px;
width: 50px;
content:"";
background-color: #333;
position:absolute;
left:-50px;
}
.circle.active{
border-color: #f00;
}
.circle.active:not(:first-of-type)::before{
background-color: #f00;
}
<div class="circles">
<div class="circle active" data-id="1">1</div>
<div class="circle" data-id="2">2</div>
<div class="circle" data-id="3">3</div>
<div class="circle" data-id="4">4</div>
<div class="circle" data-id="5">5</div>
</div>

Not proud of this
var header = document.getElementById("rows");
var bar = document.getElementsByClassName("progressbar");
var btns = header.getElementsByClassName("cir");
Array.prototype.forEach.call(btns,function(btn){
btn.addEventListener('click', function(e){
updateProgress(btn,e)
})
});
function updateProgress(btn,e){
removeDangerFromAll();
for( let btnToCheck of btns){
btnToCheck.classList.add('danger');
if (btnToCheck == btn) {
break;
}
}
}
function removeDangerFromAll(){
Array.prototype.forEach.call(btns,function(btn){
btn.classList.remove('danger');
});
}
UPDATE: Switched to cleaner classList as Other Answer

Related

changing the content of a div

I would like to change the content of a div. I have three divs:
<div
class="box1"
style="height: 200px; width: 200px; background-color: red"
>
A
</div>
<br />
<div
class="box2"
style="height: 200px; width: 200px; background-color: blue"
>
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div
class="box3"
style="height: 200px; width: 200px; background-color: yellow"
>
C
</div>
when the page is ready the 2 and 3rd box displays none:
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
}
$(document).ready(hideElementBoxOnLoad);
I want a click that toggles the content of box2 and box3 into box1 and then back to box1 content:
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
}
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
So far it worked but it does not display the content of box2 only box3. what did i do wrong and what better way can i toggle with a boolean.
See below
Instead of trying to swap content between each div just use JS to go through the array of them and swap an active class between them;
var boxes = document.getElementsByClassName('box');
var change = document.getElementById('change');
var counter = 0;
change.addEventListener('click', function(){
boxes[counter].classList.remove('active');
boxes[counter].nextElementSibling.classList.add('active');
counter++;
if(counter === boxes.length) {
counter = 0;
boxes[0].classList.add('active');
}
});
.box {
display: none;
width: 100px;
height: 100px;
background-color: gray;
}
.box.active {
display:block
}
<div class="box active">A</div>
<div class="box">B</div>
<div class="box">C</div>
<button id="change">Change Content</button>
im not completely sure if i understood ur question.
but below u can see and even test with the snippet button.
the button now add what ever content in in the yellow box, and whats in the input field of the blue box into the red box. listing them downwards.
if you want to replace the content completely.
just change the logic to box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
this is the most simple way to do it thats easy to understand just by reading the code i think.
hope this helps!
function changeContent() {
//the button
const btn = document.getElementById("btn");
//the boxes
const box1 = document.getElementById("box1");
const box2 = document.getElementById("box2");
const box3 = document.getElementById("box3");
//a spacer
const spacer = "<br>";
//the input field
const input = document.getElementById("input");
//logic
box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
}
div{
border-radius: 5px;
text-align: center;
font-family: sans-serif;
}
#box1{
min-height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(255, 73, 73);
}
#box2 {
height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(0, 195, 255);
}
#box3 {
height: 200px;
width: 200px;
padding: 5px;
background-color: yellow;
}
button{
padding: 3px;
margin-top: 10px;
}
<div id="box1">
<p>contetnt A</p>
</div>
<br />
<div id="box2" >
<label for="">tex</label>
<input id="input" type="text" />
<button id="btn" onclick="changeContent()">click me</button>
</div>
<br />
<div id="box3">
contetnt C
</div>
List of bugs :-
You had declared the var chang locally instead of globally, which make it true whenever you runs the function.
You are directly writing value from one tag to another, which causing the data loss, when you run your function second time.
For example :- When you click the button first time, the data is swapped, but for the second click, the data first div is lost and cannot be brought back...
Solution :- Store the data in an array in document.ready event handler and extract data from the array to update you html tags.
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
content = [box1.textContent, box2.textContent, box3.textContent];
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
}
var content = [];
window.onload = (hideElementBoxOnLoad);
var index = 0;
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
/* let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
*/
function cycle(n, x = 0, y = content.length - 1, a = 1) {
n += a;
if (n > y) return x;
if (n < x) return y;
return n;
}
index = cycle(index);
box1.textContent = content[index];
}
<div class="box1" style="height: 200px; width: 200px; background-color: red">
A
</div>
<br />
<div class="box2" style="height: 200px; width: 200px; background-color: blue">
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div class="box3" style="height: 200px; width: 200px; background-color: yellow">
C
</div>
<button id="btn"> CLICK ME </button>
Explaination
Here I first stored the tags textContent in a array content, in the starting of the code.
Then, inside the button click handler, a simple cycle function to cycle on the values stored inside the content array.

How to save new background color via `colorpicker` to `localStorage`?

I know there's a lot of similar questions.. I've tried them but I really can't incorporate it to my project.
I'm trying to save to localStorage the new background-color selected using the native colorpicker.
I'm almost there but I just can't figure out how to make it work.
Please see my code so far:
function changeBgColor(color) {
if (color) window.localStorage.setItem('bgColor', color);
else if (!(color = window.localStorage.getItem('bgColor'))) return;
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
The important feature for me are:
To change background color using input="color"
Use class selector since I have multiple divs I want to target with the same input
Save the value to localStorage
That's all really. I just need to figure out the part where the value gets saved to localStorage.
After I make this work, I will need to replicate it for a different set of divs..
Thank you in advance for any help.
If check had = assignment instead of == comparison
Here is a working refactored snippet:
let pretend_local_storage = null
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
document.getElementById('colorpicker').addEventListener('input', function(e) {
color = e.target.value
if (color === pretend_local_storage) return
pretend_local_storage = color
elements.forEach((element) => element.style.background = color)
})
}
window.onDOMContentLoaded = setupBackgroundColorChange();
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
Local Storage example:
localStorage.getItem('bgColor', null)
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
setColor(elements, localStorage.getItem('bgColor', '#000'))
document.getElementById('colorpicker').addEventListener('input', function (e) {
color = e.target.value
if (color === localStorage.getItem('bgColor')) return
localStorage.setItem('bgColor', color)
setColor(elements, color)
})
}
function setColor(elements, color) {
elements.forEach((element) => element.style.background = color)
}
window.onDOMContentLoaded = setupBackgroundColorChange();
First of all i would use onchange trigger. To be honest, you dont need any condition inside the function. you can set the color to localStorage and that is it.
/* this lines check if already set color to localStorage */
if (window.localStorage.getItem('bgColor')) {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
}
function changeBgColor() {
let color = document.getElementById('colorpicker').value;
const bg_curr = localStorage.getItem('bgColor');
console.log(color, bg_curr);
localStorage.setItem('bgColor', color);
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = color;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<input type="color" id="colorpicker" onchange="changeBgColor();">
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>

show/hide elements and switch between them js

I have two elements that are hidden. When button a is clicked, I would like div a to show. When button b is clicked, I would like div a to close and div b to show.
However, if button a is clicked a second time after being shown, I would like it to hide the div again. Same with button b.
Update:
I was able to get the buttons to toggle properly.
However, upon initial loading, I want them to be hidden, or not visible until the button is clicked.
The following is my current javascript
function openFamily(evt, famName) {
var i, x, y, tablinks;
x = document.getElementsByClassName("family");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
tablinks = document.getElementsByClassName("familytablink");
for (i = 0; i < x.length; i++)
document.getElementById(famName).style.display = "block";
}
I have a CSS element:
.container{
display: none;
}
HTML:
<div>
<div>
<button class="familytablink" onclick="openFamily(event,'zep')">Zephaniah</button>
<button class="familytablink" onclick="openFamily(event,'anna')">Anna</button>
</div>
<div id="zep" class="container mainp-2 family">
filler text
</div>
<div id="anna" class="container mainp-2 family">
filler text
</div>
</div>
Here's an exemple of how you can achieve that
var toggleDivById = function (id) {
var div = document.getElementById(id);
if (div.classList.contains('active')) {
return div.classList.remove('active');
}
div.classList.add('active');
}
var handleToggleClick = function (event) {
var targetId = event.target.dataset.target;
toggleDivById(targetId);
}
document.querySelectorAll('.toggle')
.forEach(function(toggle) {
toggle.addEventListener('click', handleToggleClick)
})
.toggable {
width: 50px;
height: 50px;
background-color: crimson;
border: 2px solid tomato;
visibility: hidden;
transition: all 100ms ease-out;
border-radius: 5px;
box-shadow: 1px 1px 2px indianred;
}
.toggable.active {
visibility: visible
}
<button data-target="a" class="toggle">A</button>
<button data-target="b" class="toggle">B</button>
<hr/>
<div id="a" class="toggable">A</div>
<div id="b" class="toggable">B</div>
In jQuery:
<script type="application/javascript">
$(document).ready(function(){
$("#button1").click(function(){
$("diva").show();
});
$("#button2").click(function(){
$("diva").hide();
$("divb").show();
});
});
</script>
In JS:
<script type="application/javascript">
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
You can use hide and show function in Jquery and use it when a button is clicked something like this :
like
$("selector").click(function(){
$("divid").hide();
$("divid").show();
})

Switch classes on click next or back

I'm trying to setup multiple-step form in which the first step is visible by default and rest of the steps are hidden with class "hide". I'd like to switch the class with Next and Back button so only one step is visible at a time. Could you please help with this (Already spent an hour on this)
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
$('.next').click(function(){
$('div:not(.hide)').next().removeClass('hide');
$('.hide').prev().removeClass('hide')
})
Try combining the 2 actions into one, like so:
$('.next').click(function(){
$('.steps div:not(.hide)').addClass('hide').next().removeClass('hide');
})
That way, you add the .hide class on your current div and then remove it on the next one.
You can use something similar for the Back button, by replacing .next() with .previous()
$('.next').click(function() {
// find the div that is not hidden
var $current = $('.steps div:not(.hide)');
// only perform logic if there is a proceeding div
if ($current.next().length) {
// show the next div
$current.next().removeClass('hide');
// hide the old current div
$current.addClass('hide')
}
});
$('.back').click(function() {
// find the div that is not hidden
var $current = $('.steps div:not(.hide)');
// only perform logic if there is a preceeding div
if ($current.prev().length) {
// show the previous div
$current.prev().removeClass('hide');
// hide the old current div
$current.addClass('hide')
}
});
.hide { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
You can add a current step variable to track the currently displayed step and two css for styling and showing your content.
jQuery(function($) {
let currentstep = 1;
let maxsteps = 4;
function showstep(step) {
let step_c = '.step' + step;
for (i = 1; i <= maxsteps; i++) {
var step_selector = '.step' + i;
$(step_selector).removeClass('show');
$(step_selector).addClass('hide');
}
$(step_c).removeClass('hide');
$(step_c).addClass('show');
};
$('.next').click(function() {
currentstep = currentstep + 1;
currentstep = (currentstep % (maxsteps + 1));
if (currentstep == 0) currentstep = 1;
showstep(currentstep);
});
$('.back').click(function() {
currentstep = currentstep - 1;
currentstep = (currentstep % (maxsteps + 1));
if (currentstep == 0) currentstep = 4;
showstep(currentstep);
});
});
.hide {
display: none;
}
.show {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1 show">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
I converted Taplar's answer to a jQuery plugin.
You are essentially navigating left or right by one, using the previous and next functions. These functions navigate through the sibling elements.
(function() {
$.fn.moveRight = function(className) {
var $curr = this.find('div:not(.' + className + ')');
if ($curr.next().length) $curr.next().removeClass(className);
else this.find('div:first-child').removeClass(className);
$curr.addClass(className);
return this;
};
$.fn.moveLeft = function(className) {
var $curr = this.find('div:not(.' + className + ')');
if ($curr.prev().length) $curr.prev().removeClass(className);
else this.find('div:last-child').removeClass(className);
$curr.addClass(className);
return this;
};
})(jQuery);
$('.next').on('click', (e) => $('.steps').moveRight('hide'));
$('.back').on('click', (e) => $('.steps').moveLeft('hide'));
.hide {
display: none;
}
.nav {
width: 260px;
text-align: center;
}
.nav .nav-btn::selection { background: transparent; }
.nav .nav-btn::-moz-selection { background: transparent; }
.nav .nav-btn {
display: inline-block;
cursor: pointer;
}
.steps {
width: 260px;
height: 165px;
border: thin solid black;
text-align: center;
line-height: 165px;
font-size: 3em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="nav">
<div class="nav-btn back">[ << Back ]</div>
<div class="nav-btn next">[ Next >> ]</div>
</div>

How to disable other div's dropping functionality if the user clicks on one of the droppable div using jquery

I am very new to jquery. Presently i am working on a project of shopping cart where there are three types of items(item1,item2,item3) and three bags(bag1,bag2,bag3) and one shopping cart such as bag1 accepts item1,item2,item3 , bag2 accepts item2,item3 and bag3 accepts only item3 on drop which I have developed so far.
Now i want to add additional functionality such as the user should first select any one of the bag(example bag1) and then try dropping items into the bag1 such that other two bags dropping functionality should be disable(other bags should not accept any item even if it is acceptable by that bag) and also reverse if user selects other bags.
I tried all possible ways.Any one out there plz try it.
http://jsfiddle.net/Vwu37/15/
html
<div class="bag1" ><p>bag1</p></div>
<div class="bag2" > <p>bag2</p></div>
<div class="bag3" ><p>bag3</p></div>
<div class="item1"><p>item1_1</p></div>
<div class="item1"><p>item2_1</p></div>
<div class="item1"><p>item2_1</p></div>
js
$('.bag1').droppable({
accept: '.item1,.item2,.item3',
onDragEnter:function(e,source){
$(source).draggable('options').cursor='auto';
},
onDragLeave:function(e,source){
$(source).draggable('options').cursor='not-allowed';
},
onDrop:function(e,source){
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
addProduct(name, parseFloat(price.split('$')[1]));
}
});
$('.bag2').droppable({
accept: '.item2,.item3',
onDragEnter:function(e,source){
$(source).draggable('options').cursor='auto';
},
onDragLeave:function(e,source){
$(source).draggable('options').cursor='not-allowed';
},
onDrop:function(e,source){
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
}
});
$('.bag3').droppable({
accept: '.item3',
onDragEnter:function(e,source){
$(source).draggable('options').cursor='auto';
},
onDragLeave:function(e,source){
$(source).draggable('options').cursor='not-allowed';
},
onDrop:function(e,source){
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
}
});
What I would do in your position is instead of having three different classes (bag1, bag2, bag3), I would create a new class called bag and give each of the bags that class and then specify any other CSS specific to each one in another class called one, two and three. So for example the first bag would become <div class="bag two" style=".... I would then add a jQuery function like this
$('.bag').click(function() {
if($('.selected').length > 0 && !$(this).hasClass('selected'))
{ // Checks to see if there is a selected and if the clicked one is selected
$('.selected').removeClass('selected');
$(this).addClass('selected');
}
else if($(this).hasClass('selected')) {
// Allows a bag to be toggled when clicked
$(this).removeClass('selected');
}
else {
// If there is no bag `selected` then make the clicked one selected
$(this).addClass('selected');
}
});
and also create some CSS for the selected class for users to know which one is clicked
.selected {
background-color: #FFFF00;
}
Then you can set the rules for whether or not something is dragable or not based on what is selected. This part is pseudocode
if($('.bag.one').hasClass('selected'))
{
// Allow things to be dragged to only bag one
}
if($('.bag.two').hasClass('selected'))
{
// Allow things to be dragged only to bag two
}
if($('.bag.three').hasClass('selected'))
{
// Allow things to be dragged only to bag three
}
Your code is too massive for us to implement the whole thing for you. This should give you the correct direction to go towards. Please comment if there is anything else I can help you with
-----GIGANTIC EDIT-----
(I shouldn't have worked this hard on correcting your situation but I feel bad for your position so I did)
After some massive changes to correcting the formatting of your code, optimizing it for reuse (and removing hundreds of lines of unneeded code in the process), moving the if statements I created earlier into a setInterval to check to update it with current information, and correcting much of your poor CSS, I came up with this rough update
Here is the code for that:
<!-- HTML -->
<div id="body">
<div class="bag one">
Bag 1
<img src="images/sb1.jpg" height="50" width="50" />
</div>
<div class="bag two">
Bag 2
<img src="images/sb2.jpg" height="50" width="50" />
</div>
<div class="bag three">
Bag 3
<img src="images/sb3.jpg" height="50" width="50" />
</div>
<div class="products" style="width: 120px; height: 100px; left: 23px; top: 120px;">
<ul>
<li> <a href="#" class="item one">
<img src="images/shirt2.gif" height="45" width="45"/>
<div>
<p>item1_1</p>
<p>Price:$25</p>
</div>
</a>
</li>
</ul>
</div>
<br>
<div class="products" style="width: 120px; height: 100px; left: 30px; top: 225px;">
<ul>
<li> <a href="#" class="item two">
<img src="images/shoes1.gif" height="45" width="45"/>
<div>
<p>item2_1</p>
<p>Price:$30</p>
</div>
</a>
</li>
</ul>
</div>
<div class="products" style="width: 120px; height: 144px; left: 34px; top: 342px;">
<ul>
<li> <a href="#" class="item three">
<img src="images/shirt2.gif" height="45" width="45"/>
<div>
<p>item3_1</p>
<p>Price:$25</p>
</div>
</a>
</li>
</ul>
</div>
<br>
<div class="cart" style="left: 200px; top: 150px; height: 300px; width: 237px">
<div class="ctitle">Shopping Cart</div>
<div style="background:#fff">
<table id="cartcontent1" fitColumns="true" style="width1:300px;height:auto;">
<thead>
<tr>
<th field="name" width=140>Name</th>
<th field="quantity" width=60 align="right">Quantity</th>
<th field="price" width=60 align="right">Price</th>
<th field="remove" width=60 align="right">Remove</th>
</tr>
</thead>
</table>
</div>
<p class="total">Total: $0</p>
<div class="ctitle" style="position:absolute;bottom:10px"></div>
</div>
</div>
<!-- CSS -->
.bag {
width:80px;
float:left;
text-align:center;
}
.products {
position:fixed;
height:100%;
background:#fafafa;
}
.products ul {
list-style:none;
margin:0;
padding:0px;
}
.products li {
display:inline;
float:left;
margin:10px;
}
.item {
display:block;
text-decoration:none;
}
.item img {
border:1px solid #333;
}
.item p {
margin:0;
font-weight:bold;
text-align:center;
color:#c3c3c3;
}
.cart {
position:absolute;
width:260px;
height:100%;
background:#ccc;
padding:0px 10px;
}
.ctitle {
text-align:center;
color:#555;
font-size:18px;
padding:10px;
}
.auto-style3 {
float: right;
position: relative;
width: 260px;
height: 100%;
background: #ccc;
padding: 0px 10px;
margin-bottom: 0px;
}
.selected {
background-color: #FFFF00;
}
<!-- Javascript/jQuery-->
var data = {
"total": 0,
"rows": []
};
var totalCost = 0;
$(document).ready(function () {
$('#cartcontent1').datagrid({
singleSelect: true
});
$('.item').draggable({
revert: true,
proxy: 'clone',
onStartDrag: function () {
$(this).draggable('options').cursor = 'not-allowed';
$(this).draggable('proxy').css('z-index', 10);
},
onStopDrag: function () {
$(this).draggable('options').cursor = 'move';
}
});
$('.bag').click(function () {
if ($('.selected').length > 0 && !$(this).hasClass('selected')) { // Checks to see if there is a selected and if the clicked one is selected
$('.selected').removeClass('selected');
$(this).addClass('selected');
} else if ($(this).hasClass('selected')) {
// Allows a bag to be toggled when clicked
$(this).removeClass('selected');
} else {
// If there is no bag `selected` then make the clicked one selected
$(this).addClass('selected');
}
});
});
var check = setInterval(function() {
if ($('.bag.one').hasClass('selected')) {
$('.bag.one').droppable({
accept: '.item.one,.item.two,.item.three',
onDragEnter: function (e, source) {
$(source).draggable('options').cursor = 'auto';
},
onDragLeave: function (e, source) {
$(source).draggable('options').cursor = 'not-allowed';
},
onDrop: function (e, source) {
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
addProduct(name, parseFloat(price.split('$')[1]));
}
});
} else if ($('.bag.two').hasClass('selected')) {
$('.bag.two').droppable({
accept: '.item.two,.item.three',
onDragEnter: function (e, source) {
$(source).draggable('options').cursor = 'auto';
},
onDragLeave: function (e, source) {
$(source).draggable('options').cursor = 'not-allowed';
},
onDrop: function (e, source) {
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
}
});
} else if ($('.bag.three').hasClass('selected')) {
// Allow things to be dragged only to bag three
$('.bag.three').droppable({
accept: '.item.three',
onDragEnter: function (e, source) {
$(source).draggable('options').cursor = 'auto';
},
onDragLeave: function (e, source) {
$(source).draggable('options').cursor = 'not-allowed';
},
onDrop: function (e, source) {
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
}
});
}
}, 100);
function addProduct(name, price) {
var totalQuantity = sumQuantity(data);
if (totalQuantity < 8) {
function add() {
for (var i = 0; i < data.total; i++) {
var row = data.rows[i];
if (row.name == name) {
row.quantity += 1;
return;
}
}
data.total += 1;
data.rows.push({
name: name,
quantity: 1,
price: price,
remove: 'X'
});
}
add();
totalCost += price;
$('#cartcontent1').datagrid('loadData', data);
$('div.cart .total').html('Total: $' + totalCost);
} else {
alert('cannot have more than 8 items');
}
}
function removeProduct(el, event) {
var tr = $(el).closest('tr');
var name = tr.find('td[field=name]').text();
var price = tr.find('td[field=price]').text();
var quantity = tr.find('td[field=quantity]').text();
for (var i = 0; i < data.total; i++) {
var row = data.rows[i];
if (row.name == name) {
data.rows.splice(i, 1);
data.total--;
break;
}
}
totalCost -= price * quantity;
$('#cartcontent1').datagrid('loadData', data);
$('div.cart .total').html('Total: $' + totalCost);
}
function sumQuantity(data) {
var sum = 0;
for (var i = 0; i < data.total; i++) {
sum += data.rows[i].quantity;
}
return sum;
}
It still needs to be fixed in that you must disable the others using something like $(this).droppable("option", "disabled", true); and re-enable it when it is selected, and also deal with bags two and three, but this gives you a lot more to work with
Quick question: Are you going to have multiple carts for the other bags? I'm not quite sure why you have three bags...
Take Aways for you... (hopefully):
LEARN HOW TO CODE ONLINE. This will make problem solving, optimizing, and simply doing everything much better. Use tutorial websites like CodeAcademy to learn more. You NEED a basis in web coding to code on the web
Try to reuse code where you can. If you're going to have more than one element of the same type that all have very very similar characteristics, try to use a class as opposed to hard coding each one - that's the purpose of a class
Try it yourself before asking others. When you asked the question you provided zero evidence that you had tried to do it yourself. You should work on a problem for days before asking a question here unless you're 100% sure you're not going to get it
Keep your code clean. Use spacing correctly and make sure all your () and {} line up. You did well at naming your variables recognizable things so that's good
Check your code for errors. When looking through it I found several missing </div>s, misspellings, a missing </li> and other errors that can be fixed easily. That's just carelessness
Style your elements using the CSS panel in jsFiddle or in <style> tags on web pages. This makes it a lot easier to see exactly what's affecting what. In-line styling should be avoided at all costs
Learn to utilize your browser's element inspector and console log. It makes some problems very easy to fix and helps you see exactly what styles elements have while running among many other things.
This post has gone way too long now, but I hope that I've helped. Really, you do need to get a stronger basis in your javascript, HTML, CSS, and jQuery knowledge before continuing work. That should be your top priority right now.
In closing (since this feels like a letter):
"If debugging is the process of removing bugs, then programming
must be the process of putting them in." - Edsger Dijkstra
You must have been programming a lot ^^
-----FINAL EDIT-----
I really have worked too hard on this. You owe me something.
Anywho, I restructured the entire thing again to get it fully functional. I had to create a type of mini-version to make sure my concepts were correct. It turns out I simply had a couple of extra data-scopes in my HTML...
The only thing I don't have working is the remove button (the X in the table). I have no earthly idea why that's stopped working, I triple checked all the code for it is the same as before.
Updated code:
/* HTML */
<div id="body">
<div class="bag one" data-scope="one, two, three">Bag 1
<img src="images/sb1.jpg" height="50" width="50" />
</div>
<div class="bag two" data-scope="two, three">Bag 2
<img src="images/sb2.jpg" height="50" width="50" />
</div>
<div class="bag three" data-scope="three">Bag 3
<img src="images/sb3.jpg" height="50" width="50" />
</div>
<div class="products" style="width: 120px; height: 100px; left: 23px; top: 120px;">
<ul>
<li> <a href="#" class="item one" data-scope="one">
<img src="images/shirt2.gif" height="45" width="45"/>
<div>
<p>item1_1</p>
<p>Price:$25</p>
</div>
</a>
</li>
</ul>
</div>
<br>
<div class="products" style="width: 120px; height: 100px; left: 30px; top: 225px;">
<ul>
<li> <a href="#" class="item two" data-scope="two">
<img src="images/shoes1.gif" height="45" width="45"/>
<div>
<p>item2_1</p>
<p>Price:$30</p>
</div>
</a>
</li>
</ul>
</div>
<div class="products" style="width: 120px; height: 144px; left: 34px; top: 342px;">
<ul>
<li> <a href="#" class="item three" data-scope="three">
<img src="images/shirt2.gif" height="45" width="45"/>
<div>
<p>item3_1</p>
<p>Price:$25</p>
</div>
</a>
</li>
</ul>
</div>
<br>
<div class="cart" style="left: 200px; top: 150px; height: 300px; width: 237px">
<div class="ctitle">Shopping Cart</div>
<div style="background:#fff">
<table id="cartcontent1" fitColumns="true" style="width1:300px;height:auto;">
<thead>
<tr>
<th field="name" width=140>Name</th>
<th field="quantity" width=60 align="right">Quantity</th>
<th field="price" width=60 align="right">Price</th>
<th field="remove" width=60 align="right">Remove</th>
</tr>
</thead>
</table>
</div>
<p class="total">Total: $0</p>
<div class="ctitle" style="position:absolute;bottom:10px"></div>
</div>
</div>
/* CSS */
.bag {
width:80px;
float:left;
text-align:center;
}
.products {
position:fixed;
height:100%;
background:#fafafa;
}
.products ul {
list-style:none;
margin:0;
padding:0px;
}
.products li {
display:inline;
float:left;
margin:10px;
}
.item {
display:block;
text-decoration:none;
}
.item img {
border:1px solid #333;
}
.item p {
margin:0;
font-weight:bold;
text-align:center;
color:#c3c3c3;
}
.cart {
position:absolute;
width:260px;
height:100%;
background:#ccc;
padding:0px 10px;
}
.ctitle {
text-align:center;
color:#555;
font-size:18px;
padding:10px;
}
.auto-style3 {
float: right;
position: relative;
width: 260px;
height: 100%;
background: #ccc;
padding: 0px 10px;
margin-bottom: 0px;
}
.selected {
background-color: #FFFF00;
}
/* javascript/jQuery */
$(document).ready(function () {
var data = {
"total": 0,
"rows": []
};
var totalCost = 0;
$('#cartcontent1').datagrid({
singleSelect: true
});
$('.item').each(function (index, div) {
var scope = $(this).attr('data-scope');
$(div).draggable({
revert: true,
proxy: 'clone',
onStartDrag: function () {
$('.bag:not(.bag[data-scope*=' + scope + '])').droppable('disable');
if($('.selected').length > 0)
$(':not(.selected)').droppable('disable');
$(this).draggable('options').cursor = 'not-allowed';
$(this).draggable('proxy').css('z-index', 10);
},
onStopDrag: function () {
$('.bag').droppable('enable');
$(this).draggable('options').cursor = 'move';
}
});
});
$('.bag').click(function () {
if ($('.selected').length > 0 && !$(this).hasClass('selected')) {
$('.selected').removeClass('selected');
$(this).addClass('selected');
} else if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
$(this).addClass('selected');
}
});
$('.bag').droppable({
onDrop: function (e, source) {
var name = $(source).find('p:eq(0)').html();
var price = $(source).find('p:eq(1)').html();
addProduct(name, parseFloat(price.split('$')[1]));
$(source.draggable).remove();
$('.bag').droppable('enable');
}
});
function addProduct(name, price) {
var totalQuantity = sumQuantity(data);
if (totalQuantity < 8) {
function add() {
for (var i = 0; i < data.total; i++) {
var row = data.rows[i];
if (row.name == name) {
row.quantity += 1;
return;
}
}
data.total += 1;
data.rows.push({
name: name,
quantity: 1,
price: price,
remove: 'X'
});
}
add();
totalCost += price;
$('#cartcontent1').datagrid('loadData', data);
$('div.cart .total').html('Total: $' + totalCost);
} else {
alert('cannot have more than 8 items');
}
}
function removeProduct(el, event) {
var tr = $(el).closest('tr');
var name = tr.find('td[field=name]').text();
var price = tr.find('td[field=price]').text();
var quantity = tr.find('td[field=quantity]').text();
for (var i = 0; i < data.total; i++) {
var row = data.rows[i];
if (row.name == name) {
data.rows.splice(i, 1);
data.total--;
break;
}
}
totalCost -= price * quantity;
$('#cartcontent1').datagrid('loadData', data);
$('div.cart .total').html('Total: $' + totalCost);
}
function sumQuantity(data) {
var sum = 0;
for (var i = 0; i < data.total; i++) {
sum += data.rows[i].quantity;
}
return sum;
}
});
This is all I'm going to do for you, it's far more than you deserve especially since you provided 0 help since posting the question. Don't expect this much from anyone ever.
Here is the last Fiddle I'm touching. Have a good day

Categories