0

I am still fairly new to JS, and I am trying to replace the HTML of a div with a picture that is being moused over, and when the mouse leaves I want it to return to it's normal state. I thought that I did everything right but my code doesn't seem to be working. I've looked through stack overflow and I see a lot of jQuery solutions to my 'problem,' but I would like an answer in pure JavaScript (I'm trying to "maser" this first), along with an explanation so I can understand why the answer IS the answer. Thanks.

I'll try to explain myself (my code). I grabbed reference to the image holder, and I grabbed reference to the the images. I thought I made a function that looped through the array of images and added an event listener to whichever image ( image[i] ) was being moused over. Then, I added an event listener that is supposed to return the image holder to it's default state by inserting the original HTML. I just don't understand how to fix this.

var holder = document.getElementById('holder');
var images = document.getElementsByTagName('img');

var popImage = function () {
    for (i = 0; i < images.length; i++) {
        images[i].addEventListener('mouseover', = function () {
            holder.innerHTML = images[i];
        });
        images[i].addEventListener('mouseout', function () {
            holder.innerHTML = 
                '<div class='col-md-3 img-fluid' id='img1'><img src='photo1.jpg'></div>
                <div class='col-md-3 img-fluid' id='img2'><img src='photo2.jpg'></div>
                <div class='col-md-3 img-fluid' id='img3'><img src='photo3.2.jpg'></div>
                <div class='col-md-3 img-fluid' id='img4'><img src='photo4.jpg'></div>'
        });
    };
};

popImage();
  • Are you getting any console errors? In what way is the code not behaving as expected? Also, I think I see a syntax error on line 6: `'mouseover', = function () {` ... what's that equal sign doing there? – Alexander Nied Feb 28 '17 at 16:36
  • You have a number of syntax errors in this code. The equal sign in the addEventListener arguments, the single quotes are breaking the string being assigned to holder.innerHTML and HTML uses double quotes for properties. As has been said, you should look at the console and try to resolve any errors which arise in there. – Matt Feb 28 '17 at 16:44
  • @Yoda and anid thank you all. Quite sleepy. Can't believe I didn't catch the equal signs. They are there because I've been trying a variety of methods. – Rickie Knight Feb 28 '17 at 16:46
  • Also, you are creating functions inside of a loop. This will lead to unexpected behavior. See: [JavaScript closure inside loop](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Justin Taddei Feb 28 '17 at 16:48
  • @JustinTaddei Thank you. Perhaps that's it. – Rickie Knight Feb 28 '17 at 16:49
  • Are you doing this purely for the purposes of learning javascript? If not you could probably do this with CSS – Matt Feb 28 '17 at 16:51
  • @EricaKnight it's one of those gotcha's that will get you almost every time. – Justin Taddei Feb 28 '17 at 16:52
  • As @Yoda said if this it for production you should use CSS instead. I'll post an answer describing how to do that. – Justin Taddei Feb 28 '17 at 16:54
  • Thank you all, and yeah. I thought about that right before posting here. You know, that perhaps I could use CSS. I am trying to learn JS, though. I've been working at it for about 8 months, 3 months consistently. And, I feel like I should be further along than I am. – Rickie Knight Feb 28 '17 at 17:23
  • @EricaKnight [W3Schools](https://www.w3schools.com/) is an amazing, free learning resource for all things web. You should take a look at it. – Justin Taddei Feb 28 '17 at 17:34
  • @JustinTaddei Lol, I use it from time to time but I heard that there is a lot of misinformation on there so I try to stick to MDN. – Rickie Knight Feb 28 '17 at 23:02
  • @EricaKnight I've heard that too, but I haven't seen any myself. MDN is great also, though. (but I've actually found misinformation on MDN, lol). – Justin Taddei Feb 28 '17 at 23:08
  • Anyway, glad I could help. – Justin Taddei Feb 28 '17 at 23:10

2 Answers2

0

You said you are new to JS and just learning which is great but an important part of learning JS is learning when not to use it. As @Yoda said if this was for production you really should use CSS instead of JS.

Here is one way you could accomplish this with pure CSS

<style>
   .img {
      width: 100px;
      height: 100px;
      background: #bada55;
      border: 2px solid #333;
      float: left;
   }
   .holder:hover > .img {
      opacity: 0;
   }
   .holder:hover > .img:hover {
      opacity: 1;
   }
</style>

<div class="holder">
  <!-- Using div.img for simplicity, these whould be your <img/> tags -->
  <div class="img">1</div>
  <div class="img">2</div>
  <div class="img">3</div>
  <div class="img">4</div>
</div>

For the purpose of learning, here's how you'd do it in JS:

var holder = document.getElementById('holder');
var images = document.querySelectorAll('.img');
var filter = false;
function popImage () {
    // Use for (var i = 0 . . .
    // Instead of for (i = 0 . . .
    // Because without var, i will be stored in the global scope
    for (var i = 0; i < images.length; i++) {
        (function (_i) {
            images[_i].addEventListener('mouseover', function () {
                holder.innerHTML = '';
                // We can't set innerHTML to images[_i]
                // because it's a DomNode not a string
                holder.appendChild(images[_i]);
            });
        })(i);
    }
    holder.addEventListener('mouseout', function (e) {
        if (e.target !== holder)
          return;
          
        holder.innerHTML = '';
        // Again, use var j = 0 . . .
        for (var j = 0; j < images.length; j++) {
          holder.appendChild(images[j]);
        }
    });
}

popImage();
.img {
  width: 100px;
  height: 100px;
  background: #bada55;
  border: 2px solid #333;
  display: inline-block;
}
#holder {
position: relative;
  width: 100%;// So doesn't collape and trigger mouseout
  height: 100px;
  background: red;
  padding: 20px 0;
}
<div id="holder">
  <!-- Again, these would be your image tags -->
  <div class="img">1</div>
  <div class="img">2</div>
  <div class="img">3</div>
  <div class="img">4</div>
</div>
Justin Taddei
  • 2,142
  • 1
  • 16
  • 30
  • Thank you. Works like a charm. Will take that into consideration the next time I'm approaching a problem. – Rickie Knight Feb 28 '17 at 17:29
  • @EricaKnight I edited the answer to show the JS equivalent. – Justin Taddei Feb 28 '17 at 18:16
  • And as @Yoda mentioned, you hide the images with a class instead of removing them altogether. But that's how you were doing it so I stuck to that in the example. – Justin Taddei Feb 28 '17 at 18:20
  • Thank you all! I appreciate it. I will definitely remember this in the future. – Rickie Knight Feb 28 '17 at 22:59
  • @EricaKnight W3Schools has a great list of [common mistakes](https://www.w3schools.com/js/js_mistakes.asp). – Justin Taddei Feb 28 '17 at 23:05
  • I don't know how to send DMs or if that's possible, but I wanted to ask you (all) something. I think I finally understand OOP. Okay, so to ME, if I am understanding correctly, Classes are the parameters from which Objects are made. You create objects with the parameters you've made in the class you are utilizing (to create said object). Is that correct? Also, thank you. I read that article. It was very helpful. – Rickie Knight Mar 06 '17 at 18:15
0

I had 10 mins before leaving work so I had a crack at this to see how I would do it and give you some ideas.

Here is my implementation (https://jsfiddle.net/hg7s1pyh/)

I guess the main thing here is that I've broken it down into lots of smaller parts, this makes solving problems far easier, each method is concerned with doing one thing only.

You will also note the use of classes to show and hide content rather than removing it entirely, this takes lots of the arduous work out of this feature.

function attachEvents() {
  var images = getImages();
  images.forEach(function(image) {
    attachMouseOverEvent(image);
    attachMouseLeaveEvent(image);
  });
}

function attachMouseOverEvent(element) {
  element.addEventListener('mouseover', function(e) {
    var clonedImage = e.target.cloneNode();
    addImageToPreview(clonedImage);
  });
}

function attachMouseLeaveEvent(element) {
  element.addEventListener('mouseleave', function(e) {
    removeImageFromPreview();
  });
}

function getImages() {
  return document.querySelectorAll('.js-image');
}

function getImagePreviewElement() {
  return document.querySelector('.js-image-box');
}

function addImageToPreview(imageElement) {
  var previewElement = getImagePreviewElement();
  previewElement.classList.add('previewing');
  previewElement.appendChild(imageElement);
}

function removeImageFromPreview() {
  var previewElement = getImagePreviewElement();
  previewElement.classList.remove('previewing');
  var image = previewElement.querySelector('.js-image');
  image.remove();
}

attachEvents();
.image-box {
position: relative;
min-height: 400px;
width: 400px;
border: 1px solid #000;
text-align: center;
}
.image-box .placeholder {
position: absolute;
top: 50%;
text-align: center;
transform: translateY(-50%);
width: 100%;
}
.image-box.previewing .placeholder {
display: none;
}
.image-box .image {
position: absolute;
top: 50%;
text-align: center;
transform: translate(-50%, -50%);
height: 100%;
width: 100%;
}
.images {
margin-top: 10px;
}
<div class="js-image-box image-box">
  <div class="placeholder">
Placeholder
  </div>
</div>
<div class="images">
  <div class="col-md-3 img-fluid"><img class="js-image image" src="http://placehold.it/350x150"></div>
  <div class="col-md-3 img-fluid"><img class="js-image image" src="http://placehold.it/150x150"></div>
  <div class="col-md-3 img-fluid"><img class="js-image image" src="http://placehold.it/400x400"></div>
  <div class="col-md-3 img-fluid"><img class="js-image image" src="http://placehold.it/350x150"></div>
</div>
Matt
  • 4,107
  • 3
  • 29
  • 38