Target previous element with jQuery - javascript

I'm creating portfolio section where every portfolio item shows as an image and every portfolio item has its own div which is hidden and contains more information about that item. When the user clicks on some portfolio item (image) div with more information for that item is shown. Each div with more info has two classes, portf-[nid] and portf ([nid] is Node ID, I work in Drupal and this class with [nid] helps me to target portfolio item with more info div for that item).
Each of the more info divs contains arrows for item listing (next and previous) and I need to get them function, so when the user clicks on previous I need to hide current and show the previous item if it exists(when clicks on next to hide current and show next item if it exists).
My markup looks like:
<div class="portf-3 portf">
//some elements
</div>
<div class="portf-6 portf">
//some elements
</div>
<div class="portf-7 portf">
//some elements
</div>
My question is how to hide the div I'm currently on and show the previous (or next). For example: if it is currently shown div with class portf-6 and user clicks on previous arrow, this div is being hidden and div with class portf-3 is being shown.
It's not the problem to hide/show the div but how to check if there is the div above/below the current div and to target that div above or below the current div?

Here you are:
function GoToPrev()
{
var isTheLast = $('.portf:visible').prev('.portf').length === 0;
if(!isTheLast)
{
$('.portf:visible').hide().prev().show();
}
}
function GoToNext()
{
var isTheLast = $('.portf:visible').next('.portf').length === 0;
if(!isTheLast)
{
$('.portf:visible').hide().next().show();
}
}

To check if prev / next element is present or not, you can make use of .length property as shown below
if($('.portf:visible').prev('.portf').length > 0) // greater than 0 means present else not
same for next element
if($('.portf:visible').next('.portf').length > 0)

As you also need to update the next and previous buttons, I would suggest a more structured approach to the whole thing:
function update(delta) {
var $portfs = $('.portf');
var $current = $portfs.filter(':visible');
var index = $portfs.index($current) + delta;
if (index < 0) {
index = 0;
}
if (index > $portfs.length){
index = $portfs.length;
}
$current.hide();
$portfs.eq(index).show();
$('#prev').toggle(index > 0);
$('#next').toggle(index < $portfs.length-1);
}
$('#prev').click(function () {
update(-1);
});
$('#next').click(function () {
update(1);
});
// Hide all initially
$('.portf').hide();
// Show the first with appropriate logic
update(1);
JSFiddle: http://jsfiddle.net/TrueBlueAussie/xp0peoxw/
This uses a common function that takes a delta direction value and makes the decisions on range capping an when to hide/show the next/previous buttons.
The code can be shortened further, but I was aiming for readability of the logic.
If the next/prev buttons are correctly shown the range checking is not needed, so it simplifies to:
function update(delta) {
var $portfs = $('.portf');
var $current = $portfs.filter(':visible');
var index = $portfs.index($current) + delta;
$current.hide();
$portfs.eq(index).show();
$('#prev').toggle(index > 0);
$('#next').toggle(index < $portfs.length-1);
}
JSFiddle: http://jsfiddle.net/TrueBlueAussie/xp0peoxw/1/

Related

"[i - 1]" is Not Getting the Last Element of a List (JavaScript)

The Problem:
Hey everyone. I'm trying to create a simple function that identifies the next and previous elements of a current item within the ".length" of elements in a div, and then changes the ID of those two elements. Everything is working except for the part where it tries to identify the previous element at the beginning and the next element at the end.
What I've Tried:
It used to be that it would identify those items by using ".nextElementSibling" and ".previousElementSibling", but I realized that since it starts at the first element within the div then it would begin leaking out and trying to identify the previous element outside of the div. I decided to use a for loop that creates a list of the elements with the specific class name, which works as intended. It begins to run into issues again, though, when it reaches the beginning or the end of the list. I assumed that "[i - 1]" would automatically bring it to the last element if the current was the one at the beginning of the list, and that "[i + 1]" would automatically bring it to the first element if the current was the one at the end of the list. It seems that is not the case.
Is anyone able to help me figure this out? It would be much appreciated.
Note: For the sake of simplicity, I didn't include the JavaScript code that makes it switch between items within the div. That part is fully functional so I don't believe it should affect the underlying concept of this problem.
My Code:
HTML:
<div class="items">
<div id="current-item" class="current-div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
</div>
Javascript:
var divItems = document.getElementsByClassName('div-item'); // Gets number of elements with the specific class.
for (i = 0; i < divItems.length; i++) { // Creates list of elements with the specific class.
if (divItems[i].classList.contains('current-div-item')) { // If it is the current item, then do this:
var next = divItems[i + 1] // Find the next element in the list
var previous = divItems[i - 1] // Find the previous element in the list
next.id = 'next-item' // Change the next element's ID to "next-item"
previous.id = 'previous-item' // Change the previous element's ID to "previous-item"
}
}
You are wanting the items to wrap around that isn't going to happen. For the first item the previous item will be index -1 and for the last item the next index will be 1 larger than the actual number of items in the array.
If you add in a ternary you can get the values to wrap.
var prevIndex = (i === 0) ? divItems.length - 1 : i - 1;
var nextIndex = (i === divItems.length - 1) ? 0 : i + 1;
var next = divItems[prevIndex] // Find the next element in the list
var previous = divItems[nextIndex] // Find the previous element in the list
Based on your HTML code, in logic JS to fetch the all the items based in class it would not fetch the current-div-item as you have written logic to fetch only div-item. So I assume that you also need to change the HTML code. As per my understanding about your requirement I have done some changes and uploading the modified code. Which is working as per you requirement.
HTML:
<div id="current-div-item" class="div-item">Current</div>
<div id="item" class="div-item">Div1</div>
<div id="item" class="div-item">Div2</div>
<div id="item" class="div-item">Div3</div>
<div id="item" class="div-item">Div4</div>
Java Script:
var divItems = document.getElementsByClassName('div-item'); // Gets number of elements with the specific class.
for (i = 0; i < divItems.length; i++) {
if (divItems[i].id=='current-div-item') {
var next;
if (i == divItems.length-1)
next = divItems[0];
else
next = divItems[i + 1];
var previous;
if (i == 0)
previous=divItems[divItems.length-1];
else
previous = divItems[i - 1] // Find the previous element in the list
next.id = 'next-item' // Change the next element's ID to "next-item"
previous.id = 'previous-item' // Change the previous element's ID to "previous-item"
}
}
Attached the screenshot of the modified elements id for your reference

Select hidden elements and manipulate them with jQuery

Within a div wrapper with a class of "section", I have dozens of HTML elements repeated across the page that look like this:
<div class="section">
<div class="article"></div>
<div class="article"></div>
<div class="article"></div>
</div>
And each contains certain information inside. Now, what I'm trying to do is once the page loads, show only the first 5, hide the rest in a new div inserted with jQuery, and when this new div is clicked it will display the next five , and then the next five on click again, and so on until the end. The idea is that this new div will function as a button that will always be positioned at the end of the page and will respond to these orders I just mentioned. So far I've got this down:
$('.section').each(function () {
var $this = $(this),
$allArticles = $this.find('.article');
if ($allArticles.length > 5) {
$('<div/>').addClass('hidden-articles').appendTo(this).append($allArticles.slice(5));
$('.hidden-articles .article').hide();
}
});
And that hides all but the first five. But now for the rest of the process, I can't get it to work. I don't seem to be able to select properly those hidden div with class "article" and manipulate them to function the way I described above. I would appreciate it a lot if someone more experienced with jQuery could guide me in the right direction and maybe offer a snippet. Many thanks in advance!
You can use the :hidden and :lt selectors to get the functionality you are looking for..
$('.section').each(function() {
var $this = $(this),
$allArticles = $this.find('.article');
if ($allArticles.length > 5) {
$('<div/>').addClass('hidden-articles')
.appendTo(this).append($allArticles.slice(5));
$this.find('.hidden-articles .article').hide();
}
});
$('#show').on('click',function() {
var $hidden = $('.hidden-articles .article:hidden:lt(5)');
$hidden.show();
});​
UPDATE
// If one one element to search
var elem = '.section' ;
hideArticles(elem);
// If Multiple Elements on the page...
$('.section').each(function() {
hideArticles(this);
});
$('#show').on('click', function() {
var $hidden = $('.hidden-articles .article:hidden:lt(5)');
$hidden.show();
});
function hideArticles(elem) {
var $this = $(elem),
$allArticles = $this.find('.article');
if ($allArticles.length > 5) {
$('<div/>').addClass('hidden-articles')
.appendTo(this).append($allArticles.slice(5));
$this.find('.hidden-articles .article').hide();
}
}​
Check Fiddle

With JS, how to create an access key to jump to the "next section" on a page?

I have a page with several sections, and each section begins with a H2 tag. Each section has a different length from each other. I'd like to have two access keys: P and N, for "previous" and "next".
Let's say a user is viewing this page and scrolls to the middle of the page, and is viewing Section 5. If they hit the P access key to go to the previous section, then the browser should jump them to the H2 heading of Section 4. If they hit N to go to the next section, then they should jump to the H2 heading of Section 6.
Is it possible to do this, without needing to create a separate access key for every section? (E.g. "1" for Section 1, "2" for Section 2, etc.)
No you don't have to make separate keys - you only need a pointer to where the user got to and an array of all your sections... Assuming each section starts with H2 here is the code that will do what you want:
<script>
var sections = new Array();
$(document).ready(function(){
//get an array of all your sections
sections = $("h2");
//your pointer to a current section
index= 0;
$(document).keydown(function(event) {
//previous 'p'
if (event.keyCode == '80') {
if (index!=0) {
index--;
} else {
//wrap navigation (go tot the last item if on first item)
index = sections.length-1;
}
jump(sections[index]);
event.preventDefault();
}
//next 'n'
if (event.keyCode == '78') {
if (index<sections.length-1) {
index++;
} else {
//wrap navigation (go the the first item if on last item)
index = 0;
}
jump(sections[index]);
event.preventDefault();
}
})
})
function jump(obj){
var new_position = $(obj).offset();
window.scrollTo(new_position.left,new_position.top);
}
</script>
You'll need to build an array of the offsetTop for each matching h2.
When the user presses 'P' or 'N' you'll need to check the current scrollTop position in the window, and find where this sits on the sections.
From here grab the prev/next position and change the window's scrollTop via scrollTo()...
It would honestly take more time to write this out, and if you're using a library (jquery, dojo, etc) would make it easier.

How to cycle through each li or div front and backwards using jquery

I have a ul with around five <li> items. E.g.
<ul>
<li>Step 1 : Take food</li>
<li>Step 2 : Go Around</li>
<li>Step 3 : Deliver</li>
</ul>
Also I have links like
Previous
and
Next
I have to show the first li at first. Then when the next link is clicked, it should now show 2nd <li> and so on. Same for previous link. Please help.
following is the complete code:
$(document).ready(function()
{
var ul = $('ul');
// hide all li
ul.find('li').hide();
// make first li as current
ul.find('li').first().addClass('current').show();
// setup previous click handler
$('a#prev').click(function()
{
var prev = ul.find('li.current').prev();
if( prev.length )
{
ul.find('li.current').removeClass('current').hide();
prev.addClass('current').show();
}
});
// setup next click handler
$('a#next').click(function()
{
var next = ul.find('li.current').next();
if( next.length )
{
ul.find('li.current').removeClass('current').hide();
next.addClass('current').show();
}
});
});
have a look at the aptly named jQuery Cycle plugin.
http://www.malsup.com/jquery/cycle/scrollhv.html
If you are only showing one element, all you need to do is use the DOM tree as a search. If you want the next element, find the element that is currently being shown, hide it, and show its next sibling. If you are doing previous, then hide the current item and select the previous sibling.
If you are unsure of how to do this, just Google around for DOM navigation. It isn't too bad.
If at all possible, I would simply use some naming convention for your LI (in the id attribute) that you could very quickly select using jQuery. For instance, if your shown element is going to have a class that the rest won't have, you can select that element quickly using jQuery, grab its id, and modify it in some way to select the previous or next element.
as boerema said something along these lines (its untested!)
put a class "selected" on a li that starts as being shown
<ul>
<li>Step 1 : Take food</li>
<li class="selected">Step 2 : Go Around</li>
<li>Step 3 : Deliver</li>
</ul>
$("#prev").click(function(){
$(".selected").hide().removeClass("selected").prev().show().addClass("Selected");
});
$("#next").click(function(){
$(".selected").hide().removeClass("selected").next().show().addClass("Selected");
});
here is a quick demo : http://jsbin.com/oduli4
var width = 500;
var height = 250;
var slide = 0;
var speed = 500;
var size = 0;
$(document).ready(function() {
size = $('#slider').find('li').length;
$('#slider').find('ul').width(width * size).height(height);
$('#slider li, #slider img').width(width).height(height);
$('#next').bind('click',function() {
if(slide > img_width * (size - 1) *(-1)) {
slide -= width;
slider(slide);
}
});
$('#prev').bind('click',function() {
if(slide < 0) {
slide += width;
slider(slide);
}
});
});
function slider(slideMargin) {
$('#slider ul').stop().animate({'left':slideMargin}, speed );
}

jQuery Carousel. How to show the Next or Previous Element only

I have a jQuery problem, and I've really tried everything I know (i am so newbie at this) so ..
The problem in short is I am doing a simple carousel-like effect. I am using this code.
(The div .showarea is the DIV which needs to be rotated (next/prev) but I want to keep only one div shown at a time.)
This is the html markup.
<div class="maincarousel">
<div class="showarea"><img src="img/sampleshow.png" alt="" title="" /></div>
<div class="showarea"><img src="img/sampleshow2.png" alt="" title="" /></div>
<div class="showarea"><img src="img/sampleshow3.png" alt="" title="" /></div>
</div>
This is my jquery attempt
$('.showarea').hide();
$('.showarea:first').fadeIn(500);
$('.maincarousel a').click(function () {
if ($(this).attr('href') == '#carouselNext') {
$('.showarea').hide();
$('.showarea').next('.showarea').fadeIn(500);
}
if ($(this).attr('href') == '#carouselPrev') {
$('.showarea').hide();
$('.showarea').prev('.showarea').fadeIn(500);
}
});
Unfortunately, next() and prev() won't display the next element only, but all next elements and same thing for prev(). Any quick workaround..
Can someone help me on this,
Thanks
You could try using .eq(0) to select the first element in the collection given to you by .prev() and .next().
Note that .next() and .prev(), like most jQuery methods, are operating on a collection. So if your selector '.showarea' is selecting multiple elements, then .next() will select the next sibling element for each element selected by '.showarea', and similarly for .prev().
if ($(this).attr('href') == '#carouselNext') {
$('.showarea').hide();
var el = $('.showarea').next('.showarea').eq(0);
if (el.length) {
el.fadeIn(500);
}
}
if ($(this).attr('href') == '#carouselPrev') {
$('.showarea').hide();
var el = $('.showarea').prev('.showarea').eq(0);
if (el.length) {
el.fadeIn(500);
}
}
The below will rotate so if you are at the first item pressing back will then show the last item...
Demo here
$('div.showarea').fadeOut(0);
$('div.showarea:first').fadeIn(500);
$('a.leftarrow, a.rightarrow').click( function (ev) {
//prevent browser jumping to top
ev.preventDefault();
//get current visible item
var $visibleItem = $('div.showarea:visible');
//get total item count
var total = $('div.showarea').length;
//get index of current visible item
var index = $visibleItem.prevAll().length;
//if we click next increment current index, else decrease index
$(this).attr('href') === '#carouselNext' ? index++ : index--;
//if we are now past the beginning or end show the last or first item
if (index === -1){
index = total-1;
}
if (index === total){
index = 0
}
//hide current show item
$visibleItem.hide();
//fade in the relevant item
$('div.showarea:eq(' + index + ')').fadeIn(500);
});

Categories