0

I have a flex container that contains several items that have the flex-grow property set to 1 and a certain max-width.

enter image description here

I want to add an event listener to the group of items, but I do not want the event to fire if the event location is in the empty space of the flex container. For example, for a click event, I want the event to fire only if the blue space of the image below is clicked.

enter image description here

If I add the event listener to the parent container, the event fires even if I click the purple. If I add the event listener to the child items, the event does not fire when if I click on the margins of the items. In addition, for events like onmouseenter or onmouseleave, the event fires 3 times if I move my mouse over all the items, whereas my desire is for it to only fire once.

Here is a snippet of the current scenario:

$(".flex-container").on("mouseenter", () => {
    $("#hidden").show();
})

$(".flex-container").on("mouseleave", () => {
    $("#hidden").hide();
})

$(".flex-item").on("mouseenter", () => {
    $("#hidden2").show();
})

$(".flex-item").on("mouseleave", () => {
    $("#hidden2").hide();
})
.flex-container {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid black;
  margin: 5px;
  padding: 5px;
}

.item-container {
    display: flex;
    align-items: center;
    width: 100%;
    justify-content: center;
}

.flex-item {
    padding: 5px;
    margin: 10px;
    outline: 1px solid black;
    flex: 1 1 auto;
    height: 24px;
    max-width: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
}

#hidden, #hidden2 {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-container">
  <div class="flex-item">
    1
  </div>
  <div class="flex-item">
    2
  </div>
  <div class="flex-item">
    3
  </div>
</div>

<div id="hidden">
  Flex Container Hovered
</div>

<div id="hidden2">
  Flex Item Hovered
</div>

Adding an extra flex container as a wrapper achieves close to the intended effect, but the intention of the flex-grow property of the items is not preserved, as seen below.

enter image description here

The items do not grow to the max-width of the items to fill up the outer box. Here is a snippet of the above scenario:

$(".flex-container").on("mouseenter", () => {
    $("#hidden").show();
})

$(".flex-container").on("mouseleave", () => {
    $("#hidden").hide();
})

$(".flex-item").on("mouseenter", () => {
    $("#hidden2").show();
})

$(".flex-item").on("mouseleave", () => {
    $("#hidden2").hide();
})

$(".extra-wrapper").on("mouseenter", () => {
    $("#hidden3").show();
})

$(".extra-wrapper").on("mouseleave", () => {
    $("#hidden3").hide();
})
.flex-container {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid black;
  margin: 5px;
  padding: 5px;
}

.extra-wrapper {
  display: flex;
}

.item-container {
    display: flex;
    align-items: center;
    width: 100%;
    justify-content: center;
}

.flex-item {
    padding: 5px;
    margin: 10px;
    outline: 1px solid black;
    flex: 1 1 auto;
    height: 24px;
    max-width: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
}

#hidden, #hidden2, #hidden3 {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-container">
  <div class="extra-wrapper">
    <div class="flex-item">
    1
    </div>
    <div class="flex-item">
      2
    </div>
    <div class="flex-item">
      3
    </div>
  </div>
</div>

<div id="hidden">
  Flex Container Hovered
</div>

<div id="hidden2">
  Flex Item Hovered
</div>

<div id="hidden3">
  Extra Wrapper Hovered
</div>

How do I add an event listener to the items in a flex container when the items have a flex-grow and a max-width property?

wahoowa
  • 358
  • 1
  • 10
  • Please post code as a [mcve]. – zer00ne Jan 21 '22 at 01:36
  • [How do I include an element's margin in the hot-spot for jQuery's hover() event?](https://stackoverflow.com/questions/11298558/how-do-i-include-an-elements-margin-in-the-hot-spot-for-jquerys-hover-event/11298589) – ourmandave Jan 21 '22 at 02:29
  • @zer00ne Do the JSfiddles not count as the reproducible examples? – wahoowa Jan 21 '22 at 05:46
  • @ourmandave If the flex items' margins were included the hot-spot, if I mouse over the flex items in a line, the event would still fire 3 times, once per item in the box. I want the event to only fire once. I guess an option could be looking at the `e.toElement` to see where the mouse is entering to prevent a re-fire, but it seems more complicated than somehow wrapping all 3 items in a single parent element. – wahoowa Jan 21 '22 at 05:49
  • @wahoowa the reason why SO requires a [mcve] is because future readers will always have the code here on this site where as a link elsewhere is not gautunteed to always be there. – zer00ne Jan 21 '22 at 07:03

2 Answers2

0

Try this: https://jsfiddle.net/sean7777/zngdr51k/11/

How 2 make it work

It works because since margin does not count in mouseleave and mouseenter events, we use a wrapper element around the flex-item, wrap. The wrapper then gets assigned padding, and you attach the event listener to the wrapper.

This way you can simulate margin as padding and make it work with the event listner.

Note that you will have to assign width and height to the box. In the example, if you remove the width/height, it won't look right.
sean-7777
  • 700
  • 4
  • 13
  • Thanks, but there are still a few things missing for my specific use case. First, if you hover over all 3 boxes, the `mouseenter` and `mouseleave` events fire every time, as seen when doing `console.log` in the event handler: https://jsfiddle.net/Lw7sjteh/ . Second, the `height` property cannot be set, because then the `flex-grow` property does not work when sizing down the screen. I want the boxes to become smaller when the screen size is smaller, and expand up to `max-width` when the screen size is bigger. – wahoowa Jan 21 '22 at 05:44
0

Building upon the suggested answer from @ourmandave, I came up with the following solution.

In this solution, I added a pseudo element to each flex-item so that I could include the elements' margins in the events' "hot spots" as they were called. I then used additional logic to prevent the event handlers from repeated triggers by using the event's related target. By checking where the cursor used to be upon mouseleave or mouseenter events, one can prevent the event handlers from being fired again when the mouse moves from one flex item to another flex item. This solution still preserves the desired effects of flex-grow and max-width.

$(".flex-container").on("mouseenter", () => {
    $("#hidden").show();
})

$(".flex-container").on("mouseleave", () => {
    $("#hidden").hide();
})

$(".flex-item").on("mouseenter", (e) => {
    if (e.relatedTarget.className === "flex-item") return;
    console.log('mouseenter fired');
    $("#hidden2").show();
})

$(".flex-item").on("mouseleave", (e) => {
    if (e.relatedTarget.className === "flex-item") return;
    console.log('mouseleave fired');
    $("#hidden2").hide();
})
.flex-container {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid black;
  margin: 5px;
  padding: 5px;
}

.item-container {
    display: flex;
    align-items: center;
    width: 100%;
    justify-content: center;
}

.flex-item {
    padding: 5px;
    margin: 10px;
    outline: 1px solid black;
    flex: 1 1 auto;
    height: 24px;
    max-width: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}

.flex-item::before {
    content: '';
    position: absolute;
    inset: -10px -10px -10px -10px;
}

#hidden, #hidden2 {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-container">
  <div class="flex-item">
    1
  </div>
  <div class="flex-item">
    2
  </div>
  <div class="flex-item">
    3
  </div>
</div>

<div id="hidden">
  Flex Container Hovered
</div>

<div id="hidden2">
  Flex Item Hovered
</div>
wahoowa
  • 358
  • 1
  • 10