Navigate through multiple divs using next/prev - javascript

So basically my DIV will look like this.
<div id="group">
<div id="one">one</div>
<div style="display:none" id="two">two</div>
<div style="display:none" id="three">three</div>
<div style="display:none" id="four">four</div>
</div>
<div id="next">next</div>
<div style="display:none" id="prev">prev</div>
<div style="display:none" id="prev">SUBMIT</div>
This is just an example, I could even have 10 or 20 divs.
I want to navigate from one to four in this example. When it reaches end it must hide the next button and show submit button. And when I navigate back to first page it must hide the prev button
Here's what I have tried so far:
$("#next").click(function () {
$("#prev").show();
$("#one").hide();
$("#one").addClass("current");
$(".current").next().addClass("current").show();
$(".current").prev().removeClass("current").hide();
});
$("#prev").click(function () {
$("#prev").show();
$("#one").hide();
$("#one").addClass("current");
$(".current").prev().addClass("current").show();
$(".current").next().removeClass("current").hide();
});
This works for certain navigation after that it gets messes up. Some guidance will be helpful to me and others.
Thanks
JSFIDDLE : http://jsfiddle.net/aVJBY/450/

I see you have an answer, but I would suggest a more structured approach that reuses a single code path:
http://jsfiddle.net/TrueBlueAussie/aVJBY/460/
function updateItems(delta)
{
var $items = $('#group').children();
var $current = $items.filter('.current');
var index = $current.index();
var newIndex = index+delta;
// Range check the new index
newIndex = (newIndex < 0) ? 0 : ((newIndex > $items.length) ? $items.length : newIndex);
if (newIndex != index){
$current.removeClass('current');
$current = $items.eq(newIndex).addClass('current');
// Hide/show the next/prev
$("#prev").toggle(!$current.is($items.first()));
$("#next").toggle(!$current.is($items.last()));
}
}
$("#next").click(function () {
updateItems(1);
});
$("#prev").click(function () {
updateItems(-1);
});
Notes:
The range capping can be simplified, but you get the idea.
You do not need to initial inline styling as that can be done in the CSS.
This is not limited in any way by the content. Here I added 6 more divs: http://jsfiddle.net/TrueBlueAussie/aVJBY/463/
Update
As I do not like situations where styling is required for initial "state" in a page, here is a new version that sets the initial state correctly too without any initial styling (using a 0 delta). I also removed a redundant var:
function updateItems(delta)
{
var $items = $('#group').children();
var $current = $items.filter('.current');
$current = $current.length ? $current : $items.first();
var index = $current.index() + delta;
// Range check the new index
index = (index < 0) ? 0 : ((index > $items.length) ? $items.length : index);
$current.removeClass('current');
$current = $items.eq(index).addClass('current');
// Hide/show the next/prev
$("#prev").toggle(!$current.is($items.first()));
$("#next").toggle(!$current.is($items.last()));
}
$("#next").click(function () {
updateItems(1);
});
$("#prev").click(function () {
updateItems(-1);
});
// Cause initial selection
updateItems(0);
JSFiddle: http://jsfiddle.net/TrueBlueAussie/aVJBY/468/

I am showing another approach where you can set the current item to any element, and it will show the next prev arrows accordingly.
$(function() {
var updateDiv = function(trigger) {
var currentDiv = $(".current");
$("#group div").removeClass("current").hide();
if (trigger.hasClass("next") && currentDiv.next("div").length > 0) {
currentDiv.next("div").addClass("current").show();
} else if (trigger.hasClass("prev") && currentDiv.prev("div").length > 0) {
currentDiv.prev("div").addClass("current").show();
}
updateNavigation();
};
var updateNavigation = function() {
var intialDiv = $(".current");
intialDiv.show();
var intialDivIndex = intialDiv.index();
intialDivIndex > 0 ? $("#prev").show() : $("#prev").hide();
intialDivIndex < totalDivs - 1 ? $("#next").show() : $("#next").hide();
};
var totalDivs = $("#group div").length;
updateNavigation();
$("#next, #prev").on("click", function() {
updateDiv($(this));
});
});
#group div {
border: 1px solid red;
width: 100px;
height: 100px;
}
#next {
margin-left: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div id="group">
<div id="one" style="display:none">one</div>
<div style="display:none" id="two">two</div>
<div style="display:none" id="three">three</div>
<div style="display:none" id="four" class="current">four</div>
<div style="display:none" id="five">five</div>
<div style="display:none" id="six">six</div>
<div style="display:none" id="seven">seven</div>
<div style="display:none" id="eight">eight</div>
</div>
<div id="next" style="display:none" class="next">next</div>
<div style="display:none" id="prev" class="prev">prev</div>
<div style="display:none" id="prev">SUBMIT</div>

I'd also like to suggest this approach though as I see the problem's been solved:
var $divs = $("#group").children("div"),
index = 0;
$("#next").click(function () {
updateStatus(1);
});
$("#prev").click(function () {
updateStatus(-1);
});
function updateStatus(a) {
$divs.eq(index).removeClass("current").hide();
index += a;
$divs.eq(index).addClass("current").show();
$("#next").toggle(index !== $divs.length - 1);
$("#prev").toggle(index !== 0);
}
Fiddle

Maybe help you below code.
Updated... again...
$( "#next" ).click(function() {
if($(".current").length!=1){
$( "#group:first-child" ).addClass("current");
}
$(".current").removeClass("current").hide().next().addClass("current").show();
if($(".current").next().length!=1){
$( "#next" ).hide();
}
$( "#prev" ).show();
});
$( "#prev" ).click(function() {
if($(".current").length!=1){
$( "#group:last-child" ).addClass("current");
}
$(".current").removeClass("current").hide().prev().addClass("current").show();
if($(".current").prev().length!=1){
$( "#prev" ).hide();
}
$( "#next" ).show();
});
Fiddle Updated

You should create a function to hide or show the prev and next buttons on click. You can use the .index() function of jQuery to check if the current div is the first or last item inside the div#group
$(function(){
var $cur = $('#group .current');
var $items = $('#group .item');
function hideButtons() {
$cur = $('#group .current');
var index = $cur.index();
if(index > 0) {
$('#prev').show();
} else {
$('#prev').hide();
}
if(index < $items.length - 1) {
$('#next').show();
} else {
$('#next').hide();
}
}
hideButtons();
$('#next').click(function(){
$cur.next().addClass('current');
$cur.removeClass('current');
hideButtons();
});
$('#prev').click(function(){
$cur.prev().addClass('current');
$cur.removeClass('current');
hideButtons();
});
});
.item {
display: none;
}
.item.current {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="group">
<div id="one" class="current item">one</div>
<div id="two" class="item">two</div>
<div id="three" class="item">three</div>
<div id="four" class="item">four</div>
</div>
<button id="next">next</button>
<button style="display:none" id="prev">prev</button>

Related

jquery If statement based on a previous element

I want to hide an element if the previous element has a number less than 0.
https://jsfiddle.net/82bysjag/2/
$(document).on("click", function() {
$(".hide").each(function() {
var prevqty = $(".hide").prev().text();
if (prevqty < 0) {
$(this).hide();
} else {}
});
});
div {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
-2
</div>
<div class="hide">
Hide
</div>
<div>
1
</div>
<div class="hide">
Hide
</div>
Is there an error with my var prevqty?
Use $(this) and parseInt to
$(".hide").each(function() {
var prevqty = parseInt($(this).prev().text(), 10);
if (prevqty < 0) {
$(this).hide();
} else {}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>-2</div>
<div class="hide">Hide</div>
The problem is from prevqty. JavaScript is seing it as a string. Convert it to number first as follows;
var prevqty = $(".hide").prev().text();
prevqty =Number(prevqty );
Then you can compare

Loop a next button to return showing from the begining

$(document).ready(function() {
$(".container .parts").each(function(e) {
if (e > 1)
$(this).hide();
console.log(e);
});
$("#next").click(function() {
if ($(".container .parts:visible:last").next().length != 0) {
$(".container .parts:visible:last").next().show();
$(".container .parts:visible:last").next().show();
$(".container .parts:visible:first").hide();
$(".container .parts:visible:first").hide();
} else {
$(".container .parts:visible:last").hide();
$(".container .parts:visible:last").hide();
$(".container .parts:visible:first").next().show();
$(".container .parts:visible:first").next().show();
}
return false;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="parts">A</div>
<div class="parts">B</div>
<div class="parts">C</div>
<div class="parts">D</div>
<div class="parts">E</div>
</div>
<div>
<button id="next">Next</button>
</div>
Hello, In the code here, I'm trying to make the script return to showing first two divs again if it is the end of the divs, But at the last one it disappears.
Ok,
I think this should do what your after, it does the (AB), (CD), (E), and then back to (AB)....
$(document).ready(function() {
var step = 0;
var dcount = 2; //how many divs shall we show..
var parts = $('.container .parts');
function showbits() {
//loop all parts
parts.each(function (x) {
//is our step in range..?
$(this).toggle(x >= step && x < step + dcount);
});
//increae our step by out div count..
step = step + dcount;
//if step is greater than length go back to 0..
if (step >= parts.length) step = 0;
}
showbits();
$("#next").click(showbits);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="parts">A</div>
<div class="parts">B</div>
<div class="parts">C</div>
<div class="parts">D</div>
<div class="parts">E</div>
</div>
<div>
<button id="next">Next</button>
</div>
$(document).ready(function() {
var $arr = $(".container .parts"), // the whole collection
index = 0; // index at which to start showing
function showNext() {
$arr.hide(); // hide all
$arr.eq(index).show(); // show the element at index (these two lines could be replaced with a for loop if the number of divs to show is dynamic: (for(var i = 0; i < numberOfDivsToShow; i++) $arr.eq(index + i).show();)
$arr.eq(index + 1).show(); // show the element at index + 1 (if any, if not don't worry as jQuery takes care of that)
index = index + 2; // increment index by 2 (if the number of divs to show is dynamic then instead of adding 2, you must add the number of divs: index = index + numberOfDivsToShow;)
if(index >= $arr.length) index = 0; // if we pass $arr.length then go back to 0
}
$("#next").click(showNext); // when clicking the #next button, show the next elements
showNext(); // by default show the first two
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="parts">A</div>
<div class="parts">B</div>
<div class="parts">C</div>
<div class="parts">D</div>
<div class="parts">E</div>
</div>
<div>
<button id="next">Next</button>
</div>
because in your code, once the last visible element becomes invisible, there are no elements visible anymore, so the :visible selector can't find any elements.
Of course there are many ways to solve this problem, but I just want to make a minimum modification to your code.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="container">
<div class="parts">A</div>
<div class="parts">B</div>
<div class="parts">C</div>
<div class="parts">D</div>
<div class="parts">E</div>
</div>
<div>
<button id="next">Next</button>
$(document).ready(function() {
$(".container .parts").each(function(e) {
if (e > 1)
$(this).hide();
console.log(e);
});
$("#next").click(function() {
if ($(".container .parts:visible:last").next().length != 0) {
$(".container .parts:visible:last").next().show();
$(".container .parts:visible:last").next().show();
$(".container .parts:visible:first").hide();
$(".container .parts:visible:first").hide();
} else {
$(".container .parts:visible:last").hide();
$(".container .parts:visible:last").hide();
$(".container .parts:first").show(); //only modified these two lines
$(".container .parts:first").next().show();
}
return false;
});
});

How to add an if statement to a toggle function

Consider the following code, which toggles visibility of two classes with separate click() functions:
<!-- Toggles -->
<div class="a"></div>
<div class="b"></div>
<!-- Result -->
<div class="x" style="display:none"></div>
<div class="y" style="display:none"></div>
<div class="z" style="display:none"></div>
<!-- Script -->
$( ".a" ).click(function() {
var $this = $(this);
$this.siblings(".x").toggle();
});
$( ".b" ).click(function() {
var $this = $(this);
$this.siblings(".y").toggle();
});
How would I update this so that any time both x and y are visible, a third class, "z" is shown instead of both x and y?
Demo http://jsfiddle.net/Yn3L2/
API is(':visible') http://api.jquery.com/visible-selector/
Rest should fit your needs :)
Code
$(".a").click(function () {
var $this = $(this);
$this.siblings(".x").toggle();
checkZ();
});
$(".b").click(function () {
var $this = $(this);
$this.siblings(".y").toggle();
checkZ();
});
function checkZ() {
$('.z').hide();
if ($('.x').is(':visible') && $('.y').is(':visible')) {
$('.z').show();
}
}
This works as show here: http://jsfiddle.net/DKRe2/1/
HTML:
<!-- Toggles -->
<div class="a">a</div>
<div class="b">b</div>
<!-- Result -->
<div class="x" style="display:none">class x</div>
<div class="y" style="display:none">class y</div>
<div class="z" style="display:none">class z</div>
JS:
<!-- Script -->
$(".a").click(function () {
var $this = $(this);
if ($this.siblings(".y").css('display') != 'none' && $this.siblings(".x").css('display') == 'none') {
//now Hide y and show Z
$this.siblings(".y").toggle();
$this.siblings(".z").toggle();
} else {
$this.siblings(".z").css('display', 'none');
$this.siblings(".x").toggle();
}
});
$(".b").click(function () {
var $this = $(this);
if ($this.siblings(".x").css('display') != 'none' && $this.siblings(".y").css('display') == 'none') {
//now Hide y and show Z
$this.siblings(".x").toggle();
$this.siblings(".z").toggle();
} else {
$this.siblings(".z").css('display', 'none')
$this.siblings(".y").toggle();
}
});
I think this is what you really want.
Working DEMO
Added jQuery code
function checkZ() {
$('.z').hide();
if ($('.x').is(':visible') && $('.y').is(':visible')) {
$('.x').hide(500);
$('.y').hide(500)
$('.z').show();
}
}

How do I change the active class to the LI element when I click next/previous button?

I have this HTML markup:
<ul style="text-align: center;" class="product-wizard-bar">
<li style="cursor:default" class="active" data-display="categories-picker" id="tab1">Seleccionar categoría</li>
<li data-display="product-create-step-2" id="tab2" class="">Datos</li>
<li style="display: none" data-display="product-create-step-3" id="tab3">Variaciones</li>
<li data-display="product-create-step-4" id="tab4" class="">Detalles del Producto</li>
<li data-display="product-create-step-5" id="tab5" class=""><a class="last" style="cursor:default" href="#">Condiciones de Venta</a></li>
</ul>
<fieldset title="Categoría" class="fstep" id="categories-picker" style="display: none;"></fieldset>
<fieldset style="display: none;" title="Producto" class="fstep" id="product-create-step-2"></fieldset>
<fieldset style="display: none" title="Variaciones" id="product-create-step-3"></fieldset>
<fieldset style="display: none;" title="Detalles" class="fstep" id="product-create-step-4"></fieldset>
<fieldset style="display: none;" title="Condiciones" class="fstep" id="product-create-step-5"></fieldset>
<div style="position:absolute; right:0px; margin-top: 20px; margin-bottom: 20px;">
<button disabled="disabled" id="previous-step" name="previous" type="button" class="button">« Anterior</button>
<button id="next-step" name="next" type="button" class="button">Siguiente »</button>
</div>
And this is the jQuery code to handle next/previous steps:
$('fieldset.fstep').hide().eq(0).show();
$('#next-step').click(function() {
var current = $('fieldset.fstep:visible'), next = current.next('fieldset.fstep');
var category_id = $("#selected_category").val();
if (next.length === 0) {
next = current.nextUntil('fieldset.fstep').next('fieldset.fstep');
}
current.hide();
next.show();
if (next.nextUntil('fieldset.fstep').next('fieldset.fstep').add(next.next('fieldset.fstep')).length === 0) {
$("#next-step").prop("disabled", true);
}
$("#previous-step").prop("disabled", false);
});
$('#previous-step').click(function() {
var current = $('fieldset.fstep:visible'), prev = current.prev('fieldset.fstep');
var category_id = $("#selected_category").val();
if (prev.length === 0) {
prev = current.prevUntil('fieldset.fstep').prev('fieldset.fstep');
}
current.hide();
prev.show();
if (prev.prevUntil('fieldset.fstep').prev('fieldset.fstep').add(prev.prev('fieldset.fstep')).length === 0) {
$("#previous-step").prop("disabled", true);
}
$("#next-step").prop("disabled", false);
});
$("#product_create").on("click", "#tab1, #tab2, #tab3, #tab4, #tab5", function() {
var div = $('#' + $(this).data('display'));
$("li.active").removeClass("active");
$(this).addClass('active');
if ($.trim(div.html()) !== '') {
$('#' + $(this).data('display')).show().siblings('fieldset').hide();
}
return false;
});
How I can change the active class to the element according to the fieldset I'm on? I mean when I click next/previous button?
Since the id of the displayed item and the data-display property of the wizard-bar items are same, you can use it to filter and add the active class
var $fsteps = $('fieldset.fstep').hide();
var $wizitems = $('.product-wizard-bar > li');
$fsteps.eq(0).show();
$('#next-step').click(function () {
var current = $fsteps.filter(':visible'),
next = current.next('fieldset.fstep');
var category_id = $("#selected_category").val();
if (next.length === 0) {
next = current.nextUntil('fieldset.fstep').next('fieldset.fstep');
}
current.hide();
next.show();
$wizitems.filter('.active').removeClass('active')
$wizitems.filter('[data-display="' + next.attr('id') + '"]').addClass('active')
if (next.nextUntil('fieldset.fstep').next('fieldset.fstep').add(next.next('fieldset.fstep')).length === 0) {
$("#next-step").prop("disabled", true);
}
$("#previous-step").prop("disabled", false);
});
$('#previous-step').click(function () {
var current = $fsteps.filter(':visible'),
prev = current.prev('fieldset.fstep');
var category_id = $("#selected_category").val();
if (prev.length === 0) {
prev = current.prevUntil('fieldset.fstep').prev('fieldset.fstep');
}
current.hide();
prev.show();
$wizitems.filter('.active').removeClass('active')
$wizitems.filter('[data-display="' + prev.attr('id') + '"]').addClass('active')
if (prev.prevUntil('fieldset.fstep').prev('fieldset.fstep').add(prev.prev('fieldset.fstep')).length === 0) {
$("#previous-step").prop("disabled", true);
}
$("#next-step").prop("disabled", false);
});
$("#product_create").on("click", "#tab1, #tab2, #tab3, #tab4, #tab5", function () {
var div = $('#' + $(this).data('display'));
$("li.active").removeClass("active");
$(this).addClass('active');
if ($.trim(div.html()) !== '') {
$('#' + $(this).data('display')).show().siblings('fieldset').hide();
}
return false;
});
Demo: Fiddle

Implementing colspan on DIVS

I have a div layout like this
Style
.l-item{
display:inline-block;
border:1px solid #CCC;
width:20px;
height:20px
}
<div id="head">
<div>
<div class="l-item">a</div>
<div class="l-item">a</div>
<div class="l-item">a</div>
<div class="l-item">a</div>
<div class="l-item">b</div>
<div class="l-item">b</div>
</div>
<div>
<div class="l-item">x</div>
<div class="l-item">y</div>
<div class="l-item">z</div>
<div class="l-item">z</div>
<div class="l-item">z</div>
<div class="l-item">x</div>
</div>
<div>
<div class="l-item">1</div>
<div class="l-item">2</div>
<div class="l-item">3</div>
<div class="l-item">4</div>
<div class="l-item">4</div>
<div class="l-item">4</div>
</div>
</div>
My requirement is to merge similar valued and sibling DIVS into single DIV as colspan. For that I have an approach like below
$('#head > div').each(function(){
$(this).find('.l-item').each(function(){
var txt = $(this).text();
$(this).siblings().filter(function(){
return $(this).text() == txt;
});
});
});
It seems like it will mess with the DOM, any other solution for this please..
Try this out:- http://jsfiddle.net/adiioo7/rnL3h/
JS:-
$('#head > div').each(function () {
$(this).find('.l-item').each(function () {
var txt = $(this).text();
var items = $(this).siblings().filter(function () {
return $(this).text() == txt;
});
if (items.length > 0) {
$(this).width($(this).width() * (items.length + 1));
items.remove();
}
});
});
Here's a little bit of help to get you started: http://jsfiddle.net/WeJmu
$('#head > div').each(function(){
$(this).find('.l-item').each(function(){
var txt = $(this).text();
var num_eaten = 0;
$(this).siblings().each(function () {
if ($(this).text() === txt) {
num_eaten++;
$(this).remove();
}
});
if (num_eaten > 0) {
$(this).width($(this).width() * (num_eaten + 1));
}
});
});
different approach with next, you can develop it with better way. demo
$('#head > div').each(function(){
$(this).find('.l-item').each(function(){
var txt = $(this).text();
if( $(this).next().text() == txt){
$(this).next().width($(this).next().width() + 20);
$(this).remove();
}
});
});
if by appearance you want consecutive divs with same text to look like a single div/column;
http://jsfiddle.net/WeJmu/2/
$('#head > div').each(function(){
$(".l-item").each(function(){
var $this=$(this);
var $next=$(this).next();
if( $this.text()==$next.text()){
$this.css({'border-right':'none'});
$next.css({'border-left':'none'});
}
});
});

Categories