Search code examples
javascripthtmldjangofor-loopqueryselector

How to select a specific HTML element from a for loop in a Django template?


I am trying to create a button that hides and displays only the specific HTML elements that are in the same div with it through JavaScript. All the divs are within a Django template for loop and display different information. Right now, I am using a querySelector to select the id, but that is not correct because it selects the first element it finds with that id.

html:

<div>
        {% for post in page_obj.object_list %}
            <div class = "individual_posts">
                <a href="{% url 'username' post.user %}"><h5 id="p_user" class = "post_user">{{ post.user }}</h5></a>
                <h6 id = "post_itself">{{ post.post }}</h6>
                <h6 id="date_and_time" class = "post_elements">{{ post.date_and_time }}</h6>
                <h6 id="likes" class = "post_elements">{{ post.likes }}&#x1F44D;</h6>
                {% if post.user == request.user %}
                    <button class="edit_button" value="{{ post.id }}">Edit</button>
                {% endif %}
                <textarea class="textarea" id="edit_area"></textarea>
                <button class="edit_save" id="save">Save</button>
            </div>
        {% endfor %}
    </div>

javascript:

document.addEventListener('DOMContentLoaded', function(){
    //hide the textarea
    const editingTextareas = document.querySelectorAll(".textarea");
    for (const textarea of editingTextareas){
        textarea.style.display = 'none';
    }
    //hide the save buttons for the textarea
    const saveButtons = document.querySelectorAll(".edit_save");
    for (const s_button of saveButtons){
        s_button.style.display = 'none';
    }
    //adds the click to the edit buttons
    const editButtons = document.querySelectorAll('.edit_button');
    for (const button of editButtons) {
      id = button.value;
      button.addEventListener('click', () => edit_email(id));
    }
  });
  
function edit_email(id){
    document.querySelector('#post_itself').style.display = 'none';
    document.querySelector('#date_and_time').style.display = 'none';
    document.querySelector('#likes').style.display = 'none';
    const edit_area = document.querySelector('#edit_area');
    edit_area.style.display = 'block';
    const save = document.querySelector('#save');
    save.style.display = 'block';

    //get post
    fetch(`/edit/${id}`)
    .then(response => response.json())
    .then(post => {
        edit_area.innerHTML = `${post.post}`;
    })

    //save the post
    fetch(`/edit/${id}`,{
        method: 'POST',
        post: JSON.stringify({
            post: edit_area.value
        })
    })
}

Will I have to run each HTML element through a for loop like I do when the DOM is first loaded to hide the buttons?


Solution

  • You're sharing the same id for multiple elements. According to MDN,

    The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors

    To fix this for your case, append the post ID to the element ID so each ID is unique and can be queried individually. E.g <h6 id = "post_itself-{{post.id}}">{{ post.post }}</h6>, then the JS side should be:

    document.querySelector(`#post_itself-${id}`).style.display = 'none';
    

    Do that for all repeated IDs. I'll advise you to store the element in a variable so you don't have to repeatedly query the same element

    const postItselfEl = document.querySelector(`#post_itself-${id}`)