1

I've written some code for a simple popup feature for a website and have managed to make it work as long as I'm individually specifying the array index of each popup box, however this requires me to manually duplicating the code for each array index. See below:

/* POP UP BOXES */ 
var services = document.querySelectorAll('.service-box');
var popUps = document.querySelectorAll('.popup-box')
var closePopUp = document.querySelectorAll('.close');
var shadow = document.getElementById('shadow');

// open first popup
services[0].addEventListener('click', () => {
    popUps[0].style.display = 'block';
    shadow.style.display = 'block';
});
// open second popup
services[1].addEventListener('click', () => {
    popUps[1].style.display = 'block';
    shadow.style.display = 'block';
});
// open third popup
services[2].addEventListener('click', () => {
    popUps[2].style.display = 'block';
    shadow.style.display = 'block';
});
// close first popup
closePopUp[0].addEventListener('click', () => {
    popUps[0].style.display = 'none';
    shadow.style.display = 'none';
});
// close second popup
closePopUp[1].addEventListener('click', () => {
    popUps[1].style.display = 'none';
    shadow.style.display = 'none';
});
// close third popup
closePopUp[2].addEventListener('click', () => {
    popUps[2].style.display = 'none';
    shadow.style.display = 'none';
});
/* END POP UP BOXES*/

I was thinking that there must be a way combine all of the event listeners which i've added to to the array indexes into a single event listener, which is dependent to the index of the element clicked. I haven't been able to come up with anything more elegant than this on my own, so was after some help. I'm still very new to javascript so any assistance would be appreciated.

HTML is as follows (ignore the placeholder text)

<div class="section-inside">
  <div class="service-box web-dev">
    <img src="img/code.png" alt="Web Development Icon">
    <h4>Web Development</h4>
    <p>Build your brand new website from scratch, expertly tailored to the needs of your business. </p>
    <span>Find out more</span>
  </div>

  <div id="web-dev" class="popup-box">
    <h2>Web Development</h2>
    <p>
      Scuttle rigging scurvy cog lee nipper Letter of Marque transom Buccaneer Privateer. 
      Chain Shot ho Letter of Marque hornswaggle booty fathom jack bounty maroon Barbary Coast. 
      Nipperkin Barbary Coast measured fer yer chains blow the man down Letter of Marque 
      smartly splice the main brace furl parley starboard.
    </p>
    <span class="close">&times;</span>
  </div>

  <div class="service-box cro">
    <img src="img/optimisation.png" alt="Coversion Rate Optimisation Icon">
    <h4>Conversion Rate Optimisation</h4>
    <p>Fine-tune your website to guide traffic in the right direction to help you deliver your goals.</p>
    <span>Find out more</span>
  </div>

  <div id="cro" class="popup-box">
    <h2>Conversion Rate Optimisation</h2>
    <p>
      Scuttle rigging scurvy cog lee nipper Letter of Marque transom Buccaneer Privateer. 
      Chain Shot ho Letter of Marque hornswaggle booty fathom jack bounty maroon Barbary Coast. 
      Nipperkin Barbary Coast measured fer yer chains blow the man down Letter of Marque 
      smartly splice the main brace furl parley starboard.
    </p>
    <span class="close">&times;</span>
  </div>
  
  <div class="service-box analytics">
    <img src="img/analytics.png" alt="Analytics Icon">
    <h4>Analytics</h4>
    <p>Set up systems to analyse and understand the activity of users reaching your website.</p>
    <span>Find out more</span>
  </div>

  <div id="analytics" class="popup-box"> 
    <h2>Analytics</h2>
    <p>
      Scuttle rigging scurvy cog lee nipper Letter of Marque transom Buccaneer Privateer. 
      Chain Shot ho Letter of Marque hornswaggle booty fathom jack bounty maroon Barbary Coast. 
      Nipperkin Barbary Coast measured fer yer chains blow the man down Letter of Marque 
      smartly splice the main brace furl parley starboard.
    </p>
    <span class="close">&times;</span>
  </div>
</div>
Orlyyn
  • 2,296
  • 2
  • 20
  • 32
Wilgadamus
  • 13
  • 3
  • There is a way for sure but the exact code would depend on your HTML structure therefore you should post your HTML code as well. ;) – secan Oct 01 '20 at 14:33
  • 1
    `index()` in jQuery is seemingly the answer to you question. I just looked up if there was a javascript alternative. There is a post here: https://stackoverflow.com/questions/13658021/jquery-index-in-vanilla-javascript Please have a look and let us know if this answers your problem, in which case I/we will mark this question a duplicate – ControlAltDel Oct 01 '20 at 14:33

2 Answers2

2

I don't know your exact HTML, but i guess you could use forEach and closures.

e.g.

const services = document.querySelectorAll('.service-box');
const popUps = document.querySelectorAll('.popup-box');
const closePopUps = document.querySelectorAll('.close');

services.forEach((service, index) => {
  service.addEventListener('click', () => {
    popUps[index].style.display = 'block';
  });
});

closePopUps.forEach((closePopUp, index) => {
  closePopUp.addEventListener('click', () => {
    popUps[index].style.display = 'none';
  });
});

edit:

I added a second forEach to match your HTML. Check out here: JSFiddle

FelHa
  • 1,043
  • 11
  • 24
  • Apologies for not adding the HTML, i've updated the post now. The forEach method does look like what I'm looking for, but I can seem to get it to work. Should it live within the event listener, so that the click can trigger the function? – Wilgadamus Oct 01 '20 at 15:04
1
       const services = document.querySelectorAll('.service-box');
        const popUps = document.querySelectorAll('.popup-box');
        let index;
    // converting nodelist to array
    
        const servicesArray = Array.prototype.slice.call(services);
        const popUpsArray = Array.prototype.slice.call(popUps);
// attaching eventlisteners to services
            for(let i = 0; i < servicesArray.length; i++) {
                
                servicesArray[i].addEventListener('click', function() {
                    // get index of current service which is clicked
                    index = servicesArray.indexOf(this);
                    // checking if popUp of same index as services is block if so change it to none
                    if(popUpsArray[index].style.display === 'block') {
                    popUpsArray[index].style.display = 'none';
                    }
                    else {
                        // checking if any previous popUp is block so change it to none
                        for(let i = 0; i < popUpsArray.length; i++) {
                            if(popUps[i].style.display === 'block') {
                                popUpsArray[i].style.display = 'none';
                            };
                        };
                        popUps[index].style.display = 'block';   
                    }
                });
            };