I have the following HTML code and I'm really struggling to come up with a solution for the following: (pseudo code, javascript or jquery answers please, but would prefer jquery)
When the page loads, hide all of the list items except for the first
5 (display only the first five, select by unique id)
Two buttons on
the bottom of the list, one for "older" one for "newer".
When older btn is
pressed, show the next 5 on the list (might just be one list-item if
there is 6 altogether)
When "newer" is pressed, show the 5 in front of the current list-items
Hide newer button if already on the first page 5
code:
<div class="container">
<div class="list-item" id="13">
<p>First Item</p>
</div>
<div class="list-item" id="12">
<p>Second Item</p>
</div>
<div class="list-item" id="11">
<p>Third Item</p>
</div>
<div class="list-item" id="10">
<p>Fourth Item</p>
</div>
<div class="list-item" id="9">
<p>Fifth Item</p>
</div>
<div class="list-item" id="8">
<p>Sixth Item</p>
</div>
… ( more list-items)
</div>
<button onclick="showOlder()">Older</button>
<button onclick="showNewer()">Newer</button>
After further research and trial and error I Was able to come up with a solution. I thought I'd post it if anyone else is looking for something similar. Please note I'm not an expert in jQuery and this code can probably be done in a more optimised way.
$(document).ready(function () {
btnNewer.hide();
for (i = numOfItems; i >= 1; i--) {
if (i == numOfItems - (5 * page)) {
page++;
}
$("#" + i).addClass("Page-" + page);
}
for (i = 0; i <= numOfPages; i++) {
if (i != 1) {
hidePage(i);
}
}
});
var numOfItems = $('div.list-item').length;
var numOfPages = Math.ceil(numOfItems / 5);
var page = 1;
var currentPage = 1;
var btnOlder = $("#showOlder")
var btnNewer = $("#showNewer")
function hidePage(pageNum) {
$('.Page-' + pageNum).hide();
}
function showPage(pageNum) {
$('.Page-' + pageNum).show();
}
btnOlder.on("click", function () {
hidePage(currentPage);
currentPage++;
showPage(currentPage);
CheckIfOnLastPage();
CheckIfOnFirstPage();
})
btnNewer.on("click", function () {
hidePage(currentPage);
currentPage--;
showPage(currentPage);
CheckIfOnFirstPage();
CheckIfOnLastPage();
})
function CheckIfOnFirstPage() {
if (currentPage == 1) {
btnNewer.hide();
} else {
btnNewer.show();
}
}
function CheckIfOnLastPage() {
if (currentPage == numOfPages) {
btnOlder.hide();
} else {
btnOlder.show();
}
}
Related
Background
I made slides which are appeared on a modal, and its main functions are below.
There are "←Prev, Next→" buttons, and it enables to flip the page.
There are page numbers, "1, 2, 3", and it enables to flip the page.
If the shown page is the first or the last one, "←Prev, Next→" buttons are hidden, respectively.
Those functions were working properly when I had only one slide with the code below, but the last funtion doesn't work with multiple slides now.
slide.html.erb
<ul>
<li><div data-target="slide01">Slide1</div>
<div id="slide01" class="modal-wrapper">
<div class="modal">
<div class="close-modal">
<i class="fa fa-2x fa-times"></i>
</div>
<div class="slide-wrapper">
<div class="slide-title">Slide1</div>
<div class="change-btn-wrapper">
<div class="change-btn prev-btn">← Prev</div>
<div class="change-btn next-btn">Next →</div>
</div>
<ul class="slides">
<li class="slide active">A</li>
<li class="slide">B</li>
<li class="slide">C</li>
</ul>
<div class="index-btn-wrapper">
<div class="index-btn">1</div>
<div class="index-btn">2</div>
<div class="index-btn">3</div>
</div>
</div>
</div>
</div>
</li>
<li><div data-target="slide02">Slide2</div>
<div id="slide02" class="modal-wrapper">
<div class="modal">
<div class="close-modal">
<i class="fa fa-2x fa-times"></i>
</div>
<div class="slide-wrapper">
<div class="slide-title">Slide2</div>
<div class="change-btn-wrapper">
<div class="change-btn prev-btn">← Prev</div>
<div class="change-btn next-btn">Next →</div>
</div>
<ul class="slides">
<li class="slide active">D</li>
<li class="slide">E</li>
<li class="slide">F</li>
</ul>
<div class="index-btn-wrapper">
<div class="index-btn">1</div>
<div class="index-btn">2</div>
<div class="index-btn">3</div>
</div>
</div>
</div>
</div>
</li>
</ul>
slide.js
$(document).on('turbolinks:load', function() {
$(function() {
function toggleChangeBtn(){
var slideIndex = $('.slide').index($('.active'));
$('.change-btn').show();
if (slideIndex == 0) {
$('.prev-btn').hide();
} else if (slideIndex == $('.slide').length -1) {
$('.next-btn').hide();
}
$('.index-btn').click(function() {
$('.active').removeClass('active');
var clickedIndex = $('.index-btn').index($(this));
$('.slide').eq(clickedIndex).addClass('active');
toggleChangeBtn();
});
$('.change-btn').click(function() {
var $displaySlide = $('.active');
$displaySlide.removeClass('active');
if ($(this).hasClass('next-btn')) {
$displaySlide.next().addClass('active');
}
else {
$displaySlide.prev().addClass('active');
}
toggleChangeBtn();
});
})
});
Problems
Those codes below check if the shown page is the first or the last one from its index number, and hide "←Prev, Next→" buttons, respectively.
slide.js
var slideIndex = $('.slide').index($('.active'));
$('.change-btn').show();
if (slideIndex == 0) {
$('.prev-btn').hide();
} else if (slideIndex == $('.slide').length -1) {
$('.next-btn').hide();
}
The trouble is that those index numbers are connected when multiple slides are made. As a result, the code above just checks only both of the first page in the first slide and the last page in the last slide.
What I have tried
I tried to use $(this).parents method to narrow down the range of the slide like below. I did not make any change on the view.
slide.js
$(document).on('turbolinks:load', function() {
$(function() {
function toggleChangeBtn(dir){
var dir = $(this).parents('.slide-wrapper'); // Identify the slide.
$('.change-btn').show();
var slideIndex = dir.find('.slide').dir.index('.active');
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
} else if (slideIndex == dir.find('.slide').length -1) {
dir.find('.next-btn').hide();
}
}
$('.index-btn').click(function() {
var dir = $(this).parents('.slide-wrapper');
dir.find('.active').removeClass('active');
var clickedIndex = $('.index-btn').index($(this));
$('.slide').eq(clickedIndex).addClass('active');
toggleChangeBtn(dir);
});
$('.change-btn').click(function() {
var dir = $(this).parents('.slide-wrapper');
var $displaySlide = dir.find('.active');
$displaySlide.removeClass('active');
if ($(this).hasClass('next-btn')) {
$displaySlide.next().addClass('active');
}
else {
$displaySlide.prev().addClass('active');
}
toggleChangeBtn(dir);
});
})
});
However, "←Prev, Next→" buttons are not hidden properly in any slide with this code.
And how "←Prev, Next→" buttons are shown in one slide affects to the other slide too.
I am grateful if anyone gives me some advice.
Versions
ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3
jquery 1.12.4
If both buttons should be independent of each other, why are they made dependant by the if / else if block?
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
} else if (slideIndex == dir.find('.slide').length -1) {
dir.find('.next-btn').hide();
}
To make the .prev-btn and .next-btn appear/disappear independently, make these independant if statements:
var slides = dir.find('.slide');
var slideIndex = slides.length ? slides.dir.index('.active') : 0;
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
}
if (slides.length <= 1 || slideIndex == slides.length - 1) {
dir.find('.next-btn').hide();
}
Looking to remove a class if a certain button is clicked.
<div class="slide-container">
<section class="about" id="slide-0">
<div class="menu-total">
<nav class="nav">
<button class="nav_link home" onclick="slideTo('slide-2')">HOME</button>
<button class="nav_link about" onclick="slideTo('slide-0')">ABOUT</button>
<button class="nav_link fun-stuff" onclick="slideTo('slide-1')">FUN STUFF</button>
<button class="nav_link professional" onclick="slideTo('slide-3')">PROFESSIONAL</button>
<button class="nav_link contact" onclick="slideTo('slide-4')">CONTACT</button>
</nav>
<div class="hamburger">
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
</div>
</div>
The one I want to remove the class on is the HOME button. So "slideTo('slide-2)". If it's clicked on the others then the class is kept. I believe someone is either wrong with my loop or not getting the ID correctly of the items/
function slideTo(slideId) {
const slide = document.getElementById(slideId);
slide.scrollIntoView({
behavior: 'smooth'
})
// above this line works fine
let nonHome = document.querySelectorAll('.slide-container section');
let nonHomeID = document.getElementById('slide-2');
var i;
setTimeout(function(){
for (i=0; i < nonHome.length; i++ ){
// i believe it's somewhere here it is wrong
if (nonHome[i].id != nonHomeID){
nonHome[i].classList.add("nav-visibility");
} else{
nonHomeID.classList.remove("nav-visibility");
}
}
}, 1000)
}
If you can use jquery library, you can write in the HTML:
<button class="nav_link" data-value="home">HOME</button>
...
and then in the JS code:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // Get the data-value clicked
$(".nav_link").each(function() { // Loop through all elements of the class 'nav-link'
var v = $(this).data("value");
if (v == valueClicked) {
$(this).removeClass("nav-visibility");
} else {
$(this).addClass("nav-visibility");
}
)
}
Not much simpler, but the HTML is cleaner.
Simpler version if it is not required to browse through all buttons at each button click:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // The value of the button clicked by the user
if (valueClicked == "home") {
$(this).removeClass("nav-visibility");
console.log('remove')
} else { $(this).addClass("nav-visibility");
console.log('add')
}
});
I'm trying to set up pagination for some blog posts. It works with the first page, and I check my tests to see if the loop is actually populating the "postsToDisplay" array (which it does), but when I click the second-page button, nothing shows up. I can click the first-page button and it brings the first page of posts back up. For some reason, it won't push the new arrays to the page though.
I've tried adding and taking away tests to see what is working. The array is definitely being populated, and the loop is going through the correct "i" values just fine.
Here's some edited code to reproduce my problem:
//Use this as "scripts.js"
$(document).ready(function() {
var realBlog = document.getElementsByClassName("realBlog");
var postsPerPage = 2;
var $pagination = $(".pagination")
function showPage(page) {
$(realBlog).hide();
let postsToDisplay = [];
for (let i = 0; i < realBlog.length; i += 1) {
if (i >= page * postsPerPage && i <= page * postsPerPage + postsPerPage - 1) {
postsToDisplay.push(realBlog[i]);
console.log(i); //Test to see if the loop is running the correct numbers
$(postsToDisplay[i]).show();
}
}
console.log(postsToDisplay); //Test to see if the array is full
return postsToDisplay;
}
showPage(0);
function createPageNumbers() {
let createUl = document.createElement("ul");
createUl.className = "pageNumbers";
for (let i = 1; i <= Math.ceil(realBlog.length/2); i += 1) {
let createLi = document.createElement("li");
let createA = document.createElement("a");
createA.href = "#" + i;
createA.textContent = i;
createLi.className = "pageButton";
createLi.append(createA);
createUl.append(createLi);
$(".pagination").append(createUl);
createA.addEventListener("click", () => {
showPage(i-1);
});
}
}
createPageNumbers();
});
//Use this as index.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="scripts.js"></script>
</head>
<body>
<div class="container realBlog">
<h1 class="realBlogTitle threeDText">Title</h1>
<p class="entry"></p>
<div class="entryInfo">
<span class="tag1"></span>
<span class="tag2"></span>
<span class="date"></span>
<span class="time"></span>
</div>
<div class="borderBottom"></div>
</div>
<div class="container realBlog">
<h1 class="realBlogTitle threeDText">Title</h1>
<p class="entry"></p>
<div class="entryInfo">
<span class="tag1"></span>
<span class="tag2"></span>
<span class="date"></span>
<span class="time"></span>
</div>
<div class="borderBottom"></div>
</div>
<div class="container realBlog">
<h1 class="realBlogTitle threeDText">Title</h1>
<p class="entry"></p>
<div class="entryInfo">
<span class="tag1"></span>
<span class="tag2"></span>
<span class="date"></span>
<span class="time"></span>
</div>
<div class="borderBottom"></div>
</div>
<div class="pagination"></div>
</body>
</html>
Page 1 should show posts 1 and 2, page 2 should show post 3.
Alright, I found the answer, and of course, it's a silly mistake. I have this little snippet: $(postsToDisplay[i]).show();
I'm not sure why I'm trying to show each 'i' when I can just show the whole array... So the fix is $(postsToDisplay).show();
Need help with using js script.
<ul class="producers-links">
<li class="section_All active-producer">A-Z</li>
<li class="section_0-9">0-9</li>
<li class="section_A">A</li>
<li class="section_B">B</li>
<li class="section_C">C</li>
</ul>
And
<div class="producers-list">
<div class="producers-container" id="producers-0-9">
<div class="break-producers">0-9</div>
</div>
<div class="producers-container" id="producers-A">
<div class="break-producers">A</div>
Producer 1
</div>
<div class="producers-container" id="producers-B">
<div class="break-producers">B</div>
Producer 2
</div>
<div class="producers-container" id="producers-C">
<div class="break-producers">C</div>
Producer 3
</div>
</div>
How to make js script that will allow user click on list element then all divs from producers-list will get display:none without this one which was clicked at list.
var producersList = document.querySelectorAll('ul.producers-links>li');
var producersLists = document.querySelectorAll('div.producers-list>div.producers-container');
for (var i = 0; i < producersList.length; i++) {
producersList[i].addEventListener('click', function () {
document.querySelector('.active-producer').classList.remove('active-producer');
this.classList.add('active-producer');
var index = 0,
length = producersList.length;
for (; index < length; index++) {
producersLists[index].style.display = "none";
}
});
}
This allow me to hide all elements from producers-container but i don't know how to show only one element clicked before at list.
First of all you should use classes instead of id in the second list in order to have the ability to add more procedures in the future
try this:
<ul class="producers-links">
<li id="section_All" class="active-producer">A-Z</li>
<li id="section_0-9">0-9</li>
<li id="section_A">A</li>
<li id="section_B">B</li>
<li id="section_C">C</li>
</ul>
<div class="producers-list">
<div class="producers-container section_0-9 section_All">
<div class="break-producers">0-9</div>
</div>
<div class="producers-container section_A section_All">
<div class="break-producers">A</div>
Producer 1
</div>
<div class="producers-container section_B section_All">
<div class="break-producers">B</div>
Producer 2
</div>
<div class="producers-container section_C section_All">
<div class="break-producers">C</div>
Producer 3
</div>
</div>
var producersList = document.querySelectorAll('ul.producers-links > li');
var producersLists = document.querySelectorAll('.producers-container');
for (var i = 0; i < producersList.length; i++) {
producersList[i].addEventListener('click', function () {
document.querySelector('.active-producer').classList.remove('active-producer');
this.classList.add('active-producer');
for (var index = 0; index < producersLists.length ; index++) {
var currElement = producersLists[index];
var hide = !currElement.classList.contains(this.id);
producersLists[index].style.display = hide? "none" : "block";
}
});
}
On click, you can sequentially:
- hide all
- select the one having the same end of id than the textContent of the clicked item (or select all if text is A-Z)
var producersList = document.querySelectorAll('ul.producers-links>li');
var producersLists = document.querySelectorAll('div.producers-list>div.producers-container');
// add eventlistener...
producersList.forEach(x => {
x.addEventListener("click", x => {
hideAll();
document.querySelector('.active-producer').classList.remove('active-producer');
x.target.classList.add('active-producer');
const txt = x.target.textContent;
selectForText(txt);
});
});
// hide/show all...
function hideAll(bShow) {
const cl = bShow === true?"block":"none";
producersLists.forEach(x => x.style.display = cl);
}
// select for text...
function selectForText(txt) {
if(txt === "A-Z") {
// select all...
hideAll(true);
return;
}
// the [...nodelist] part allows to 'cast' to proper array, and to have access to find() function...
const found = [...producersLists].find(q => q.id.split("producers-")[1] === txt);
if(found) {
found.style.display = "block";
}
else {
// ???
}
}
.active-producer {
color: #19f;
}
<ul class="producers-links">
<li class="section_All active-producer">A-Z</li>
<li class="section_0-9">0-9</li>
<li class="section_A">A</li>
<li class="section_B">B</li>
<li class="section_C">C</li>
</ul>
And
<div class="producers-list">
<div class="producers-container" id="producers-0-9">
<div class="break-producers">0-9</div>
</div>
<div class="producers-container" id="producers-A">
<div class="break-producers">A</div>
Producer 1
</div>
<div class="producers-container" id="producers-B">
<div class="break-producers">B</div>
Producer 2
</div>
<div class="producers-container" id="producers-C">
<div class="break-producers">C</div>
Producer 3
</div>
</div>
I currently have it so that a block of text changes when you click on the "page" number, but I'd like to add previous and next buttons.
Check out my current version here: http://jsfiddle.net/ZBWqS/
Every solution I've thought of turns into a mess of non-working code when I start going.
Sorry for the noob-JS question.
<div id="1" style="display: block;">
<p>This is the first block of text</p>
<p class="page">
1 of 3
</p>
</div>
<div id="2" style="display: none;">
<p class="red">This is the second block of text</p>
<p class="page">
2 of 3
</p>
</div>
<div id="3" style="display: none;">
<span>This is the third block of text</span>
<p class="page">
3 of 3
</p>
</div>
<div class="bottom">
1 2 3
</div>
<script>
function show(id) {
document.getElementById(id).style.display = 'block';
}
function hide(id) {
document.getElementById(id).style.display = 'none';
}
</script>
I have also build a refactored version of your code, you decide which one you like more ;)
http://jsfiddle.net/haDAj/
HTML
<div id="1" class="pagecontainer" style="display: block;">
<p>This is the first block of text</p>
<p class="page">
1 of 3
</p>
</div>
<div id="2" class="pagecontainer" style="display: none;">
<p class="red">This is the second block of text</p>
<p class="page">
2 of 3
</p>
</div>
<div id="3" class="pagecontainer" style="display: none;">
<span>This is the third block of text</span>
<p class="page">
3 of 3
</p>
</div>
<div class="bottom">
‹
1
2
3
›
</div>
SCRIPT
var currentPage = 1;
function page(pg)
{
var els = document.getElementsByClassName("pagecontainer");
for (var i = 0; i < els.length; i++)
{
var page_of_container = els[i].getAttribute("id");
els[i].style.display = page_of_container == pg ? 'block' : 'none';
}
currentPage = pg;
}
function prev()
{
if (currentPage <= 1) return;
page(currentPage -1);
}
function next()
{
if (currentPage >= document.getElementsByClassName("pagecontainer").length) return;
page(currentPage + 1);
}
Keep a variable to store where you are, increment/decrement it, then show content based on that variable.
http://jsfiddle.net/ZBWqS/3/
// hold where we are right now. For previous and next to make sense,
// you have to know where you are.
var current = 1;
// function to go to previous
var prev = function() {
current -= 1;
if (current < 1) current = 1; // can't go too far previous
showContent();
};
// function to go next
var next = function() {
current += 1;
if (current > 3) current = 3; // can't go too far next
showContent();
};
// Update what content we are showing based on the "current" index
var showContent = function() {
var display;
for (var i = 1; i <= 3; i++) {
if (i == current) {
display = 'block';
} else {
display = 'none';
}
document.getElementById(i).style.display = display;
}
};
// bind the prev and next function to the links
document.getElementById('prev').onclick = prev;
document.getElementById('next').onclick = next;
// Setup the initial state of the content
showContent();