Translating jQuery to Vanilla JS issue - javascript

I was watching a tutorial that used jQuery and wanted to turn it into JS, but my code is broken - was hoping someone could help me with this:
Tutorial JS:
$(function() {
var btn = $('button');
var progressBar = $('.progressbar');
btn.click(function() {
progressBar.find('li.active').next().addClass('active');
})
})
Taken from URL:http://www.kodhus.com/kodity/codify/kod/mGXAtb
Here is my failed attempt at rewriting the jQuery using JavaScript DOM:
var btn1 = document.getElementsByTagName('BUTTON');
var progBar = document.getElementsByClassName('progressbar');
function clickMe1() {
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
return emlClass.nextElementSibling.addClass('active');
}
btn1.addEventListener("click", clickMe1, false);
where did I go wrong?

Working fiddle.
Your code will work after several changes check the notes below :
You've missed addClass() there it's a jQuery function, for vanilla JS use .classList.add() instead:
return emlClass.nextElementSibling.classList.add("active");
querySelectorAll(); will return a list of nodes you have to loop through them and add class, use :
var emlClass = progBar.querySelectorAll("li.active");
Instead of :
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
Then loop and add active class:
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
getElementsByTagName() and getElementsByClassName() will also returns a list of nodes with given name, you have to specify which one you want to pick (selecting the first in my example) :
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
Hope this helps.
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
function clickMe1() {
var emlClass = progBar.querySelectorAll("li.active");
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
}
btn1.addEventListener("click", clickMe1, false);
.container {
width: 100%;
}
.progressbar {
counter-reset: step;
margin: 0;
margin-top: 50px;
padding: 0;
}
.progressbar li {
list-style-type: none;
float: left;
width: 33.33%;
position: relative;
text-align: center;
}
.progressbar li:before {
content: counter(step);
counter-increment: step;
width: 30px;
height: 30px;
line-height: 30px;
border: 2px solid #ddd;
display: block;
text-align: center;
margin: 0 auto 10px auto;
border-radius: 50%;
background-color: white;
}
.progressbar li:after {
content: '';
position: absolute;
width: 100%;
height: 2px;
background-color: #ddd;
top: 15px;
left: -50%;
z-index: -1;
}
.progressbar li:first-child:after {
content: none;
}
.progressbar li.active {
color: green;
}
.progressbar li.active:before {
border-color: green;
}
.progressbar li.active + li:after {
background-color: green;
}
button {
position: relative;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 2px;
left: 50%;
margin-top: 30px;
transform: translate(-50%);
cursor: pointer;
outline: none;
}
button:hover {
opacity: 0.8;
}
<div class="container">
<ul class="progressbar">
<li class="active">Step 1</li>
<li>Step 2</li>
<li>Step 3</li>
</ul>
</div>
<button>Next step</button>

.querySelectorAll("li") will return an array (or an array-like object) with one or more <li> tags. So you need to either:
loop through every <li> in that list and do the rest,
or just take the first item from that list if you don't want to worry about there being more than one li in the page,
or use .querySelector (not .querySelectorAll) to just take the first <li> for you.
MDN

Related

JavaScript If and else statement w/function calls not producing expected result

I have a mobile menu that includes four list items. When you click on the "Features" list item, another unordered list is supposed to populate below it, and when you click it again, it's supposed to close it.
Here's my issue:
Inside the addEventListener function, I am calling two other functions (displayType and displayTypeCheck) inside the if, and else statement. When I do this and click on the "Features" list item, it opens but does not close when I click it again.
If I don't use the displayType and displayTypeCheck functions in the if and else statement and click on the "Features" list item, the UL will both open and close.
Why does the if and else statement that calls the other two functions not work, and how do I get it to work?
In the provided Javascript code below, the if and else statement that's commented out works, and the block that's not commented out is the code that doesn't entirely work.
const menuIcon = document.querySelector(".mobile-menu-icon");
const mobileMenu = document.querySelector(".mobile-menu");
const closeMenuIcon = document.querySelector(".close-menu-icon");
const featuresMobile = document.querySelector(".features-mobile");
const featuresMobileDropdown = document.querySelector(".features-mobile-dropdown");
const overlay = document.querySelector(".overlay");
function displayType(element, displayValue) {
element.style.display = displayValue;
}
function displayTypeCheck(element, displayValue) {
element.style.display === displayValue;
}
menuIcon.addEventListener("click", function () {
displayType(mobileMenu, 'block');
displayType(overlay, 'block');
});
closeMenuIcon.addEventListener("click", function () {
displayType(mobileMenu, 'none');
displayType(overlay, 'none');
});
featuresMobile.addEventListener("click", function () {
// if (featuresMobileDropdown.style.display === "block") {
// featuresMobileDropdown.style.display = "none";
// } else {
// featuresMobileDropdown.style.display = "block";
// }
if (displayTypeCheck(featuresMobileDropdown, "block")) {
displayType(featuresMobileDropdown, "none");
} else {
displayType(featuresMobileDropdown, "block");
}
});
#import url("https://fonts.googleapis.com/css2?family=Epilogue:wght#500;700&display=swap");
:root {
--almostWhite: hsl(0, 0%, 98%);
--mediumGray: hsl(0, 0%, 41%);
--almostBlack: hsl(0, 0%, 8%);
--navDropDownColor: #e9ecef;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
body {
min-height: 100vh;
font-family: "Epilogue", sans-serif;
background-color: var(--almostWhite);
}
header {
padding: .9375rem 2.5rem .9375rem 2.5rem;
max-width: 100rem;
margin: auto;
}
header nav {
display: flex;
align-items: center;
justify-content: flex-end;
}
header nav ul li {
cursor: pointer;
}
.register {
border: .125rem solid var(--mediumGray);
padding: .625rem .9375rem;
border-radius: .8125rem;
}
.mobile-menu-icon {
height: 3.125rem;
}
.mobile-menu-icon {
display: block;
cursor: pointer;
}
.mobile-menu .mobile-nav-links {
margin-top: 4.375em;
padding-left: .9375em;
color: var(--mediumGray);
}
.mobile-menu ul li {
padding: .625em;
}
.mobile-menu .mobile-nav-links li ul {
margin-left: .625em;
margin-top: .625em;
display: none;
}
.mobile-menu {
background-color: white;
width: 18.75em;
height: 100vh;
position: absolute;
top: 0;
right: 0;
z-index: 2;
display: none;
}
.close-menu-icon {
margin-left: auto;
margin-right: 1.25em;
margin-top: 1.25em;
display: block;
cursor: pointer;
height: 3.125em;
}
.login-register-mobile-container {
color: var(--mediumGray);
width: 90%;
margin: 3.125em auto;
}
.login-register-mobile-container span {
display: block;
text-align: center;
cursor: pointer;
}
.login-register-mobile-container span:first-child {
margin-bottom: 1.25em;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(.1875rem);
z-index: 1;
display: none;
}
<header>
<nav>
<img class="mobile-menu-icon" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Hamburger_icon.svg/2048px-Hamburger_icon.svg.png" alt="" />
<div class="mobile-menu">
<img
class="close-menu-icon"
src="https://cdn4.iconfinder.com/data/icons/user-interface-131/32/close-512.png"
alt=""
/>
<ul class="mobile-nav-links">
<li class="features-mobile">Features
<ul class="features-mobile-dropdown">
<li>Todo List</li>
<li>Calenders</li>
<li>Reminders</li>
<li>Planning</li>
</ul>
</li>
<li class="company-mobile">Company</li>
<li>Careers</li>
<li>About</li>
</ul>
<div class="login-register-mobile-container">
<span class="login">Login</span>
<span class="register">Register</span>
</div>
</div>
</nav>
<div class="overlay"></div>
</header>
You forgot the return statement.
function displayTypeCheck(element, displayValue) {
return element.style.display === displayValue;
}
Otherwise the function will always return undefined which is a falsey value.
Within the displayTypeCheck function, you aren't returning the boolean result of the conditions.
Without the return statement, it is returning void
function displayTypeCheck(element, displayValue) {
return element.style.display === displayValue;
}

Changing background color doesn't work well

I am trying to change the background color of my webpage using a hamburger menu. There are 4 color options on my hamburger menu. I managed to get a change on the background when clicking on the color of my choice. But that change only happens once. When I clicked another color and come back to click that same color from earlier on, it doesn't respond. The color seems to change only once, and not more than that.
The repository to my GitHub code is here: https://github.com/tand100b/Winc_Academy
const changeColorButton1 = document.getElementById("color1");
changeColorButton1.addEventListener("click", function() {
changeClassRedBackground();
});
const changeColorButton2 = document.getElementById("color2");
changeColorButton2.addEventListener("click", function() {
changeClassOrangeBackground();
});
const changeColorButton3 = document.getElementById("color3");
changeColorButton3.addEventListener("click", function() {
changeClassPurpleBackground();
});
const changeColorButton4 = document.getElementById("color4");
changeColorButton4.addEventListener("click", function() {
changeClassGreenBackground();
});
const changeClassRedBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("red-background");
}
const changeClassOrangeBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("orange-background");
};
const changeClassPurpleBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("purple-background");
};
const changeClassGreenBackground = function() {
const bodyElement = document.body;
bodyElement.classList.add("green-background");
};
body {
background-color: pink;
}
.red-background {
background-color: red;
}
.orange-background {
background-color: orange;
}
.purple-background {
background-color: purple;
}
.green-background {
background-color: green;
}
.btn-toggle-nav {
width: 60px;
height: 20%;
background-color: #f98f39;
background-image: url("https://i.stack.imgur.com/tniUv.png");
background-repeat: no-repeat;
background-size: 60%;
background-position: center;
cursor: pointer;
}
.btn-toggle-nav:hover {
opacity: 0.5;
}
.navbar ul {
padding-top: 15px;
/* visibility: hidden; */
}
.navbar ul li {
line-height: 60px;
list-style: none;
background-color: white;
width: 300px;
padding-top: 0px;
padding-top: 0px;
}
.navbar ul li a {
display: block;
height: 60px;
padding: 0 10px;
text-decoration: none;
font-family: arial;
font-size: 16px;
}
.navbar {
background-color: red;
width: 50px;
padding: 0 5px;
height: calc(100vh-60px);
z-index: 1000;
}
.list {
margin-top: 0px;
}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<div class="btn-toggle-nav"></div>
<aside class="navbar">
<ul class="list">
<li><a id="color1" href="#">Red</a></li>
<li><a id="color2" href="#">Orange</a></li>
<li><a id="color3" href="#">Purple</a></li>
<li><a id="color4" href="#">Green</a></li>
</ul>
</aside>
Can someone please look at my code and suggest what I can do?
Firstly, I suggest declaring variable bodyElement only once at the top of the file because each time it would be the same body element:
const bodyElement = document.body
Next, we create function that will check if body has any style classes in its classList. If it's not empty (length more than one) we remove all classes, and do nothing otherwise:
const isBodyHasStyle = () => bodyElement.classList.length ? bodyElement.classList = '' : null
Then, on each button click we going to call our new function:
changeColorButton1.addEventListener("click", function() {
isBodyHasStyle()
changeClassRedBackground();
});
Do the same with other buttons.
You need to make sure that you don't have multiple classes conflicting with each other, also try to DRY your code, here is an alternative I came up with:
const changeColor = (e) => {
const bodyElement = document.querySelector('body');
const colorIdMap = {
"color1": "red-background",
"color2": "orange-background",
"color3": "purple-background",
"color4": "green-background"
}
bodyElement.className = colorIdMap[e.target.id];
}
const btns = document.querySelectorAll('.list li');
btns.forEach(btn => btn.addEventListener('click', changeColor))
An easier way to accomplish this is by setting a data attribute on the background, based on the selected color. Just add a color data value to each of the menu items and set the body background to that color.
const toggleMenu = (event) => {
event.target.closest('.navbar').classList.toggle('open');
};
const changeColor = (event) => {
document.body.dataset.background = event.target.dataset.color;
toggleMenu(event); /* do not call ~ to stay open */
};
document.querySelector('.btn-toggle-nav')
.addEventListener('click', toggleMenu)
document.querySelectorAll('.color-picker')
.forEach(e => e.addEventListener('click', changeColor));
/* CSS reset */
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
body { display: flex; background-color: #222; }
ul { list-style-type: none; margin: 0; }
body[data-background="red"] { background-color: red }
body[data-background="orange"] { background-color: orange }
body[data-background="purple"] { background-color: purple }
body[data-background="green"] { background-color: green }
body[data-background="default"] { /* Do not set the background-color */ }
a[data-color="red"] { color: red; }
a[data-color="orange"] { color: orange; }
a[data-color="purple"] { color: purple; }
a[data-color="green"] { color: green; }
a[data-color="default"] { color: #222; }
.list {
position: absolute;
display: none; /* hide menu (default) */
flex-direction: column;
gap: 0.5em;
padding: 0.5em;
width: 6em;
left: 2em;
background: #444;
}
.list li a { text-decoration: none; font-weight: bold; }
.list li a:hover { text-decoration: underline; }
.navbar {
position: relative;
width: 2em;
background-color: #444;
}
.navbar.open .list {
display: flex; /* show menu */
}
.btn-toggle-nav {
width: 2em;
height: 2em;
background-image: url("https://i.stack.imgur.com/tniUv.png");
background-repeat: no-repeat;
background-size: 60%;
background-position: center;
cursor: pointer;
}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<aside class="navbar">
<div class="btn-toggle-nav"></div>
<ul class="list">
<li><a class="color-picker" href="#" data-color="red">Red</a></li>
<li><a class="color-picker" href="#" data-color="orange">Orange</a></li>
<li><a class="color-picker" href="#" data-color="purple">Purple</a></li>
<li><a class="color-picker" href="#" data-color="green">Green</a></li>
<li><a class="color-picker" href="#" data-color="default">Default</a></li>
</ul>
</aside>

How do I use drag and drop with dynamically created HTML? (SortableJS)

I'm starting to learn javascript and I have a simple todo application where I want to be able to drag and drop the different todo's created. A simple way to do this was with SortableJS library, but it doesn't work the way i want to. After implementing the simple sortable function, when dragging on a todo, it grabs the whole todo-list instead of a single todo
I think the issue is because I dynamically create the html, but I'm kinda stuck and would appreciate any suggestions.
//Selectors
const todoInput = document.querySelector(".todos-input"); //input for adding a todo
const todoButton = document.querySelector(".todos-button"); //add todo-button
const todoList = document.querySelector(".todos-list"); //the todo-list
//Event listeners
todoButton.addEventListener("click", addTodo);
todoList.addEventListener("click", deleteTodo);
todoList.addEventListener("click", completeTodo);
//Functions
function addTodo(event) {
//prevent form from submitting
event.preventDefault();
//create a div for the todos-list
const todoDiv = document.createElement("div");
//add classlist for styling
todoDiv.classList.add("todo");
//Create LI
const newTodo = document.createElement("li");
//output the value from the add-todo field
if (todoInput.value != "") {
newTodo.innerText = todoInput.value;
} else {
return false;
}
//classlist for styling
newTodo.classList.add("todo-item");
//append child to div
todoDiv.appendChild(newTodo);
//complete button
const completedButton = document.createElement("button");
completedButton.innerHTML = '<i class="fas fa-check"><i/>';
completedButton.classList.add("completed-btn");
todoDiv.appendChild(completedButton);
//delete button
const deletedButton = document.createElement("button");
deletedButton.innerHTML = '<i class="fas fa-trash"><i/>';
deletedButton.classList.add("deleted-btn");
todoDiv.appendChild(deletedButton);
//drag button
const dragButton = document.createElement("button");
dragButton.innerHTML = '<i class="icon fa fa-bars"><i/>';
dragButton.classList.add("drag-btn");
dragButton.classList.add("handle");
todoDiv.appendChild(dragButton);
//append div to list of todos
todoList.appendChild(todoDiv);
//clear input field after adding a new todo
todoInput.value = "";
//DRAG AND DROP
const dragArea = document.querySelector('.todos-section');
new Sortable(dragArea, {
animation: 300
});
}
//deleting todo
function deleteTodo(e) {
//grab the item, whatever we are clicking on
const item = e.target;
//delete todo
if (item.classList[0] === "deleted-btn") {
//grab the parent element of the item, which is the todolist element in this case
const todo = item.parentElement;
//remove the todo
todo.remove();
}
}
//completing todo
function completeTodo(e) {
//grab the item, whatever we are clicking on
const item = e.target;
//complete todo
if (item.classList[0] === "completed-btn") {
const todo = item.parentElement;
//use the toggle because if the element has a class, then the classList.toggle method
//behaves like classList.remove and the class is removed from the element.
//And if the element does not have the specified class
//then classList.toggle, just like classList.add, adds this class to the element.
//So it basically does the add/remove operation for us depending on the state.
todo.classList.toggle("completed-todo");
}
}
/*Apply to all elements*/
* {
box-sizing: border-box;
list-style-type: none;
margin: 0;
padding: 0;
}
body {
font-family: "Merriweather Sans", sans-serif;
background: rgba(216, 206, 206, 0.787);
}
.wrapper {
display: flex;
position: relative;
}
/* Add todos-section */
.todos-bar {
position: fixed;
top: 5%;
left: 50%;
font-size: 17px;
border: 0;
transform: translate(-50%, -50%);
padding-left: 100px;
}
.todos-bar input {
width: 600px;
height: 50px;
border: 0px;
outline: none;
font-size: 20px;
padding-left: 20px;
border-radius: 5px;
}
.todos-bar button {
position: fixed;
background: rgba(20, 33, 93, 0.952);
color: white;
font-size: 20px;
border: 0;
outline: none;
height: 50px;
padding: 10px 20px;
right: 0px;
border-radius: 0px 5px 5px 0px;
cursor: pointer;
}
.todos-bar button:hover {
background: rgb(43, 54, 73);
}
/* Todos section */
.todos-section {
display: flex;
position: fixed;
top: 15%;
left: 37%;
}
.todos-list {
width: 600px;
}
.todo {
margin: 1.5rem;
background: white;
color: black;
font-size: 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 5px;
padding-left: 0.5rem;
margin: 15px;
transition: all 0.5s ease;
}
.todo li {
flex: 1;
}
.todo-item {
padding: 0rem 0.5rem;
padding-left: 2.5rem;
}
.deleted-btn,
.completed-btn {
background: rgb(248, 56, 56);
color: white;
border: none;
padding: 1rem;
cursor: pointer;
font-size: 1rem;
}
.completed-btn {
background: green;
}
.deleted-btn {
border-radius: 0px 5px 5px 0px;
}
.drag-btn {
display: block;
position: absolute;
background: white;
border: 2px solid white;
}
.fa-bars {
padding: 5px;
margin: 2px;
cursor: pointer;
}
.fa-trash,
.fa-check {
pointer-events: none;
}
.completed-todo {
text-decoration: line-through;
opacity: 0.5;
}
<head>
<link rel="stylesheet" href="style.css">
<script src="https://kit.fontawesome.com/47440aba67.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
</head>
<body>
<div class="wrapper">
<!--ADD TODO-->
<div class="todos-bar">
<input type="text" class="todos-input" placeholder="Add to list...">
<button class="todos-button" type="submit"><i class="fas fa-plus"></i></button>
</div>
<!--TODO LIST-->
<div class="todos-section">
<ul class="todos-list"></ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
According to the documentation,
You can use any element for the list and its elements, not just ul/li
What you've implemented actually fits in this description since there is a ul with div tags inside. However, you are not referencing the right element in the dragArea, because it should be the direct parent (.todos-list) of your desired draggable children.
So, change it to .todos-list and in addition pass handle property to Sortable constructor to reference the icon in which you want to drag.
const dragArea = document.querySelector('.todos-list');
new Sortable(dragArea, {
animation: 300,
handle: '.fa-bars'
})
Working example

Make dots active on Slider

I have this Slider example created with pure JS.
The slider is working great. The only thing left to do would be to activate the three dots so when the 1st slide opens, 1st dot activates, showing different color than the other dots, and so on. Also, you should be able to open the correct slide when clicking dots, so 1st dot opens 1st slide, 2nd dot 2nd slide, and so on.
Could you help me to achieve this? You can find the source code below.
const nextBtn = document.querySelector('.nextBtn');
const prevBtn = document.querySelector('.prevBtn');
const container = document.querySelector('.images');
const offers = document.getElementById('offers');
const link = document.getElementById('links');
let colors = ['#7f86ff', '#2932d1', '#00067f'];
let currentSlide = 0;
let texts = ['Change1', 'Change2', 'Change3'];
let currentText = 0;
let links = ['Link1', 'Link2', 'Link3'];
let currentLink = 0;
function updateSlide(direction) {
currentSlide =
(colors.length + currentSlide + direction)
% colors.length;
container.style.backgroundColor = colors[currentSlide];
container.animate([{opacity:'0.1'}, {opacity:'1.0'}],
{duration: 200, fill:'forwards'})
}
function updateText(direction) {
currentText =
(texts.length + currentText + direction)
% texts.length;
offers.innerHTML = texts[currentText];
offers.animate([{transform:'translateY(-50px)', opacity:'0.0'}, {transform:'translateY(0)', opacity:'1.0'}],
{duration: 200, fill:'forwards'})
}
function updateLink(direction) {
currentLink =
(links.length + currentLink + direction)
% links.length;
link.innerHTML = links[currentLink];
link.animate([{transform:'scale(0,0)'}, {transform:'scale(1.1)'}],
{duration: 200, fill:'forwards'})
}
updateSlide(0);
updateText(0);
updateLink(0);
nextBtn.addEventListener('click', nextSlide);
prevBtn.addEventListener('click', prevSlide);
function nextSlide() {
updateSlide(+1);
updateText(+1);
updateLink(+1);
clearInterval(myInterval);
}
function prevSlide() {
updateSlide(-1);
updateText(-1);
updateLink(-1);
clearInterval();
clearInterval(myInterval);
}
var myInterval = window.setInterval(function(){
updateSlide(+1),updateText(+1),updateLink(+1); },
8000);
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: lightblue;
}
.images {
background-color: #4047c9;
flex: 0 0 80%;
min-height: 70vh;
border-radius: 10px;
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
color: white;
}
#links {
text-decoration: none;
color: white;
border: solid 2px white;
border-radius: 3px;
padding: 5px 10px;
}
#links:hover {
background-color: #000238;
}
a {
color: white;
text-decoration: none;
}
.dots {
display: flex;
margin-top: 120px;
margin-bottom: 50px;
}
#dot1, #dot2, #dot3 {
width: 20px;
height: 20px;
background-color: rgb(147, 151, 249);
border-radius: 50%;
margin: 0px 5px;
cursor: pointer;
}
#dot1:active, #dot2:active, #dot3:active {
background-color: #fff;
}
.btn {
display: inline-block;
background: white;
color: black;
padding: 10px;
border: none;
cursor: pointer;
}
.prevBtn {
position: absolute;
top: 50%;
left: 0;
transform: translate(-50%, -50%);
}
.nextBtn {
position: absolute;
top: 50%;
right: 0;
transform: translate(50%, -50%);
}
.btn:active {
background-color: grey;
color: white;
}
.btn:hover {
background-color: grey;
color: white;
}
<body>
<div class="images">
<button type="button" class="btn prevBtn">Prev Btn</button>
<button type="button" class="btn nextBtn">Next Btn</button>
<h1 id="offers">Changing text</h1>
Links
<div class="dots">
<span id="dot1"></span>
<span id="dot2"></span>
<span id="dot3"></span>
</div>
</div>
</body>
First off, according to
https://developer.mozilla.org/en-US/docs/Web/CSS/:active
The :active CSS pseudo-class represents an element (such as a button) that is being activated by the user.
So if you want your dots to be active, you’ll have to write a different way of giving them an active state since they are currently <span> tags, I would recommend giving them a class of .active, and adding in Javascript code to add that class on to them, or adding in that style programmatically within the Javascript function.
Based on your other request though, you will most likely also have to make the dots an <a> tag or something along those lines so you can add functionality on to them to let clicking on the dots bring you to any slide. Something probably along the lines of:
function dot1Click() {
updateSlide(1);
updateText(1);
updateLink(1);
dot1.style.backgroundColor = #fff;
}
Then you should have something along the lines of what you want. I'll return to this question when I have more time to iron out a code snippet, but I wanted to give you something to help you get started!

for/if loop to run a function multiple times depending on input :: jquery

I am writing a slider from scratch, no plugins.
I have my slider working, based on adding the slides together and plus or minus the length of the slider window.
It has become complicated when pagination needs to be added. I can't seem to wrap my head around the logic of the function needed to be written that states.
if button 1 is clicked run the function 1 time and go to slide one.
if button 2 is clicked run the function 2 times and go to slide two. .... and so on..
The issue I see coming from this is if on slide 3 and the button 4 is clicked the function only needs to move once not 4 times!! This is where my head breaks and all logic spills out of my ears.
How do I go about writing something like this?
here is the jsfiddle I have so far. http://jsfiddle.net/r5DY8/2/
Any help would be appreciated.
:: all the code on one page if you don't want to use jsfiddle ::
<!DOCTYPE html>
<html>
<head>
<script src='http://code.jquery.com/jquery-1.9.0.min.js'type="text/javascript"></script>
<link href='http://fonts.googleapis.com/css?family=Marmelad' rel='stylesheet' type='text/css'>
<style type="text/css">
body {
font-family: 'Marmelad', sans-serif;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select:none;
user-select:none;
}
#slideContainer {
position: relative;
width: 990px;
height: 275px;
float: left;
overflow: hidden;
margin-top:5%;
margin-left:15%;
}
#slideWrap {
width: 3960px;
height: 275px;
position: absolute;
top: 0;
left: 0;
}
.slide {
width: 990px;
height: 275px;
float: left;
}
.slide:first-child { background-color: #009999; }
.slide:nth-child(2) { background-color: #CC0033; }
.slide:nth-child(3) { background-color: #FFFF66; }
.slide:nth-child(4) { background-color: #006699; }
#clickLeft{
color: black;
float: left;
margin: 12% 0% 0 15%;
/*background: url("prev.png") no-repeat;*/
width: 60px;
height: 60px;
cursor: pointer;
list-style: none;
position: absolute;
z-index: 9;
border:1px solid black;/**/
}
#clickRight{
color: black;
float: right;
margin: 12% 0 0 79.5%;
/*background: url("next.png") no-repeat;*/
width: 60px;
height: 60px;
cursor: pointer;
list-style: none;
position: absolute;
border:1px solid black;/**/
}
.dots{
width: 9%;
position: absolute;
top: 310px;
text-align: center;
height: 45px;
padding-top: 5px;
background: white;
left: 43.5%;
border-radius: 8px;
list-style:none;
}
.dots li {
display: inline-block;
list-style:none;
}
.dots li:first-child {
margin-left:-40px;
}
.dots li a{
width: 16px;
height: 16px;
display: block;
background: #ededed;
cursor: pointer;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
-o-border-radius: 20px;
border-radius: 20px;
margin: 5px;
}
.dots li a:hover { background: rgba(0, 0, 0, 0.7); }
.styleDots { background: #a4acb2; }
.active { background: #a4acb2;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
-o-border-radius: 20px;
border-radius: 20px;}
li.pagerItem{
}
</style>
<script type="text/javascript">
$(function(){
var currentSlidePosition = 0;
var slideW = 990;
var allSlides = $('.slide');
var numberOfSlides = allSlides.length;
var marker;
$('.slide').each(function(i) {
listNumber=i+1;
marker = $("<li>");
marker.addClass('pagerItem '+listNumber);
$("<a href='#' ></a>").appendTo(marker);
if (i===0){
marker.addClass('active');
}
marker.appendTo($(".dots"));
});
allSlides.wrapAll('<div id="moveSlide"></div>').css({'float' : 'left','width' : slideW});
$('#moveSlide').css('width', slideW * numberOfSlides);
$('body').prepend('<li class="controls" id="clickLeft"></li>')
.append('<li class="controls" id="clickRight"></li>');
$('.controls').click(function(){
moveSlide(this);
moveSlide(this); // running twice because the function is being called twice
//create a function that says if button 1 is clicked run the function 1 time if button 3 is clicked run the function 3 times..
});
var moveSlide = function(thisobject){
console.log('function run');
if(($(thisobject).attr('id')=='clickRight')) {
if(currentSlidePosition == numberOfSlides-1)currentSlidePosition=0;
else currentSlidePosition++;
var active = $(".active").removeClass('active');
if(active.next() && active.next().length){
active.next().addClass('active');
} else {
active.siblings(":first").addClass('active');
}
} else if($(thisobject).attr('id')=='clickLeft'){
if(currentSlidePosition == 0)currentSlidePosition=numberOfSlides-1;
else currentSlidePosition--;
var active = $(".active").removeClass('active');
if(active.prev() && active.prev().length){
active.prev().addClass('active');
} else {
active.siblings(":last").addClass('active');
}
}
$('#moveSlide').animate({'margin-left' : slideW*(-currentSlidePosition)});
}
});
</script>
</head>
<body>
<div id="slideContainer">
<div id="slideWrap">
<div class="slide">1</div>
<div class="slide">2</div>
<div class="slide">3</div>
<div class="slide">4</div>
</div>
</div>
<ul class="dots"></ul>
</body>
</html>
It's more complicated than just calling the function a number of times. As the animation is asynchronous, you need to call the function again when the animation has finished, not right away.
Add a callback parameter to the function so that it can use that do do something when the animation finishes:
var moveSlide = function (thisobject, callback) {
Add the callback to the animation:
$('#moveSlide').animate({
'margin-left': slideW * (-currentSlidePosition)
}, callback);
Make a function moveTo that will call moveSlide in the right direction, and use itself as callback:
function moveTo(target){
if (target < currentSlidePosition) {
moveSlide($('#clickLeft'), function(){ moveTo(target); });
} else if (target > currentSlidePosition) {
moveSlide($('#clickRight'), function(){ moveTo(target); });
}
}
Bind the click event to the links in the dots. Use the index method to find out which slide you want to go to, and call moveTo to do it:
$('.dots a').click(function(e){
e.preventDefault();
var target = $(this).parent().index();
moveTo(target);
});
Fiddle: http://jsfiddle.net/Guffa/r5DY8/3/
From a purely logical point of view (assumes the existence of two variables - curr_slide_num and butt_num):
for (var i=0; i < Math.abs(curr_slide_num - butt_num); i++) my_func();
Be careful of zero indexing; either treat the first button and first slide as number 0, or neither, else the maths will break down.
This takes no account of the direction the slider should move. I haven't looked at your Fiddle but I guess you would pass direction as an argument to the function. Let's say the function expects direction as its first argument - the string 'left' or 'right'
for (var i=0; i < Math.abs(curr_slide_num - butt_num); i++)
my_func(curr_slide_num < butt_num ? 'left' : 'right');

Categories