Vanilla JS DOM event question

Hi there,

I’m working on the last responsive design certificate project. I would like to create a certain functionality via vanilla JS.

What I would like to achieve is this: if you hover over “element 1” then “picture A” will show up at X position, you hover over “element 2” and “picture B” will show up at the same X position. On a sidenote, I know this is possible via CSS, however it would require me to reorganise my containers and I wanted to use some JS anyway to practice.

I have found a solution to this:

anchorTribute.addEventListener('mouseover', () => {
    previewTribute.classList.toggle('preview-animation');
});

anchorTribute.addEventListener('mouseout', () => {
    previewTribute.classList.toggle('preview-animation');
});

This piece of code works perfectly for me, however I would need to apply to each and every one of them almost the same exact code. What I’ve deduced so far in the JS course is that whenever you start to repeat or use an almost identical piece of code, there’s a possibility that you can do it “simpler” or at least arrive at a more complex solution with less code.

For example here’s this code:

anchorArr.forEach((element) => {
    element.addEventListener('mouseover', () => {
        previewArr.forEach((styling) => {
            styling.classList.toggle('preview-animation');
        })
    });
    element.addEventListener('mouseout', () => {
        previewArr.forEach((styling) => {
            styling.classList.toggle('preview-animation');
        })
    });
});

While this code applies the intended functionality to the elements, it also triggers all the other elements (in my case “picture A, B, etc…”). I understand why this happens, so I tried to play around with the arrays, since it is structured in a way that anchorArr[0] is what needs to trigger previewArr[0].

I’ve tried a simple for loop, but it’s the same result. I’ve tried somehow pass the current index of anchorArr by using anchorArr.indexOf(element). I’ve tried with a console.log(), I can actually access it, however console says:

anchorArr.indexOf(…).classList is undefined

Then, I tried to create an empty array inside the function, pushing the current index number, then shifting on mouseout.

Uncaught TypeError: testArr.classList is undefined

I guess I just don’t have the necessary experience with JavaScript, but I’m at a point where I consider myself kind of obsessed with this problem. :slight_smile:

This is dead easy in D3 with tooltips like in the D3 projects, so you could look there for inspiration. It’s also easy with closures in React and so on for all the other frameworks.

Doing it manually, you need some way to differentiate the different elements you want to preview so that your preview function can programmatically decide what to display. The easiest way that comes to mind is to assign an id to each anchor that can be used to decide what to show in the preview (i.e. the <a id='cat'...> preview will display a div showing cat.png on mouseover, etc.).

1 Like

Thank you so much for you answer!

I’ll make sure to check out what you mentioned, although I might just use the first block of code then, because this might be out of the scope of my current knowledge, after all I’m only working on my responsive cert. I just wanted to avoid applying almost the same code for several different elements. This problem might be irrelevant in the future, because as you said there are easier solutions with a framework, and I can fix it later anyway! : )

Thank you again for taking your time to answer!

We might need a bit more context to really know how you are using the code. A live example would be nice.

One option is to make it data-driven instead. You might create an object of objects with the images and then give each hover item the same identifier as the object property from which you want the image. The identifier can be whatever you like, id/data attribute, or just the text content.

Simple example. It’s likely not applicable to your exact needs but it just shows what I’m talking about.

1 Like

I’ll try to implement this later, because I think this is exactly what I’m looking for. To be fair, using objects have never even crossed my mind, I guess I have a long way to go :slight_smile:

Thank your very much! I’ll make sure next time include a live example, it was my first time posting a coding related question.

Obviously I’ll update you what happened and mark yours as a solution, as soon as I had the time to get around this.

1 Like

The data-driven approach is often much simpler and also more manageable than relying too much on the DOM. It is an approach that can be used for many different solutions.

Take a todo list, it is much easier to use a data structure than to use the DOM as data storage. All the data manipulation happens using the data structure and then the DOM just reflects the data at any given time.

The less you have to rely on the DOM the better, as it can get messy really fast.

1 Like

Thanks for taking the time and effort to educate me on this. I’ll make sure to read about data-driven approach, sounds like a really useful and important concept.

Hi there! I’ve managed to implement it, it works beautifully, thank you very much for your help, I really appreciate it! If you’re interested, this is how I implemented it:

Looks good.

The basic idea here is a bit similar to what you might have used for some of the challenges in the JS curriculum. Some of them can be solved (DNA pairs, Convert HTML Entities) using an object to do a lookup (sometimes called a hash map/table). Here you get the key out of the DOM and use that to map to a value in an object.

1 Like