Home > Mobile >  How to remove properties from one item and add to another with JQuery?
How to remove properties from one item and add to another with JQuery?

Time:12-13

Guys! I have a menu with few links, and when i click on one of them i want to show horizontal line, like on screenshot below.enter image description here

I've tried to use this script, but now css properties applies to all of the links. What should i do to remove propertie from inactive link, and apply it to one, that i clicked? Thank you!


$('.main-menu-link-container').click(function() {
    $(this).find('.main-menu-link-line').css({"width": "6.11em", "marginRight": "2.36em"});
});

CodePudding user response:

Some context (your current HTML markup) was missing so it was hard to perfectly address your exact issue. Anyway, your main concern was how to address the element that fired the click event.

Your events seem attached to the parent menu element, which is a good coding habit considering Events are better handled using delegation in order to handle current or future, dynamic child elements.

The problem

jQuery's $(this) is the somewhat "equivalent" of Event.currentTarget in vanilla JavaScript. When using direct events like $("targetSelector").on("eventName", fn) the this inside the callback function refers directly to any element matching the "targetSelector". In your case the parent element. .find("childSelector") returns a collection of child Elements, .css() will apply the new styles to every such child element in the collection.

The solution: proper event delegation

In a jQuery-syntax use Event delegation by providing a second argument to the .on("eventName", "dynamicChildSelector") and inside the function use $(this) - which will be the actual clicked child:

// "Static delegated parent"     "EventName", "dynamicChild"
$('.main-menu-link-container').on("click", ".menu-link", function(evt) {

  const $menu = $(evt.delegateTarget); // The '.main-menu-link-container' parent
  const $links = $menu.find(".menu-link"); // All the children links
  const $link = $(this); // or: $(evt.currentTarget) The clicked ".menu-link" element 
  
  $links.removeClass("is-active"); // remove from all children
  $link.addClass("is-active");     // add to the clicked one
  
});
* {margin:0; box-sizing: border-box;}

.main-menu-link-container {
  display: flex;
  flex-direction: column;
  background-color: red;
  color: white;
  padding: 1rem;
  gap: 1rem;
}

.menu-link {
  display: flex;
  align-items: center;
  border: solid white 3px;
  padding: 1rem;
  cursor: pointer;
}

.menu-link::before {
  content: "";
  display: inline-block;
  width: 0rem;
  height: 0.3rem;
  background: #fff;
  transition: all 0.3s;
}
.menu-link.is-active::before {
  width: 6rem;
  margin-right: 2rem;
}
<div >
  <div >Link 1</div>
  <div >Link 2</div>
  <div >Link 3</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

Also, instead of changing the styles directly using JS (bad practice since hard to maintain) use the .[add/remove/toggle]Class() methods - and set the styles in your Stylesheet - where due.

Event delegation in JavaScript

For comparison, here's the same approach to event delegation in pure JavaScript, without the overhead of a library like jQuery:

// DOM utility functions:

const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);

// Task: Menu active items

const handleActiveMenuItem = (evt) => {
  const elLink = evt.target.closest(".menu-link"); // The clicked element's closest selector / or self
  if (!elLink) return; // Do nothing, no link clicked
  const elMenu = evt.currentTarget; // The event-bound element
  const elsLinks = els(".menu-link", elMenu);
  
  elsLinks.forEach(elLink => elLink.classList.remove("is-active")); // remove from all children
  elLink.classList.add("is-active"); // add to the clicked one
};

els(".main-menu-link-container").forEach(elMenu => {
  elMenu.addEventListener("click", handleActiveMenuItem);
});
* {margin:0; box-sizing: border-box;}

.main-menu-link-container {
  display: flex;
  flex-direction: column;
  background-color: red;
  color: white;
  padding: 1rem;
  gap: 1rem;
}

.menu-link {
  display: flex;
  align-items: center;
  border: solid white 3px;
  padding: 1rem;
  cursor: pointer;
}

.menu-link::before {
  content: "";
  display: inline-block;
  width: 0rem;
  height: 0.3rem;
  background: #fff;
  transition: all 0.3s;
}
.menu-link.is-active::before {
  width: 6rem;
  margin-right: 2rem;
}
<div >
  <div >Link 1</div>
  <div >Link 2</div>
  <div >Link 3</div>
</div>

  • Related