1

I've a couple div that allow you to hover over #HoverMe in order to see contents in #hidden div(that's hidden when un-hovered). If the list is a bit to long, it's scrollable. However, I can't scroll it while I'm hovering #HoverMe div. If I want to scroll #Hidden div, then I've to move, which result it disappearing again(obviously).

I would like to be able to hover #HoverMe and have lke 5 seconds to move to #hidden. If you hover #hidden before disappearing, it will stop the hide timer and be able to scroll and check the contents.

A possible worse alternative solution:

scroll #Hiddendiv while mouse is at #HoverMe?

How it looks like:

                      ------------     --------- _
                     |  #HoverMe   |  | #hidden |S|                           
                      ------------    | --------|R|
                                      | car.name|O|       
                                      |---------|L|
                                      | car.name|L|
                                       ---------|B|
                                      | car.name|A|
                                      |---------|R|
                                      | car.name| |
                                       ---------|_|

Code:

<div>
    <div id="HoverMe" style="width: 100px; background: green">
        Car
    </div>
    <div id="hidden" style="overflow:auto; height:100px; position: absolute; background-color: red; display: none">

        @foreach (var car in Model.Car) { @* Where the #hidden list get its content *@
            <div>@car.Name</div>
       }

    </div>
</div>


<script>
    var hoverEle = document.getElementById("HoverMe");
    var popupEle = document.getElementById("hidden");

    hoverEle.addEventListener('mouseover', function () {
        var hoverRect = hoverEle.getBoundingClientRect(); // get the position of the hover element
        popupEle.style.left = (hoverRect.right + 16) + "px";
        popupEle.style.top = hoverRect.top + "px";
        popupEle.style.display = "block";

    }, false);

    hoverEle.addEventListener('mouseout', function () {
        popupEle.style.display = "none";
    }, false);
</script>
Nyprez
  • 306
  • 4
  • 18

2 Answers2

2

(BTW, this question is labelled as jQuery but you're actually using just vanilla JS! No problem, of course, just letting you know!)

You're on the right track, for sure. I think you could probably handle it with setting a timeout and clearing it.

<div>
    <div id="HoverMe" style="width: 100px; background: green">
        Car
    </div>
    <div id="hidden" style="overflow:auto; height:100px; position: absolute; background-color: red; display: none">

        @foreach (var car in Model.Car) { @* Where the #hidden list get its content *@
            <div>@car.Name</div>
       }

    </div>
</div>


<script>
    var hoverEle = document.getElementById("HoverMe");
    var popupEle = document.getElementById("hidden");
    var timeoutId;

    function showPopup() {
        var hoverRect = hoverEle.getBoundingClientRect(); // get the position of the hover element
        popupEle.style.left = (hoverRect.right + 16) + "px";
        popupEle.style.top = hoverRect.top + "px";
        popupEle.style.display = "block";
    }

    function hidePopup() {
        popupEle.style.display = "none";
    }

    hoverEle.addEventListener('mouseover', function () {
        showPopup();
    }, false);

    hoverEle.addEventListener('mouseout', function () {
        timeoutId = window.setTimeout(function () {
            hidePopup(); 
        }, 5000);
    }, false);

    popupEle.addEventListener('mouseover', function () {
        if (timeoutId) {
            window.clearTimeout(timeoutId);
        }
    }, false);

    popEle.addEventListener('mouseout', function () {
        hidePopup();
    }, false);

</script>
Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
  • Thanks! Oh I really thought this was JQuery. I removed the label JQuery :) – Nyprez Oct 09 '16 at 03:14
  • off-question, but do you know any good guide how I can customize scrollbar? I couldn't find any bootstrap or related solution – Nyprez Oct 09 '16 at 03:25
  • 1
    No problem! If you're not aware, [jQuery](https://jquery.com/) is a library that attempts to add some nice extensions to Javascript and also handle cross-browser support. It's a great tool, but vanilla JS skills are also very valuable so don't feel like you _need_ to use it. – Alexander Nied Oct 09 '16 at 03:30
  • 1
    As for custom scrollbars, there's a StackOverflow [here](http://stackoverflow.com/questions/9251354/css-customized-scroll-bar-in-div) that nicely outlines what is achievable with CSS-- beyond that, you probably need a Javascript/jQuery option-- check this StackOverflow [here](http://stackoverflow.com/questions/9945547/how-to-create-a-custom-scrollbar-on-a-div-facebook-style) for some jumping off points. – Alexander Nied Oct 09 '16 at 03:31
  • Hmm, I'm having a hard time trying to convert this JS to JQuery. After some reading I think JQuery is the way to go, "write less, do more". Any chance you could provide additional JQuery solution? I will add a new question – Nyprez Oct 09 '16 at 05:25
  • If you post another question, I'll try to keep an eye out and answer it, sure. But I can give you a few pointers right here, as nicely as the comment formatting will allow: 1) Elements can be selected with CSS selectors -- ex `$('#myId')` 2) Use the `.on` method to add event listeners 3) Styles can be set using the `.css` method 4) Simple hiding/showing can be done with the `.hide` and `.show` methods || Oh, and my favorite jQuery cheatsheet site, if you're looking for a quick reference is https://oscarotero.com/jquery/ . – Alexander Nied Oct 09 '16 at 05:31
  • Ah I posted it [already](http://stackoverflow.com/questions/39940373/how-to-convert-following-js-to-jquery?noredirect=1#comment67161922_39940373). Thanks for the valuable tips! I'm looking into that right now :) **Edit:** That's a really good cheatsheet! – Nyprez Oct 09 '16 at 05:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/125265/discussion-between-nyprez-and-anied). – Nyprez Oct 09 '16 at 06:07
1

You can schedule the hiding action instead of instantly hiding your popover on mouseout of your trigger or popover elements using setTimeout and cancel it when you hover on your trigger or popover again.

window.onload = function () {
  var triggerEl = document.querySelector('.trigger');
  var popoverEl = document.querySelector('.popover');
  
  var hideTimer = null;
  
  triggerEl.addEventListener('mouseover', function () {
    showPopover();
  }, false);

  triggerEl.addEventListener('mouseout', function () {
    scheduleHidingPopover();
  }, false);
  
  popoverEl.addEventListener('mouseover', function () {
    cancelHidingPopover();
  }, false);
  
  popoverEl.addEventListener('mouseout', function () {
    scheduleHidingPopover();
  }, false);

  function showPopover() {
    cancelHidingPopover();
    popoverEl.classList.remove("hidden");
  }
  
  function hidePopover() {
    cancelHidingPopover();
    popoverEl.classList.add("hidden");
  }

  function scheduleHidingPopover() {
    cancelHidingPopover();
    hideTimer = setTimeout(function () {
      hidePopover();
      hideTimer = null;
    }, 1000);
  }
  
  function cancelHidingPopover() {
    if (hideTimer) {
      clearTimeout(hideTimer);
      hideTimer = null;
    }
  }

};
.trigger {
  display: inline-block;
  vertical-align: top;
  background-color: #eef;
}
.popover {
  display: inline-block;
  vertical-align: top;
  background-color: #fee;
  max-height: 100px;
  overflow: auto;
}
.hidden {
  display: none !important;
}
<div class="trigger">Hover over me</div>
<div class="popover hidden">
  I will pop over.<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
</div>

The jQuery version:

$(function () {
  var $triggerEl = $('.trigger');
  var $popoverEl = $('.popover');
  
  var hideTimer = null;
  
  $triggerEl.on('mouseover', function () {
    showPopover();
  });

  $triggerEl.on('mouseout', function () {
    scheduleHidingPopover();
  });
  
  $popoverEl.on('mouseover', function () {
    cancelHidingPopover();
  });
  
  $popoverEl.on('mouseout', function () {
    scheduleHidingPopover();
  });

  function showPopover() {
    cancelHidingPopover();
    $popoverEl.removeClass("hidden");
  }
  
  function hidePopover() {
    cancelHidingPopover();
    $popoverEl.addClass("hidden");
  }

  function scheduleHidingPopover() {
    cancelHidingPopover();
    hideTimer = setTimeout(function () {
      hidePopover();
      hideTimer = null;
    }, 1000);
  }
  
  function cancelHidingPopover() {
    if (hideTimer) {
      clearTimeout(hideTimer);
      hideTimer = null;
    }
  }

});
.trigger {
  display: inline-block;
  vertical-align: top;
  background-color: #eef;
}
.popover {
  display: inline-block;
  vertical-align: top;
  background-color: #fee;
  max-height: 100px;
  overflow: auto;
}
.hidden {
  display: none !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="trigger">Hover over me</div>
<div class="popover hidden">
  I will pop over.<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
  Lorem ipsum<br>
</div>

Note that not so many things changed. The variables were prefixed with $ sign just to clear that they are not DOM elements anymore (as in Vanilla JS example) but jQuery wrappers. The power of jQuery is brevity, convinience (you can do more things with JQuery wrappers than with DOM elements) and smoothing browser incompatabilities (this factor is less important now, than 10 years ago when jQuery rised).

Ruslan Stelmachenko
  • 4,987
  • 2
  • 36
  • 51