add class to li onclick - javascript

how will i go on to added a class to li class='active' on click and also on page load have the first li ( overview ) active by default ?
<ul>
<li>Overview</li>
<li>Reviews</li>
<li>News</li>
<li>Gallery</li>
</lu>
<div id='overview' style='display: none;'>
<!-- overview content -->
</div>
<div id='articles' style='display: none;'>
<!-- arcticles content -->
</div>
<div id='news' style='display: none;'>
<!-- news content -->
</div>
<div id='gallery' style='display: none;'>
<!-- gallery content -->
</div>
<script type="text/javascript">
function showdiv(id){
document.getElementById(id).style.display = "block";
}
</script>

Here is a Quick JSFiddle Demo that demonstrates swapping classNames and display of divs in pure JavaScript.
var toggleDiv = function(self, id) {
var li = self.parentNode,
contents = document.getElementsByClassName('content'),
menu = document.getElementById('menu'),
children = menu.children,
child = undefined,
i = 0;
// Loop over all content divs and show the active and hide all others.
for (i = 0; i < contents.length; i++)
contents[i].style.display = contents[i].id == id ? 'block' : 'none';
// Loop over all menu items and add active class to the selected
// and remove from others if applicable.
for (i = 0; i < children.length; i++) {
child = children[i];
if (child === li) {
child.className = (child.className + ' active').trim();
} else {
if (child.className.indexOf('active') > -1) {
child.className = child.className.replace('active', '').trim();
}
}
}
}
<ul id="menu">
<li>Overview</li>
<li>Reviews</li>
<li>News</li>
<li>Gallery</li>
</ul>
<div id="overview" class="content">Overview...</div>
<div id="reviews" class="content">Reviews...</div>
<div id="news" class="content">News...</div>
<div id="gallery" class="content">Gallery...</div>
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
li {
position: relative;
display: inline-block;
width: 80px;
background: #4679BD;
color: #FFFFFF;
text-align: center;
}
li>a {
color: #FFFFFF;
text-decoration: none;
font-weight: bold;
}
.content {
display: none;
}
.active {
background: #064CA8;
}

You should consider using jQuery if you have not already. It really makes these a bit easier.
Strictly speaking, here is one way: (untested)
<ul>
<li>Overview</li>
<li>Reviews</li>
<li>News</li>
<li>Gallery</li>
</ul>
<div id='overview' style='display: none;'>
<!-- overview content -->
</div>
<div id='articles' style='display: none;'>
<!-- arcticles content -->
</div>
<div id='news' style='display: none;'>
<!-- news content -->
</div>
<div id='gallery' style='display: none;'>
<!-- gallery content -->
</div>
<script type="text/javascript">
function showdiv(id, a){
if (window.activeA != undefined) {
window.activeA.className = ''; // delcare window.activeA, if not already exists
}
document.getElementById(id).style.display = "block";
a.className = 'active';
window.activeA = a;
}
</script>

Related

Is there a shorter more concise way to hide & show div with Javascript?

I am creating a dashboard with approximately 20 divs starting with "display: none;".
When the .onClick() in the sidebar will be used, it will show a specific div and keep hidden all the others.
I have used the classic solution of creating a function for each div, however, is extremely lengthy and the code looks like a mess.
Is there a better cleaner way to achieve this with Javascript?
Here is my code:
function presale() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (x.style.display === "grid") {
x.style.display = "none";
} else {
x.style.display = "grid";
y.style.display = "none";
z.style.display = "none";
}
}
function claim() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (y.style.display === "grid") {
y.style.display = "none";
} else {
x.style.display = "none";
y.style.display = "grid";
z.style.display = "none";
}
}
function stake() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (z.style.display === "grid") {
z.style.display = "none";
} else {
x.style.display = "none";
y.style.display = "none";
z.style.display = "grid";
}
}
*,
html {
color: #fff;
background-color: black;
}
#presale,
#claim,
#stake
/* Here I have many other divs like below */
{
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<link rel="stylesheet" href="MOD.CSS">
<script src="main2.js"></script>
<title>Base Template</title>
</head>
<body>
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li onclick="presale()">Presale</li>
<li onclick="claim()">Claim</li>
<li onclick="stake()">Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div id="presale">
<h1>Presale</h1>
</div>
<div id="claim">
<h1>Claim</h1>
</div>
<div id="stake">
<h1>Stake</h1>
</div>
</div>
</body>
</html>
Is there a better way to do this without the need to create a function and repeat the same thing over and over for each div?
There is no need for JS at all. You can simply use an anchor and use #id as hyper reference. Then you can display the element through CSS by using the :target-selector:
*,
html {
color: #fff;
background-color: black;
}
.d-none
/* Here I have many other divs like below */
{
display: none;
}
div:target {
display: grid;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<link rel="stylesheet" href="MOD.CSS">
<script src="main2.js"></script>
<title>Base Template</title>
</head>
<body>
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li>Presale</li>
<li>Claim</li>
<li>Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div id="presale" class="d-none">
<h1>Presale</h1>
</div>
<div id="claim" class="d-none">
<h1>Claim</h1>
</div>
<div id="stake" class="d-none">
<h1>Stake</h1>
</div>
</div>
</body>
</html>
Here you see a vanilla Javascript solution.
content divs are by default hidden.
If you click an element, the corresponding data-id get the class show.
window.onload = function () {
document.querySelectorAll('#nav li').forEach((elements) => {
elements.addEventListener('click', (el) => {
document.querySelectorAll('.content').forEach((item) => {
// hide all
item.classList.remove('show');
});
// show one
document.getElementById(el.target.getAttribute('data-id')).classList.add('show');
});
});
};
.content {
display: none;
}
.show {
display: block;
}
<ul id="nav">
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div id="presale" class="content">
<h1>Presale</h1>
</div>
<div id="claim" class="content">
<h1>Claim</h1>
</div>
<div id="stake" class="content">
<h1>Stake</h1>
</div>
Something like this using data attributes and classlist toggles should also work.
I would consider minimizing your code (and CSS) by using generic CSS selectors to hide/show the individual sections. This also makes scalability and maintainability easier for the next guy.
This has the added benefit of your styling being controlled 100% using CSS and not arbitrary inline styles set by the javascript.
Adding another section is also easy as can be:
Add a new section with some id (eg. awesome-section)
Add a nav entry with the attribute data-toggle-section with the id as the value <li data-toggle-section="awesome-section">Awesome Section</li>
Profit
You're also not restricted to using just the nav elements themselves as the event listener is bound using the [data-toggle-section] selector which means that basically anything can show or hide a section as long as it has that attribute with the correct value.
const buttons = Array.from(document.querySelectorAll("[data-toggle-section]"));
const sections = buttons.map(element => {
return document.getElementById(element.dataset.toggleSection)
});
buttons.forEach(element => {
element.addEventListener('click', event => {
const selected = element.dataset.toggleSection;
sections.forEach(section => {
if(section.id === selected) {
section.classList.toggle('shown');
} else {
section.classList.remove('shown');
}
})
});
});
*,
html {
color: #fff;
background-color: black;
}
.option-section {
display: none;
}
.option-section.shown {
display: grid;
}
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li data-toggle-section="presale">Presale</li>
<li data-toggle-section="claim">Claim</li>
<li data-toggle-section="stake">Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div id="presale" class="option-section">
<h1>Presale</h1>
</div>
<div id="claim" class="option-section">
<h1>Claim</h1>
</div>
<div id="stake" class="option-section">
<h1>Stake</h1>
</div>
</div>
You could simply assign the same class (e.g. my_div) to every showable div, then pass the id to your function (that will show that and hide all the others).
function show_hide(id) {
document.querySelectorAll('.my_div').forEach(my_div => {
my_div.style.display = my_div.getAttribute('id') == id ? 'block' : 'none';
});
}
.my_div {
display: none;
}
<div>
<ul>
<li onclick="show_hide('presale')">Presale</li>
<li onclick="show_hide('claim')">Claim</li>
<li onclick="show_hide('stake')">Stake</li>
</ul>
<div class="my_div" id="presale">
<h1>Presale</h1>
</div>
<div class="my_div" id="claim">
<h1>Claim</h1>
</div>
<div class="my_div" id="stake">
<h1>Stake</h1>
</div>
</div>
Here's my attempt. It's sensibly the same as #ztom's answer but I tryed avoiding a foreach.
document.querySelectorAll("li").forEach(e => e.addEventListener("click", () => {
let shown = document.querySelector(".action:not(.d-none)")
if(shown){
shown.classList.add("d-none")
if(e.dataset.id != shown.id){
document.getElementById(e.dataset.id).classList.remove("d-none")
}
}else{
document.getElementById(e.dataset.id).classList.remove("d-none")
}
}))
.action{
display:grid;
}
.d-none{
display:none;
}
<ul>
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div class="action d-none" id="presale">Presale</div>
<div class="action d-none" id="claim">Claim</div>
<div class="action d-none" id="stake">Stake</div>
When it comes to use the same logic on multiple elements, use classes instead of id's and your solution is shortened by default.
With jQuery, it's basically a 2-liner:
in CSS, create a class .hidden with display:none;
Your div and li elements should be grouped, using a class too.
Then you can simply refer to this classes and add the show/hide logic by:
$('h1:contains('+$(this).text()+')').parent().toggleClass("hidden");
$('h1:not(:contains('+$(this).text()+'))').parent().addClass("hidden");
$('document').ready(function(){
$('.toggle').on('click',function(){
$('h1:contains('+$(this).text()+')').parent().toggleClass("hidden");
$('h1:not(:contains('+$(this).text()+'))').parent().addClass("hidden");
});
});
*,
html {
color: #fff;
background-color: black;
}
.hidden
{
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="MOD.CSS">
<script src="main2.js"></script>
<title>Base Template</title>
</head>
<body>
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li class="toggle">Presale</li>
<li class="toggle">Claim</li>
<li class="toggle">Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div class="hidden">
<h1>Presale</h1>
</div>
<div class="hidden">
<h1>Claim</h1>
</div>
<div class="hidden">
<h1>Stake</h1>
</div>
</div>
</body>
</html>
This is a question for Code Review section https://codereview.stackexchange.com/
However, you can try smth like this:
const elems = ["presale", "claim", "stake"];
function toggle(elem) {
elems.map(i => {
let el = document.getElementById(i);
el.style.display = "none";
});
let active_el = document.getElementById(elem);
active_el.style.display = "grid";
}
and in html add the elem name as a param, so, replace this
<li onclick="presale()">Presale</li>
<li onclick="claim()">Claim</li>
<li onclick="stake()">Stake</li>
with this
<li onclick="toggle('presale')">Presale</li>
<li onclick="toggle('claim')">Claim</li>
<li onclick="toggle('stake')">Stake</li>
If you attach data attributes to both the list items and the "panels" you can use one function to match them up, and use a CSS class to determine whether it should be active or not.
// Cache the elements, the panels container, and the list element
// separately adding one event listener to the list. We're using
// event delegation for this - one listener captures all
// the events from its child elements
const allElements = document.querySelectorAll('.list li, .panels .panel');
const panels = document.querySelector('.panels');
const list = document.querySelector('ul');
list.addEventListener('click', handlePanel);
// When the listener is triggered
function handlePanel(e) {
// Check if it's a list item
if (e.target.matches('li')) {
// Destructure its id from the dataset
const { id } = e.target.dataset;
// Remove all the active classes from the elements
allElements.forEach(el => el.classList.remove('active'));
// And then add an active class to the list item,
// and the panel where their ids match
const selector = `[data-id="${id}"]`;
const item = list.querySelector(`li${selector}`);
const panel = panels.querySelector(`.panel${selector}`);
item.classList.add('active');
panel.classList.add('active');
}
}
.panel { display: none; }
.panel h1 { font-size: 1.2em; color: darkblue; }
ul { list-style-type: none; margin-left: 0; padding: 0; }
li { padding: 0.3em; border: 1px solid white; }
li:hover { background-color: thistle; cursor: pointer; }
li.active { border: 1px solid #454545; background-color: lightyellow; }
.panel.active { display: block; }
<ul class="list">
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div class="panels">
<div data-id="presale" class="panel">
<h1>Presale</h1>
</div>
<div data-id="claim" class="panel">
<h1>Claim</h1>
</div>
<div data-id="stake" class="panel">
<h1>Stake</h1>
</div>
</div>
Additional documentation
classList
Destructuring assignment
Event delegation
matches
querySelector / querySelectorAll
Template/string literals

How do I check whether an element is already bound to an event?

Goal
Avoid unnecessary event bindings.
Sample code
Comment box with a reply button for each individual comment
const btns = document.getElementsByClassName('reply-btn');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', showCommentContentAsPreview);
}
function showCommentContentAsPreview(e) {
console.log('showCommentContentAsPreview()');
// CHECK IF THIS BUTTON ALREADY BINDED !!!
const previewDiv = document.getElementById('preview');
const commentId = e.target.getAttribute('data-comment-id')
const commentDiv = document.getElementById('comment-' + commentId);
const commentText = commentDiv.querySelector('p').innerText
const closeReplyBtn = previewDiv.querySelector('button');
const previewContent = previewDiv.querySelector('.preview-content');
// set to preview
previewContent.innerText = commentText;
// show reply close button
closeReplyBtn.classList.remove('hidden');
// bind EventListener to "reply close button"
closeReplyBtn.addEventListener('click', closeReply)
function closeReply() {
console.log('bind to btn');
previewContent.innerText = '';
this.removeEventListener('click', closeReply);
closeReplyBtn.classList.add('hidden');
}
}
.hidden {
display: none;
}
.comment {
border-bottom: 1px solid #000;
padding: 5px;
}
.preview {
background-color: #ccc;
padding: 20px;
margin-top: 20px;
}
<div>
<!-- comment list -->
<div id="comment-1" class="comment">
<p>Comment Content 1</p>
<button class="reply-btn" data-comment-id="1">reply</button>
</div>
<div id="comment-2" class="comment">
<p>Comment Content 2</p>
<button class="reply-btn" data-comment-id="2">reply</button>
</div>
</div>
<!-- output -->
<div>
<div id="preview" class="preview">
<div class="preview-content"></div>
<button class="hidden">Close Preview</button>
</div>
</div>
Simulate problem
When you try the example, the following two scenarios occur:
Click reply once and then click "close preview"
Click on reply several times and then on "close preview".
Question
How can I avoid multiple bindings to the same button? I am already thinking about singleton.
Instead of binding a listener to every element in the series, you can bind a single listener once on a common parent of them all, and then use element.matches() to determine if the click target is the one that you want before doing more work. See the following example:
function logTextContent (elm) {
console.log(elm.textContent);
}
function handleClick (ev) {
if (ev.target.matches('.item')) {
logTextContent(ev.target);
}
}
document.querySelector('ul.list').addEventListener('click', handleClick);
<ul class="list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
<li class="item">Item 4</li>
<li class="item">Item 5</li>
</ul>
With the helpful hints from #Zephyr and #jsejcksn I have rewritten the code of the above question. Thus I have achieved my goal of avoiding multiple identical bindings to one element.
const container = document.getElementById('comment-container');
const previewDiv = document.getElementById('preview');
const closeReplyBtn = previewDiv.querySelector('button');
const previewContent = previewDiv.querySelector('.preview-content');
container.addEventListener('click', handleClick);
function handleClick(ev) {
if (ev.target.matches('.reply-btn')) {
if (ev.target.getAttribute('listener') !== 'true') {
removeOtherListenerFlags();
ev.target.setAttribute('listener', 'true');
showCommentContentAsPreview(ev);
}
}
if (ev.target.matches('#preview button')) {
previewContent.innerText = '';
closeReplyBtn.classList.add('hidden');
removeOtherListenerFlags();
}
}
function showCommentContentAsPreview(e) {
console.log('showCommentContentAsPreview()');
const commentId = e.target.getAttribute('data-comment-id')
const commentDiv = document.getElementById('comment-' + commentId);
const commentText = commentDiv.querySelector('p').innerText
// set to preview
previewContent.innerText = commentText;
// show reply close button
closeReplyBtn.classList.remove('hidden');
}
function removeOtherListenerFlags() {
const replyBtns = container.querySelectorAll('.reply-btn')
Object.keys(replyBtns).forEach((el) => {
replyBtns[el].removeAttribute('listener');
})
}
.hidden {
display: none;
}
.comment {
border-bottom: 1px solid #000;
padding: 5px;
}
.preview {
background-color: #ccc;
padding: 20px;
margin-top: 20px;
}
<div id="comment-container">
<div id="comment-listing">
<!-- comment list -->
<div id="comment-1" class="comment">
<p>Comment Content 1</p>
<button class="reply-btn" data-comment-id="1">reply 1</button>
</div>
<div id="comment-2" class="comment">
<p>Comment Content 2</p>
<button class="reply-btn" data-comment-id="2">reply 2</button>
</div>
</div>
<!-- output -->
<div>
<div id="preview" class="preview">
<div class="preview-content"></div>
<button class="hidden">Close Preview</button>
</div>
</div>
</div>
Cool and Thanks!

jQuery tabs - Enable and disable

I'm having a problem on how to disable tab 3 when the first button is clicked. When I click Activate 2nd tab, the 2nd tab will be enabled, but the 3rd tab will be enabled, too; it should be enabled when I click Activate 3rd tab.
What should I do?
<div class="tab-wrapper" id="tab-wrapper">
<div class="tab-header">
<ul class="tabs">
<li>Step 1</li>
<li>Step 2</li>
<li>Step 3</li>
</ul>
</div>
<div class="tab_container">
<div id="tab1" class="tab_content">
this is tab 1
<button id="button2">Activate 2nd tab</button>
</div>
<div id="tab2" class="tab_content">
this is tab 2
<button id="button3">Activate 3rd tab</button>
</div>
<div id="tab3" class="tab_content">
This is tab3
</div>
</div>
</div>
</body>
<script type="text/javascript">
$(function() {
var activate = false,
tabLinks = $('.tabs a'),
tabContent = $('.tab_container').children();
tabLinks.eq(0).addClass('active'); // Add active class, could possibly go in markup
$('#tab2').hide();
$('#tab3').hide(); // Hide second tab
tabLinks.bind('click', function(e) {
e.preventDefault();
if(activate === true) { // Only do something if button has been clicked
var target = this.hash,
el = $(this);
tabLinks.filter('.active').removeClass('active');
el.addClass('active');
tabContent.hide(); // Hide all
$(target).show(); // Show selected
}
});
$('#button2').bind('click', function() {
activate = true; // Activate tab functionality
tabLinks.eq(1).trigger('click'); // Trigger a click on the second tab link
});
$('#button3').bind('click', function() {
activate = true; // Activate tab functionality
tabLinks.eq(2).trigger('click'); // Trigger a click on the third tab link
});
});
</script>
</html>
You can do something like this (using an array to know if the tab is already activated instead of only one boolean):
$(function() {
var activate = [true, false, false],
tabLinks = $('.tabs a'),
tabContent = $('.tab_container').children();
tabLinks.eq(0).addClass('active'); // Add active class, could possibly go in markup
$('#tab2').hide(); // Hide second tab
$('#tab3').hide(); // Hide second tab
tabLinks.on('click', function(e) {
e.preventDefault();
var idx = $(this).data('index');
if (activate[idx] === true) { // Only do something if button has been clicked
var target = this.hash,
el = $(this);
tabLinks.filter('.active').removeClass('active');
el.addClass('active');
tabContent.hide(); // Hide all
$(target).show(); // Show selected
}
});
$('button').on('click', function() {
var index = $(this).data('index');
activate[index] = true; // Activate tab functionality
tabLinks.eq(index).trigger('click'); // Trigger a click on the second tab link
});
});
* {
padding: 0;
margin: 0;
}
body {
margin: 30px;
}
.tab-wrapper {
width: 500px;
}
.tabs {
overflow: hidden;
list-style: none;
}
.tabs li {
float: left;
margin-right: 10px;
border: 1px solid #ccc;
border-bottom: 0;
}
.tabs a {
display: block;
padding: 5px;
width: 100px;
}
.tabs a.active {
background: #efefef;
}
.tab_container > div {
padding: 10px;
border: 1px solid #ccc;
}
button {
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="tab-wrapper" id="tab-wrapper">
<div class="tab-header">
<ul class="tabs">
<li>step1</li>
<li>step2</li>
<li>step3</li>
</ul>
</div>
<div class="tab_container">
<div id="tab1" class="tab_content">
here is the list of the overview
<button data-index="1">Activate 2nd tab</button>
</div>
<div id="tab2" class="tab_content">
here is the list of the overview
<button data-index="2">Activate 3nd tab</button>
</div>
<div id="tab3" class="tab_content">
End
</div>
</div>
</div>
</body>
You can find the code on jsfiddle too :
https://jsfiddle.net/psLshz3u/

How to dynamically link menu items to sections

Using jQuery, how can I dynamically add href and id attributes to link the menu items to the sections in the code below in order?
<body>
<nav>
<ul>
<li><a>nav1</a></li>
<li><a>nav2</a></li>
<li><a>nav3</a></li>
</ul>
</nav>
<section class="main-section"></section>
<section class="main-section"></section>
<section class="main-section"></section>
</body>
It should look like this after.
<body>
<nav>
<ul>
<li>nav1</li>
<li>nav2</li>
<li>nav3</li>
</ul>
</nav>
<section id="id1" class="main-section"></section>
<section id="id2" class="main-section"></section>
<section id="id3" class="main-section"></section>
</body>
You can try this.....
Fiddle
Html :
<ul>
</ul>
</nav>
<div id='addMore'>
</div>
<button id='btn'>add section and link</button>
Jquery :
var count = 0;
$('#btn').click(function(){
$('#addMore').append('<section id="id'+ count+'" class="main-section"></section>');
$('nav ul').append('<li>nav'+count+'</li>');
count++;
});
let me know if it according to you requirements...
Happy coding...
How about this: First build your strings
var sections ="";
var list = "<ul>";
for(var i=0; i < 3; i++)
{
list += '<li>nav'+i+'</li>';
sections += '<section id="id'+i+'" class="main-section"></section>';
}
list += "</ul>"
Then add them somewhere like:
$('nav').html(list );
$('#container').html(sections);
Here is the JSFIDDLE
var totalLists = 4;
var listitems='';
var sectionitems='';
$(document).ready(function(){
for(var i = 1; i<= totalLists; i++){
listitems = listitems+'<li>nav'+i+'</li>';
sectionitems=sectionitems+'<section id="id'+i+'" class="main-section"></section>'
}
$("#navlists").append(listitems);
$("#section").append(sectionitems);
});
You can try this solution :
adding id dynamically to section within body according to nav element
Seems like the nav element exist already then the solution is find the a element length(for creating section), then insert newly created element after existing section or nav. Hope this helped.
Html
<nav>
<ul>
<li><a>nav1</a>
</li>
<li><a>nav2</a>
</li>
<li><a>nav3</a>
</li>
</ul>
</nav>
jQuery
$('nav li a').each(function(i,e){
var section;
$(this).attr('href','#id'+(i+1));
section = $('<section/>',{
class : 'main-section',
id : 'id'+(i+1)
});
if ( $('nav').next().is('section') ) {
$(section).insertAfter($('nav').nextAll().last());
} else {
$(section).insertAfter('nav');
}
});
DEMO
You can loop through the links, then assign common href and id values based on the index of the link.
This checks if the section exists before setting the attributes.
var sections = $('section.main-section');
$('nav a').each(function(index){
if(sections.eq(index).length) {
$(this).attr('href','#section' + index);
sections.eq(index).attr('id','section' + index);
}
})
/* This CSS is for demo purposes only */ html, body { margin: 0; height: 100%; } .main-section { height: 100%; } ul,li { padding: 0; margin: 0; } ul { position: fixed; } li { display: inline-block; } #section0 { background: rgb(150,200,250); } #section1 { background: rgb(250,200,150); } #section2 { background: rgb(150,250,200); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul>
<li><a>nav1</a></li>
<li><a>nav2</a></li>
<li><a>nav3</a></li>
<li><a>nav4</a></li> <!-- This will not change because
there is no fourth section -->
</ul>
</nav>
<section class="main-section"></section>
<section class="main-section"></section>
<section class="main-section"></section>

simple jquery slideshow with navigation?

So I'm in the process of creating a pretty simple jQuery/CSS slideshow for a course of mine. It's about ten pages long, and right now it works fine if you want to just go from beginning to end in that order, but if you need to refresh the page for any reason, it sends you back to the first page. Since it's on the longer end, I'd like to be able to "click" to a certain page... is this possible without getting too complicated?
Here's my jQuery
function checkNav() {
if ($('.active-slide').hasClass('first')) {
$('.prev').hide();
$('.next').show();
} else if ($('.active-slide').hasClass('last')) {
$('.next').hide();
$('.prev').show();
} else {
$('.next').show();
$('.prev').show();
}
}
var main = function() {
checkNav();
$('.next').click(function() {
var currentSlide = $('.active-slide');
var nextSlide = currentSlide.next('.slide');
var currentDot = $('.active-dot');
var nextDot = currentDot.next();
//if nextslide is last slide, go back to the first
if (nextSlide.length === 0) {
nextSlide = $('.slide').first();
nextDot = $('.dot').first();
}
currentSlide.fadeOut(500).removeClass('active-slide');
nextSlide.fadeIn(1100).addClass('active-slide');
currentDot.removeClass('active-dot');
nextDot.addClass('active-dot');
checkNav();
});
//prev slide function
$('.prev').click(function() {
var currentSlide = $('.active-slide');
var prevSlide = currentSlide.prev('.slide');
var currentDot = $('.active-dot');
var prevDot = currentDot.prev();
//if prevslide is last slide, go back to the first
if (prevSlide.length === 0) {
prevSlide = $('.slide').last();
prevDot = $('.dot').last();
}
currentSlide.fadeOut(600).removeClass('active-slide');
prevSlide.fadeIn(600).addClass('active-slide');
currentDot.removeClass('active-dot');
prevDot.addClass('active-dot');
checkNav();
});
};
$(document).ready(main);
And here's a rough markup of what the HTML looks like
<div class="slide active-slide first">
<div class="content">
<p>First Slide</p>
</div>
</div>
<div class="slide">
<div class="content">
<p>second slide</p>
</div>
</div>
<div class="slide last">
<div class="content">
<p>third slide</p>
</div>
</div>
<div class="slider-nav">
<div class="prev">prev</div>
<ul class="dots">
<li class="dot active-dot">•</li>
<li class="dot">•</li>
<li class="dot">•</li>
</ul>
<div class="next">next</div>
</div>
Here's the jsFiddle ... I'd like to be able to click on one of the bullets and go to that corresponding slide....
$('ul.dots li').click(function(){
var num = $(this).index();
var currentSlide = $('.active-slide');
var nextSlide = $('.slide:eq('+num+')');
var currentDot = $('.active-dot');
var nextDot = $(this);
currentSlide.fadeOut(600).removeClass('active-slide');
nextSlide.fadeIn(600).addClass('active-slide');
currentDot.removeClass('active-dot');
nextDot.addClass('active-dot');
checkNav();
});
Add IDs to the divs. For instance:
<div class="slide active-slide first" id="1">
<div class="content">
<p>First Slide</p>
</div>
</div>
<div class="slide" id="2">
<div class="content" >
<p>second slide</p>
</div>
</div>
<div class="slide last" id="3">
<div class="content">
<p>third slide</p>
</div>
</div>
Then you can target specific slides using something like:
<ul class="dots">
<li class="dot active-dot"><a onclick="goto(1)">•</a></li>
<li class="dot"><a onclick="goto(2)">•</a></li>
<li class="dot"><a onclick="goto(3)">•</a></li>
</ul>
<script>
function goto(slide){
$(".slide").removeClass("active-slide");
$("#"+slide).addClass("active-slide");
$("#"+slide).show();
}
We need a way to "index" these items, I will do it by child so add a parent div class called slider:
<div id="slider">
...slides here...
</div>
You need to use localStorage (used to save data between pages) to keep track of both what slide you are on and what dot you are on in the nav bar. This can save data even when we leave the page (when it refreshes), making it so we still know our last page we where on. I will use this to keep track of the current index of each slide. So when the page loads we need to check that if our localStorage item exist:
// If we have saved data add it's index to active-slide
if(localStorage.getItem("activeSlide")) {
$("#slider div.slide")
.eq(localStorage.getItem("activeSlide"))
.addClass("active-slide");
$('.dots li.dot')
.eq(localStorage.getItem("activeSlide"))
.addClass("active-dot");
} else { // Otherwise make them both 0
$("#slider div.slide")
.eq('0')
.addClass("active-slide");
$('.dots li.dot')
.eq('0')
.addClass("active-dot");
}
Then when we move to the next slide next or the last slide prev we update the localStorage item to the current index of the item in active-slide:
// Make the current index of the item in active slide our updated variable
localStorage.setItem( "activeSlide",
$("#slider div.slide").index($(".active-slide")) );
Here is a working example
This way when the page refreshes we stay on the last slide we where looking at before.
<!doctype html>
<html>
<head>
<style>
body{
text-align: center;
}
#slideshow{
margin:0 auto;
width:600px;
height:450px;
overflow: hidden;
position: relative;
}
#slideshow ul{
list-style: none;
margin:0;
padding:0;
position: absolute;
}
#slideshow li{
float:left;
}
#slideshow a:hover{
background: rgba(0,0,0,0.8);
border-color: #000;
}
#slideshow a:active{
background: #990;
}
.slideshow-prev, .slideshow-next{
position: absolute;
top:180px;
font-size: 30px;
text-decoration: none;
color:#fff;
background: rgba(0,0,0,0.5);
padding: 5px;
z-index:2;
}
.slideshow-prev{
left:0px;
border-left: 3px solid #fff;
}
.slideshow-next{
right:0px;
border-right: 3px solid #fff;
}
</style>
</head>
<body>
<div id="slideshow">
«
<ul>
<li><img src="1.jpg" alt="photo1" /></li>
<li><img src="2.jpg" alt="photo2" /></li>
<li><img src="3.jpg" alt="photo3" /></li>
<li><img src="4.jpg" alt="photo4" /></li>
</ul>
»
</div>
<!--
We use Google's CDN to serve the jQuery js libs.
To speed up the page load we put these scripts at the bottom of the page
-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
//an image width in pixels
var imageWidth = 600;
//DOM and all content is loaded
$(window).ready(function() {
var currentImage = 0;
//set image count
var allImages = $('#slideshow li img').length;
//setup slideshow frame width
$('#slideshow ul').width(allImages*imageWidth);
//attach click event to slideshow buttons
$('.slideshow-next').click(function(){
//increase image counter
currentImage++;
//if we are at the end let set it to 0
if(currentImage>=allImages) currentImage = 0;
//calcualte and set position
setFramePosition(currentImage);
});
$('.slideshow-prev').click(function(){
//decrease image counter
currentImage--;
//if we are at the end let set it to 0
if(currentImage<0) currentImage = allImages-1;
//calcualte and set position
setFramePosition(currentImage);
});
});
//calculate the slideshow frame position and animate it to the new position
function setFramePosition(pos){
//calculate position
var px = imageWidth*pos*-1;
//set ul left position
$('#slideshow ul').animate({
left: px
}, 300);
}
</script>
</body>
</html>

Categories

Resources