'back and forth between nodes in vanilla javascript

I'm expanding a site (menright.com) that displays about fifty years of photos. This link goes to the first photo page: (https://menright.com/pages/photoPages/photos-1967.php). Each photo is followed by a caption, and there is a button that allows the viewer to see a longer description that replaces the caption. The button isn't working here but allows you to see what I'm talking about.

To implement this I have an img (the button) inside of a p tag (the caption). Clicking the button substitutes the longer description drawn from the alt and the title in a second img (the picture) immediately above the caption.

I can't use IDs since there are many captions and pictures on each page.

Here is the HTML skeleton of the significant parts of the problem:

<img alt='long description' title='location image taken' />
<p class='the caption'> <img class='get long description button' /> </p>

I'm thinking I have to find the node of the target (the button), track its parent (the caption), and then get the alt and title from something like a previousSibling (the picture) and use the innerHTML of the parent (the caption) to display the long description.

Am I correct in this assumption, or is there another way to do this? And if this is the technique I need to use, how do I do it? I'm totally new to using nodes in my vanilla Javascript, and I don't want to add JSquery or other libraries to my pages.

This is my first post here, though I've used the site for years. Thanks for any help you might provide!



Solution 1:[1]

I'm thinking I have to find the node of the target (the button), track its parent (the caption), and then get the alt and title from something like a previousSibling (the picture) and use the innerHTML of the parent (the caption) to display the long description.

Am I correct in this assumption, or is there another way to do this?

If you stick to that structure, yes, that's what you'd do (probably previousElementSibling so you don't have to worry about intervening Text nodes), and setting textContent rather than innerHTML unless you want < and & in the text to be interpreted as HTML. You'd probably do it via event delegation on whatever container has all of these in it (body, if there's nothing nearer):

theContainer.addEventListener("click", event => {
    const btn = event.target.closest(".get.long.description.button");
    if (btn && theContainer.contains(btn)) {
        const p = btn.parentElement;
        const alt = p.previousElementSibling?.alt;
        if (alt) {
            p.textContent = alt; // `textContent` assuming you don't have tags
        }
    }
});

But if you can wrap all of that in an element:

<div class="wrapper">
    <img alt='long description' title='location image taken' />
    <p class='the caption'>
        <img class='get long description button' />
    </p>
</div>

...you can make it more robust:

theContainer.addEventListener("click", event => {
    const wrapper = event.target.closest(".container");
    if (wrapper && theContainer.contains(wrapper)) {
        const p = wrapper.querySelector(".the.caption");
        const alt = wrapper.querySelector(".location.image.taken")?.alt;
        if (alt) {
            p.textContent = alt; // `textContent` assuming you don't have tags
        }
    }
});

That doesn't rely on the exact relationship between the elements, just that they're all in the same container, so you can move them around as the page design evolves without changing your code.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 T.J. Crowder