Selecting DOM Elements

Hello,

I’m having trouble solving the problem of selecting a particular dom element and looping through which ever element is clicked with events because said element(s) do not initially exist. I have a button the adds divs( said elements) to the dom , and i would like to select any div with a mouse click and then delete. I know i can figure out the delete problem , but i cant figure out how to select a particular div. Any guidance would be much appreciate thank you.


function createDiv() {
    divNum++;
    mainContainer.style.visibility = "visible"

    html = `<div class="movements__row" id="alldivs" data-id=${divNum}>
        <div class="movements__date">${currentDay}</div>
        <div class="movements__value">Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque quibusdam ipsa libero laudantium hic nihil consectetur eos optio reprehenderit ducimus, cupiditate eum tenetur sunt iusto similique pariatur mollitia, distinctio necessitatibus! Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ullam voluptate expedita assumenda? Unde esse repellat vel saepe fugit architecto pariatur inventore illum, ducimus ullam excepturi dolores, sed laboriosam, voluptas modi.</div></div>`;

    rowContainer.insertAdjacentHTML("beforebegin", html);

    thisOne = document.querySelector(`[data-id="${divNum}"`)

    divMap.set(`div${divNum}`, divNum)

    console.log(divMap);
}
document.addEventListener("click", function (e) {


    if (e.target.matches(`[data-id='${divMap.get(`div${divNum}`)}']`)) {
        console.log("Its there!")
    }


})

Zachary

Based on what you have posted, I’m going to be making some guesses here that hopefully work out! :slight_smile:

In your addEventListener call, add a console.log statement to capture ALL elements in the path to your click. See if any element matches the div elements you have dynamically added. If it does, at least you have a starting point from which you can start to filter by.

Let us know what happens once you do that?

Cheers,
Kirupa :octopus:

Thank you for your assistance. With the console log, I was able to determine which determined which div element was clicked. Would i then store the div element in an array , and when the element is clicked , check if array div.id matches the event.currenttarget.id and for example , highlight grey , if true? ( to signify selection?)

No, what I wanted to check with the console.log example is whether the div element you are looking for is even detected. From what you are saying, it is. There is no need to store this div element. You need to adjust your “if” statement to target this div element, for the detection logic (e.target.matches) you have right now isn’t working.

Is there a way for you to share an example of your code on https://www.codepen.io? That will make it easier for you and I to look at this code together.

:grinning:

First time hearing about codepen. What an awesome resource. I’ve made some progress but hit another road block. My current problem : Only able to delete 1 div at a time, even when multiple divs are selected. I haven’t revamped my code to utilize target.matches yet, i;ve been storing the divs in arrays and removiing them :open_mouth: Here is my link - https://codepen.io/cryptozachary/pen/YzepZYy

I am not able to get your example to work, even for the single div case. I re-created a simple example of your problem here:

Click on the Add Item button to add items. Click on any newly created item in the list to remove it from the list. This should be similar to what you are trying to do, so take a look at my code and see if helps you better understand how to remove a dynamically generated element.

Does this help?

Cheers
Kirupa :slight_smile:

Btw - I decided to fiddle with this some more and added an animation as part of each item getting removed :stuck_out_tongue:

1 Like

Wow thank you. And the additional animation is great. And the code is really straight forward. I don’t know how I went down that rabbit hole of putting the added elements into arrays and splicing. Previous code was such a mess. Much to learn.

What if i wanted to select multiple elements? like for example, by holding shift and click to select multiple elements, and then deleting with the delete key. Would I add a new class for each element selected element signifying the selection? Then maybe use a foreach loop to remove the element? I’m going to try and code this now.

Yes - you have it right! Let’s say you have a class called “selected” that you add to signify selection. You can just add that class to each item that you tag as being selected.

You can possibly get away with actually not even storing the selected items in an array and just getting them when you are about to remove them, similar to the following:

let selectedItems = document.querySelector(".item .selected")

There is no right or wrong way here :slight_smile:

Greetings - I was finally able to implement the multiple selections without the arrays as you suggested :slight_smile: But when deleting , all the the selected elements do not get deleted at the same time , max like 2 or 3 elements get deleted. I have to click the delete button again to delete the rest of the selected elements. After research , I’ve determined this might have something to do with async and promises? I have yet to study those topics , this might be the time to dive in. Any ideas ?

timeLine.addEventListener("dblclick", selectItem, false);

AddBtn.addEventListener("click", createDiv, false)

trash.addEventListener("click", removeElement)

//create timeline item
function createDiv(event) {

    divNum++;
    textNum++;

    html = `<div class="timeline-item all-timeline-items" id="D${divNum}"><div class="date-container"><input type="text" id=in-${divNum}" class="item-title" name="title" placeholder="title"></input>
        <div class="timeline__date">${currentDay}</div></div>
        <textarea class="timeline__value" rows="2" placeholder="enter information" id="text-${textNum}"></textarea></div>`;

    rowContainer.insertAdjacentHTML("beforeend", html);



    textArea = document.querySelectorAll("textarea")

    console.log(textArea)

    timeLine.addEventListener("input", () => {
        textArea.forEach(item => {
            item.style.height = "auto"
            item.style.height = item.scrollHeight + "px"
        })
    })

}


//select elements
function selectItem(e) {

    if (e.target.classList.contains("all-timeline-items")) {
        clickedItem = e.target.id
        element = document.getElementById(`${clickedItem}`);
    }

    if (!element.classList.contains("selected")) {
        element.classList.add("selected")
    } else if (element.classList.contains("selected")) {
        element.classList.remove("selected")
    }

    selected = document.getElementsByClassName("selected")
    console.log(selected.length)
}

//remove selected elements by click
function removeElement(event) {

    for (let i = 0; i < selected.length; i++) {
        selected[i]?.remove()
    }
}

That is interesting. One way to check to see if this is timing related is to set a breakpoint on the selected[i]?.remove() line and seeing if they all get properly removed when you step through it manually for each selected item :slight_smile:

Hm…it seems to have something to do with the for loop i think…still tinkering :slight_smile:

Does this happen across different browsers? :grinning:

Greetings!

Yes it does, checked on Edge and mozzila…I’ll change it to only being able to delete 1 timeline div at a time and come back to this particular problem as its been difficult to decipher. I ran into another problem that’s been difficult to solve as well regarding saving information from the timeline div input text fields to local storage and retrieving the same information from local storage, back into their respective timeline div and input text lines. https://codepen.io/cryptozachary/pen/ZErvWge

My thought process on this was to make the “key” for local storage a dynamic variable number that increases upon each new key value pair addition. But each input text field is returning information only entered in the first title input text field on the timeline. Example -

dynamicKey = 0
// increases based on some value, haven't determined which value should increase the dynamic key

dynamicKey++

allTitleInputs= document.getElementsByClassName("item-title")

for (let b = 0; b < allTitleInputs.length; b++) {

        if (allTitleInputs[b].value ) {
            localStorage.setItem(dynamicKey, allTitlesInput[dynamicKey].value)
    
        }
    }
//the above setitem code is repeated for each input text field (total of 4)

Apologies, I tried embedding the codepen but couldn’t figure it out.

Interesting. When you go and try to inspect your Local Storage via the Chrome dev tools, do you see entries for the multiple elements?

Negative - just for the first field called “title” , and theres a key value pair of 0 , “title.value”. Theres a total of 4 input vales im trying to save. key values should be something like 0 , “title.value”, 1 , “date.value”, 2 , “time.value” , 3, divInfo.value

I tried running your codepen link, but that seems to error out. When I click “Add Item” a few times and three item areas appear below, is the goal to save those three and restore them the next time I refresh the page?

Yes that’s correct , a total of four should be restored. Title , time , date , larger text area. They all have placeholders as well.

Problem solved :slight_smile: so simple, all I needed was a foreach loop on an array containing all the elements with input.values to store. The loop stores the values in local storage based on the index number. My overthinking got the best of me again!

example


    //select all timeline div input elements
    allElements = document.getElementsByClassName("all-of-them")
    allElements2 = [...allElements]
    console.log(allElements2)

    allElements2.forEach(function (item, index, array) {
        localStorage.setItem(index, item.value)```
1 Like

Glad you got it sorted out! I also like your use of the spread operator and forEach - those are like next level techniques that make your code easier to read and debug haha.

:slight_smile:

1 Like