What is the best method for adding or removing items using ID instead of classes?

Is there a way to change the highlight class to an id, so that clicking outside the products will not trigger the highlight effect?

I have added the window.onload section with my desired changes, but I am unsure how to switch the class highlight to an id. I believe the best approach would be to change the class and then utilize the window.onload function.

let overlay;
document.querySelectorAll('.product').forEach(function(path) {
  path.onclick = chooseProduct;
})

function chooseProduct(e) {
  if (overlay) overlay.classList.remove('highlight')
  overlay = e.target
  overlay.classList.add('highlight')
}

//What I want to add to the highlight class using id to remove black border when click outside of the products

// window.onload = function(){
//   var hide = document.getElementById('?');
//   document.onclick = function(e){
//     if(e.target.id !== '?'){
//       hide.style.display = 'none';
//     }
//   };
// };


var el = document.getElementsByClassName("color");
for (var i = 0; i < el.length; i++) {
  el[i].onclick = changeColor;
}

function changeColor(e) {
  let hex = e.target.getAttribute("data-hex");
  if (overlay) overlay.style.fill = hex;
}
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#container {
  height: 200px;
  width: 200px;
}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}

.highlight {
  stroke-width: 10px;
  stroke: #000;
}
<div id="container">

  <svg id="product-svg" viewBox="0 0 744 1074">
      <path class="product" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path class="product" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path class="product" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img id="background-image" src="boxes.jpg" alt="">
</div>

<div class="colors">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</div>

Answer №1

It appears that your code is functioning correctly, with the exception of the highlighted style of the selected product not being removed when clicking outside the product.

To address this issue, I have implemented an Event Listener (removeHighlight()) by attaching

document.onclick = removeHighlight;
to the entire document on the click event. This means that whenever a click event occurs anywhere in the DOM, the event listener will be triggered. Within the EventListener function, the class highlight is removed from all products only if the click event did not originate from clicking on either a product or a color. Additionally, I have set overlay=null to remove the reference of the previously selected product. This means that clicking on colors will no longer apply the selected color to the previously selected product under the specified conditions, until a product is clicked on again.

let overlay;
document.querySelectorAll('.product').forEach(function(path) {
  path.onclick = chooseProduct;
})

function chooseProduct(e) {
  if (overlay) overlay.classList.remove('highlight')
  overlay = e.target
  overlay.classList.add('highlight')
}

var removeHighlight = function(e) { 
    var products = document.querySelectorAll('.product');
   
    if(!e.target.classList.contains('product') && !e.target.classList.contains('color')){
        overlay = null;
        document.querySelectorAll('.product').forEach(function(prod){
            prod.classList.remove('highlight');
        });
    }
}

document.onclick = removeHighlight; 


var el = document.getElementsByClassName("color");
for (var i = 0; i < el.length; i++) {
  el[i].onclick = changeColor;
}

function changeColor(e) {
  let hex = e.target.getAttribute("data-hex");
  if (overlay) overlay.style.fill = hex;
}
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#container {
  height: 200px;
  width: 200px;
}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}

.highlight {
  stroke-width: 10px;
  stroke: #000;
}
<div id="container">

  <svg id="product-svg" viewBox="0 0 744 1074">
      <path class="product" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path class="product" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path class="product" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img id="background-image" src="boxes.jpg" alt="">
</div>

<div class="colors">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</div>

jsfiddle

Answer №2

When dealing with behavior triggered by click events outside the intended targets, it is recommended to set the document Object as the click event listener and manage all clicks through Event Delegation.

  1. Set the document Object as the click event listener
    document.onclick = selectPath;
    
  2. The click event handler is selectPath(e)
    1. Gather all elements with the class .product into a NodeList
      const paths = document.querySelectorAll('.product');
      
    2. If the user clicks on any element with the class .product, remove the .highlight class from all other .product elements and add the class to the one the user clicked on
      if (e.target.matches('.product')) {
        paths.forEach(path => path.classList.remove('highlight'));
        e.target.classList.add('highlight');
      
    3. If the user clicks on any element with the class .color, get its [data-hex] value and apply it to the .highlight element if it exists
      else if (e.target.matches('.color')) {
        let hex = e.target.dataset.hex;
        let selected = document.querySelector('.highlight');
        if (selected) selected.style.fill = hex;
      
    4. Otherwise, simply remove the .highlight class if it exists on any element
      paths.forEach(path => path.classList.remove('highlight'));
      

document.onclick = selectPath;

function selectPath(e) {
  const paths = document.querySelectorAll('.product');

  if (e.target.matches('.product')) {
    paths.forEach(path => path.classList.remove('highlight'));
    e.target.classList.add('highlight');
  } else if (e.target.matches('.color')) {
    let hex = e.target.dataset.hex;
    let selected = document.querySelector('.highlight');
    if (selected) selected.style.fill = hex;
  } else {
    paths.forEach(path => path.classList.remove('highlight'));
  }
};
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

.container {
  height: 200px;
  width: 200px;
}

.svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

.background {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.circles {
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  display: inline-block;
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}

.highlight {
  stroke-width: 10px;
  stroke: #000;
}
<div class="container">

  <svg class="svg" viewBox="0 0 744 1074">
      <path class="product" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path class="product" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path class="product" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img class="background" src="boxes.jpg" alt="">
</div>

<div class="circles">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</div>

Answer №3

The styling for the "highlight" class is specifically applied to products, eliminating the need for individual identifiers.

Simply check if the clicked element has the "product" class, remove all instances of "highlight" classes, and add it to the clicked product. If the element does not have the "product" class, just remove all existing "highlight" classes.

 window.onload = function(){
   document.onclick = function(e){
     if(e.target.classList.contains("product")){
       resetClass()
       e.target.classList.add("highlight")
     }else{
         resetClass()
     }
   };
 };



 function resetClass(){
   document.querySelectorAll(".highlight").forEach(item => {
         item.classList.remove("highlight")
   })
 }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The search functionality is malfunctioning within the JavaScript table

I am working with a table that I want to filter based on input values. However, the current filtering function is not working as expected. I have utilized an onkeyup function for the filtering process. For more details and a live example, check out the jsf ...

Sequelize: When attempting to use .get({plain: true})) method, an error is returned indicating that .get is

I'm facing a strange issue as I am able to retrieve only the values of an instance in other parts of my code without any problems. Can you spot what might be wrong with my current code? app.get('/profile', checkAuth, function(req, res) { ...

What steps can be taken to stop 'type-hacking'?

Imagine owning a popular social media platform and wanting to integrate an iframe for user signups through third-party sites, similar to Facebook's 'like this' iframes. However, you are concerned about the security risks associated with ifra ...

Warning: Potential Infinite Loop when using Vue JS Category Filter

I developed a program that filters events based on their program and type. The program is working correctly, however, an error message stating "You may have an infinite update loop in a component render function" keeps popping up. I suspect that the issue ...

Error encountered in Vue code, lacks default export on Editor Terminal

I'm not experiencing any issues in the browser, I am getting the desired output. However, why does this keep showing up in the editor terminal? Any assistance would be greatly appreciated. Error - No Default Export: The module "/vue3/src/components/ ...

The problem of creating a custom pop-up with jQuery

I'm running into an issue while trying to develop a custom CSS and jQuery popup. Despite my efforts, the popup isn't functioning as intended. Take a look at my code below and point out where I may have gone wrong. What I aim to achieve is a popup ...

jQuery - Wait for the completion of one UI change before initiating another UI change

Is there a way to implement the functionality where $("#login").toggle("drop", {direction: "left"}); is executed first and upon completion, $("#register").toggle("drop", {direction: "right"}); is then carried out? The issue arises from the fact that the ...

Using Vue Formulate to effortlessly upload multiple images

One of my projects involves using a Vue Formulate component for uploading multiple images to an Express.js backend. Here is the code snippet for the Vue Formulate component: <FormulateInput type="image" name="property_ ...

Notify when a certain element's ID is visible on the screen using the jQuery appear method

Having trouble getting this plugin to cooperate: https://github.com/morr/jquery.appear I attempted to reference the plugin from a CDN using Ajax: http://cdnjs.cloudflare.com/ajax/libs/jquery.appear/0.3.3/jquery.appear.js Why isn't it working as expe ...

Creating specialized paths for API - URL handlers to manage nested resources

When working with two resources, employees and employee groups, I aim to create a structured URL format as follows: GET /employees List employees. GET /employees/123 Get employee 123. GET /employees/groups List employee groups. GET /employees/groups/123 ...

Reducing the number of DOM manipulations for websites that heavily utilize jquery.append

Here's a snippet of my coding style for the website: !function(){ window.ResultsGrid = Class.extend(function(){ this.constructor = function($container, options){ this.items = []; this.$container = $($container); ...

Tips on adding custom fonts for text geometry in three.js

Currently, I am delving into the realm of three.js to create text geometry, although my expertise in JavaScript is fairly limited. Initially, I attempted to utilize my custom JSON font, which resulted in the same error encountered when using fonts from th ...

Can the PHP stylesheet import be configured to exclude a specific string?

Can I import a PHP stylesheet named style.php into my HTML document? Is there a way to delete certain strings from style.php, such as <style> tags, before importing it using traditional methods like <link>? ...

Link-defying button

I'm developing a website with a homepage that serves as an entry point to the rest of the site (it welcomes the user and allows them to click anywhere to access the main website). The following code accomplishes this: <template> <div onc ...

How can I create an input field that comes with a preset value but can be updated by the user with a different name?

I am in need of a solution that will enable a user to update text on a webpage dynamically. I have been unable to find any information on how to achieve this. Is there anyone aware of a method to implement this feature? Perhaps a library or utilizing Vue ...

Using a combination of a bootstrap class and a custom CSS class to enhance your website design

How do I apply two different classes? I have two HTML select fields where the user can choose either repair or another option in the first one. When the user selects one, the second field should appear. But it also needs to have a Bootstrap class: form-con ...

Locate HTML attribute values with the help of BeautifulSoup

Trying to extract data from HTML using BeautifulSoup has proven to be more challenging than expected. Specifically, I am struggling with utilizing the .find() function correctly in this scenario. Take a look at the HTML snippet below: <div class="a ...

Display a loading message using jQuery Dialog when the page is loading

I have a button that triggers a jQuery Dialog box to open. $( "#dialog" ).dialog({ autoOpen: false, title: 'Contract', height: 450, width:1100, modal:true, resizable: true }); $( ".btnSend" ).click(function() { var id=$(this).a ...

The PHP function is not successfully receiving a value from the AJAX call to be entered into the Database

I've been struggling with a piece of code lately, trying to pass the value 1 to my database when a user clicks the "collect coins" button. The goal is to reset the column "dailyfree" every day at 12 pm so that users can click the button again on the n ...

Retrieve information using server-side rendering

I'm faced with a situation where my page utilizes query parameters to fetch data via SSR. The challenge arises when these query parameters frequently change, triggering a re-fetch of the data using SSR despite there being no client-side data fetching ...