JavaScript Portfolio - click event only working on 1 button

I’m confused as to why my click event only works once. I’ve got two buttons and the click event only fires on the Portfolio One section, and not the Portfolio Two section. Please help?!

JavaScript:

let downButton = document.getElementById('down-button');
let upButton = document.getElementById('up-button');
let projectWindow = document.getElementById('project-window');

function expand() {
    downButton.style.display = 'none';
    projectWindow.style.display = 'block';
    upButton.style.display = 'block';
};

function hide() {
    downButton.style.display = 'block';
    projectWindow.style.display = 'none';
    upButton.style.display = 'none';
};

downButton.addEventListener('click', expand); 
upButton.addEventListener('click', hide);

HTML:

    <section id="portfolio" class="container border">
        
        <section id="project-block" class="border">
        
            <button id="down-button" class="project-heading border">Project One</button>
            <button id="up-button" class="project-heading border">Project One</button>
            <section id="project-window">
                <img src="websiteScreenshot.jpeg" width="600" height="auto"/>
            </section>

        </section>

        <section id="project-block" class="border">
        
            <button id="down-button" class="project-heading border">Project Two</button>
            <button id="up-button" class="project-heading border">Project Two</button>
            <section id="project-window">
                <img src="websiteScreenshot.jpeg" width="600" height="auto"/>
            </section>

        </section>

    </section>

Hi, there!

The way the code is setup, it will only run once.

When you have multiple buttons that will use the same function, you need to select them all with querySelectorAll()

However, an id is supposed to be unique to one element. I can see multiple elements with the same id which is invalid HTML. It would be best to switch them over to classes.

The querySelector would then look like

let downButtons = document.querySelectorAll('.down-button');
let upButtons = document.querySelectorAll('.up-button');

With the addEventListener looking like

downButtons.forEach((button) => {
  button.addEventListener('click', expand);
});

upButtons.forEach((button) => {
  button.addEventListener('click', hide);
});

I am not the best with JavaScript. If this is a slider to hide and show each project, I would do it with CSS because it’s easier for me. Or create a separate function for each image. But, if you want them all to have the same class, you’ll need to do some funky JavaScript magic with parentNode selectors to make sure the buttons are only affecting their siblings. Perhaps there is an easier way to achieve this and a JavaScript guru could enlighten us both.

Nonetheless, this is what I would do:

function expand(event) {
    const clickedButton = event.target; //Targets the button that was clicked
    const parentBlock = clickedButton.parentNode; //Gets the parent block element of the button
    const projectWindow = parentBlock.querySelector('.project-window');
    // projectWindow is set to the sibling image container of the button

    clickedButton.style.display = 'none';
    projectWindow.style.display = 'block';
    parentBlock.querySelector('.up-button').style.display = 'block';
    //This makes sure that only the sibling button is affected
}

The hide function would just be the opposite. Output then looks like:

Project 1 showing; 2 hidden

Project 2 showing, 1 hidden
image

2 Likes

Are you just trying to have a button for two different images that close and open them?

Thank you for your response. I’ve tried to implement your solution with a few changes and I don’t think the Event Listeners are working in the HTML.

I created a new Topic with all the updated code: