Kevin Lehtla
Kevin Lehtla

Reputation: 21

For each loop for menu links that affect other div

i am trying to understand how to make this code into a loop so I wouldn't have to copy the part where $('.popup-[insert nr]').click every time in the future a new menu link is made for navigation. This code is in the purpose of: Click a link, toggle or add a class of show to a hidden div and if any other link is clicked after that every shown div will be hidden.

var popContent = $('.popup-1-content');
var popContent2 = $('.popup-2-content');
var popContent3 = $('.popup-3-content');
var popContent4 = $('.popup-4-content');

var popupArray = [popContent, popContent2, popContent3, popContent4];

$('.popup-1').click(function () {

    if ( popContent.hasClass("show") ) {
        popContent.removeClass("show");
    } else {
        for (var i = 0; i < popupArray.length; i++) {
           popupArray[i].removeClass("show");
        }
        popContent.addClass("show");
    }
    return false;
});

$('.popup-2').click(function () {

    if (popContent2.hasClass("show") ) {
        popContent2.removeClass("show");
    } else {
        for (var i = 0; i < popupArray.length; i++) {
           popupArray[i].removeClass("show");
        }
        popContent2.addClass("show");
    }
    return false;
});


$('.close-popup a').click(function(){
$('.popup-content').toggleClass('hide').removeClass('show');
return false;
});

Upvotes: 2

Views: 658

Answers (5)

zer00ne
zer00ne

Reputation: 44078

Update

"...i tried your code but it needs to be edited so it wouldn't target divs below the link as the divs are located in random parts of the page. "

The updated demo addresses previously mentioned issue by adding a data-* attribute to each link. Once a link is clicked, it locates the nth div.pop by matching its data-idx with a .pop's indexed position by using .eq() method. The following example does not function as is, it is merely the relevant parts with emphasis on the index number to show the correlation between the 2 values.

<a href='#/' class='lnk' data-idx='3'>POP3</a>

$('.pop').eq(3).addClass('show')

The following is the core code without the extra utilities or comments, condensed and chained.

$('.lnk').on('click', function() {
  var idx = $(this).data('idx');
  $('.pop').removeClass('show').eq(idx).addClass('show');
});

 <a href='#/' class='.lnk' data-idx='0'>POP0</a>

For the complete updated code, refer to the Demo below.


On any automated or manually controlled groups of elements (ex. slider) that alternate in states (ex. hide and show), the easiest way to control the flow is to hide all elements and then show the currently active element.

Details commented in Demo

Demo

/* This is just to space the links apart. Upadted to provide
|| random location for .lnk's
*/
$('a.lnk').each(function(idx, a) {
  var ran = getRandom(1, 60);
  a.style.top = (idx * ran) + 'px';
  a.style.left = (idx * ran) + 'px';
});

// Click any a.lnk...
$('a.lnk').on('click', function() {

  // Reference the div.pop the clicked link belongs to

  /* The next statement works if each popup was positioned after
  || a corresponding link. It is commented out in leiu of the 
  || uncommented statement that follows this statement.
  */ // var pop = $(this).next('div.pop');

  // Get the clicked link's data-idx number
  var idx = $(this).data('idx');

  // Gather all .pop
  var pop = $('.pop');

  // ALL .pop remove class .slow
  pop.removeClass('show');

  /* .pop will open. The specific .pop that corresponds with the
  || clicked link is determined by matching the .pop's current
  || indexed position with that of the indexed position of in     
  || $('.pop') by using the eq() method and passing data-idx
  */
  pop.eq(idx).addClass('show');

});

/* This function is not neccessary. Its purpose is to generate a
|| random number between min and max parameters (inclusive)
*/
function getRandom(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
a.lnk {
  display: inline-block;
  position: relative;
  z-index: 1;
  background:#000;
  color:gold;
  
}

.pop {
  display: none;
}

.pop.show {
  display: block;
  margin-top: 30px
}
<a href='#/' class='lnk' data-idx='0'>POP0</a>
<a href='#/' class='lnk' data-idx='1'>POP1</a>
<a href='#/' class='lnk' data-idx='2'>POP2</a>
<a href='#/' class='lnk' data-idx='3'>POP3</a>
<a href='#/' class='lnk' data-idx='4'>POP4</a>


<div class='pop'>
  <img src='https://i.imgur.com/ydfYXqh.jpg'>
  <header>POP0</header>
</div>


<div class='pop'>
  <img src='https://i.imgur.com/DrEwPH0.jpg'>
  <header>POP1</header>
</div>


<div class='pop'>
  <img src="https://i.imgur.com/AXUJEUS.jpg">
  <header>POP2</header>
</div>


<div class='pop'>
  <img src='https://i.imgur.com/MEPxbq4.jpg'>
  <header>POP3</header>
</div>


<div class='pop'>
  <img src='https://i.imgur.com/dp8G9Fr.jpg'>
  <header>POP4</header>
</div>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Upvotes: 1

zfrisch
zfrisch

Reputation: 8670

Grab all the popups using a better CSS selector. Then iterate over the list using jquery's each attaching a click handler to each one.

You're toggling a class manually but JQuery has toggleClass built in. Use that instead. In your case you stated that you wanted to remove the class from all other elements once one popup had its class changed, to do that we can use jquery's .not method which specifies to get all items except the item specified, then we just use removeClass to remove the class from those elements.

var popups = $('[class$="-content"]').filter('[class^="popup-"]');

popups.each(function(index, popup) {
  $(".popup-" + (index + 1)).click(function(e) {
    $(popup).toggleClass("show");
    popups.not(popup).removeClass("show");
  });
});

var popups = $('[class$="-content"]').filter('[class^="popup-"]');

popups.each(function(index, popup) {
  $(".popup-" + (index + 1)).click(function(e) {
    $(popup).toggleClass("show");
    popups.not(popup).removeClass("show");
  });
});
.show {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="popup-1">toggle 1</button>
<button class="popup-2">toggle 2</button>
<button class="popup-3">toggle 3</button>
<button class="popup-4">toggle 4</button>

<div class="popup-1-content">1</div>
<div class="popup-2-content">2</div>
<div class="popup-3-content">3</div>
<div class="popup-4-content">4</div>

Upvotes: 0

alanfcm
alanfcm

Reputation: 78

Without looking at your HTML structure is hard, but the idea is to create a loop for each link and replace the numbers with an index variable like this:

$.each('a', function(i, link) {
    $('.popup-' + i).click(function () {

        $('div').removeClass("show");
        $(this).parent.addClass("show");

        return false;
    });
});

Upvotes: 1

msorce
msorce

Reputation: 31

Add a common class.

<!-- Added a common class popup-content -->
<div class=".popup-1-content popup-content">...<div>

select the common class when adding the event handlers, refer to $(this), assuming you are using jQuery, to get the instance where the event occurs (specific element clicked) this can also be captured with event.target in vanilla js when passing it into your callback function handling the event.

ex jQuery:

$('.popup-content').on('click', function(){
    // Check if already open, early exit
    if ($(this).hasClass('show')) return;
    // Close them all
    $('.popup-content').removeClass('show')
    // Open the one being clicked
    $(this).addClass('show');
})

Another option is to use a wildcard selector

$('[class^="popup"]').on('click', function(){
    // Check if already open, early exit
    if ($(this).hasClass('show')) return;
    // Close them all
    $('[class^="popup"]').removeClass('show');
    // Open the one being clicked
    $(this).addClass('show');
})
p {
  display: none;
  border: solid 1px black;
}

.show p {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="popup-content-1">
  1
<p>hidden content 1</p>
</div>
<div class="popup-content">
  2
<p>hidden content 2</p>
</div>

Upvotes: 0

yvoytovych
yvoytovych

Reputation: 871

Using selector attribute (starts with) you can select all popups, and based on popup class name, hide or show its content. This way you can add as many popups as you wish.

<button class="popup-1">1</button>
<span class="content-popup-1">First</span>

$("[class^=popup]").click(function() {
    $(".content-" + this.className).toggleClass('hide');
});

Working example here: https://jsfiddle.net/e9qep53w/

More about query selectors here https://api.jquery.com/category/selectors/

Upvotes: 0

Related Questions