0

I am trying to have an external (not inline) JavaScript code to handle multiple elements depending on their class and id.

My goal is that if an element is of a certain class, its' CSS will change depending on its' id name when it is hovered over.

In this example:

<p class="p-class" id="000">Hi</p>
<p class="p-class" id="FFF">Hi</p>
<p class="p-class" id="FFFF66">Hi</p>
<p class="p-class" id="498F83">Hi</p>

My goal is to get this:

<p class="p-class" id="000" style="color:#000">Hi</p>
<p class="p-class" id="FFF" style="color:#FFF">Hi</p>
<p class="p-class" id="FFFF66" style="color:#FFFF66">Hi</p>
<p class="p-class" id="498F83" style="color:#498F83">Hi</p>

I thought about something in this direction:

const pElements = document.querySelectorAll('.p-class');
for (let i = 0; i < pElements .length; i++) {
  pElements[i].addEventListener('mouseover', function() {
    pElements[i].style.color = `#${pElements[i].getAttribute('id')`;
  });
}

But, I am relatively new to this and I don't know if the above code is valid or how to properly trigger it.

Any insights/suggestions will be highly appreciated!

Yaniv Aflalo
  • 239
  • 2
  • 11
  • Except for a missing `}` at the end of this line, your code is fine. The correct code is: `pElements[i].style.color = \`#${pElements[i].getAttribute('id')}\`;` However, relying on the `id` attribute is problematic unless you can guarantee each id has a different value. You'd be better off using a [data attribute](https://stackoverflow.com/questions/30417852/what-are-data-html-attributes) like `data-color`. – kmoser Apr 04 '21 at 20:03

2 Answers2

5

The easiest way would be to avoid using an id, and instead use a CSS custom-property, for example --hoverColor:

/*
  The default styling for the element(s):
*/
.p-class {
  color: #000;
  background-color: silver;
}

/*
  The styles for the :hover pseudo-class/interaction:
*/
.p-class:hover {
  /* the var() retrieves the named custom-property from
     the closest ancestor element upon which it's defined.
     Here this is specified in the inline 'style'
     attribute for the .p-class elements: */
  color: var(--hoverColor);
}
<p class="p-class" style="--hoverColor: #000">Hi</p>
<p class="p-class" style="--hoverColor: #FFF">Hi</p>
<p class="p-class" style="--hoverColor: #FFFF66">Hi</p>
<p class="p-class" style="--hoverColor: #498F83">Hi</p>

However, given your own code as posted in the question that could be made to work relatively easily, like so:

const pElements = document.querySelectorAll('.p-class'),
  toggle = (event) => {
    // retrieves the element node to which the event
    // was bound:
    const target = event.currentTarget;
    
    // if the event is mouseenter (so the user is
    // hovering over the element):
    if (event.type === 'mouseenter') {
      // we update the color of the element
      // according to the color held in the 'id'
      // attribute, using a template-string to
      // interpolate that value into the string
      // to form a valid hexadecimal colour:
      target.style.color = `#${target.id}`;
    } else {
      // if the event is of any type other than
      // mouseenter, we unset the colour by setting
      // the colour to an empty string (an invalid
      // value) causing the style-rule to be discarded:
      target.style.color = '';
    }
  };

// using NodeList.prototype.forEach() to iterate over the
// NodeList using an Arrow function:
pElements.forEach(
  // para is a reference to each of the element Nodes of
  // the NodeList over which we're iterating:
  (para) => {
    // here we bind a named function to handle
    // the mouseenter/mouseleave (hover/unhover)
    // events; in order to avoid duplicating the
    // anonymous function:

    // to handle the mouseenter:
    para.addEventListener('mouseenter', toggle);
    // to handle the mouseleave:
    para.addEventListener('mouseleave', toggle);
  });
.p-class {
  color: #000;
  background-color: silver;
}
<p class="p-class" id="000">Hi</p>
<p class="p-class" id="FFF">Hi</p>
<p class="p-class" id="FFFF66">Hi</p>
<p class="p-class" id="498F83">Hi</p>

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
1

Array.from(document.querySelectorAll('.p-class')).forEach( p_element => {
  const OriginalColor = p_element.style.color;
  p_element.addEventListener("mouseenter", () => { p_element.style.color = '#' + p_element.id });
  p_element.addEventListener("mouseleave", () => { p_element.style.color = OriginalColor });
});
.p-class {
  background-color: lightgrey;
}
<p class="p-class" id="000">Hi</p>
<p class="p-class" id="FFF">Hi</p>
<p class="p-class" id="FFFF66">Hi</p>
<p class="p-class" id="498F83">Hi</p>
Dani-Br
  • 2,289
  • 5
  • 25
  • 32
  • Thank you! Is the `Array.from()` necessary? To my understanding NodeList also works well (i.e. `document.querySelectorAll('.p-class').forEach(....);` – Yaniv Aflalo Apr 05 '21 at 05:51