简体   繁体   中英

Function to be executed only once

First of all, my code is not beautiful. It's just an example, then I'll improve it

I am making a filter. Every time I click on a filter, it is added to a div that shows all active filters.

options.forEach(element => {
            element.addEventListener("click", (e) => {
                let id = e.target.id;

                if(filters.children.length > 0){
                    let allFilters = filters.children;
                    console.log(allFilters);
                    for (let i = 0; i < allFilters.length; i++) {
                        const element = allFilters[i];
                        let filterId = element.id.substr(7);
                        if(id == filterId){
                            return;
                        }
                    }
                }
                
                let button = document.createElement("button");
                button.id = "option_" + id;
                button.innerText = id;
                filters.appendChild(button);
                verificar();
                filtera()
            })
        });

As you could see, I call a function that I put any name on. It is the last function. Every time I add it, it is called again, so there is more than one function running. This function is to delete the active filter that the user clicks. However, as it is being executed more than once, when that element is deleted, the function executes again and gives an error, because that element no longer exists. I'm not able to think of a correct way to do this, could someone help

function filtera() {
            let filtersBtns = document.querySelectorAll("#filters button")
            filtersBtns.forEach(element => {
                element.addEventListener("click", (e) => {
                    console.log(e.target.id);

                    filtersBtns.forEach(element => {
                        if(element.id === e.target.id){
                            filters.removeChild(element);
                            return;
                        }
                    });
                })
            });
        }
<div id="filter" style="display: flex; flex-direction: column;">
        <div id="filters">
        </div>
        
        <br>

        <div style="display: flex; justify-content: space-between;">
            <p id="action">
                Ação
            </p>
            <p id="49">
                49,99
            </p>
            <p id="strategy">
                Estratégia
            </p>
            <p id="100">
                100,00
            </p>
        </div>
    </div>

<div id="container">

        <div class="card action strategy 49">
            <h1>
                Card 1
            </h1>
    
            <p>
                Lorem ipsum dolor sit amet consectetur adipisicing elit.
            </p>
            <p>
               action, strategy, 49.99
            </p>
        </div>...

It looks to me like when an option element is clicked it's going to add the filter to the active filters and then add an event handler for all active filters including any that already exist in the list. So Option A would get one event handler when it's added and then a second when Option B is clicked.

A quick fix might be to allow the button element to be passed in to filtera so that only the relevant button needs the event handler added.

Something like:

        function filtera(button = null) {
            let filtersBtns = button ? [button] : document.querySelectorAll("#filters button")
            filtersBtns.forEach(element => {
                element.addEventListener("click", (e) => {
                    console.log(e.target.id);

                    filtersBtns.forEach(element => {
                        if(element.id === e.target.id){
                            filters.removeChild(element);
                            return;
                        }
                    });
                })
            });
        }

And call it like filtera(button) in the first bit of code.

I did it in a way that apparently solved my problem.

When I create the element, I call a function by passing the event listener

function eventListener(element) {
  element.addEventListener("click", (e) => {
     filtera(e.target);
  })
}

And I delete without using "removeChild"

function filtera(button) {
   let filtersBtns = document.querySelectorAll("#filters button")
   filtersBtns.forEach(element => {
      if(element.id === button.id){
          filters.removeChild(element);
          return;
      }
   );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM