Alejandro Armas
Alejandro Armas

Reputation: 308

ID sometimes not returning with onclick event?

I'm new to JavaScript, sort of getting a hold on on it. I noticed my displayEmail function was not correctly accepting the id of the dynamically created list items in list-group. I would like to have my displayEmail function have a modal pop up, but I need each list item in list-group-item to correctly return an ID when onclick event occurs.

Here's what the problem looks like in the console

Problem

Here's my Javascript code:

document.addEventListener('DOMContentLoaded', function() {

  // Use buttons to toggle between views
  document.querySelector('#inbox').addEventListener('click', () => load_mailbox('inbox'));
  document.querySelector('#sent').addEventListener('click', () => load_mailbox('sent'));
  document.querySelector('#archived').addEventListener('click', () => load_mailbox('archive'));
  document.querySelector('#compose').addEventListener('click', compose_email);

  // By default, load the inbox
  load_mailbox('inbox');
});

function compose_email() {

  function clear_compose_form() {
    document.querySelector('#compose-recipients').value = '';
    document.querySelector('#compose-subject').value = '';
    document.querySelector('#compose-body').value = '';
  }

  // Show compose view and hide other views
  document.querySelector('#emails-view').style.display = 'none';
  document.querySelector('#compose-view').style.display = 'block';

  // Clear out composition fields
  clear_compose_form()

  document.querySelector("#compose-form").addEventListener('submit', (event) => {

    const recipients = document.querySelector('#compose-recipients').value;
    const subject = document.querySelector('#compose-subject').value;
    const body = document.querySelector('#compose-body').value;

    const message = document.createElement("div")
    message.className = "alert alert-";

    fetch("/emails", {
      method: "POST",
      body: JSON.stringify({
        recipients: recipients,
        subject: subject,
        body: body
      })
    })
    .then(response => response.json())
    .then(jsonResponse => {

      let messageText = null

      if (jsonResponse.hasOwnProperty("message")) {
        message.className += "success";
        messageText = jsonResponse["message"]
      } else {
        message.className += "danger";
        messageText = jsonResponse["error"]
      }

      message.innerHTML = messageText

      let alert = document.querySelector(".alert")
      if (alert !== null) {
        alert.replaceWith(message)
      } else {
        document.querySelector("#compose-view").insertBefore(message, document.querySelector("#compose-form"))
      }

      clear_compose_form()
    })

    event.preventDefault();
    return false;
  });

}


function load_mailbox(mailbox) {
  
  // Show the mailbox and hide other views
  document.querySelector('#emails-view').style.display = 'block';
  document.querySelector('#compose-view').style.display = 'none';

  // Show the mailbox name
  document.querySelector('#emails-view').innerHTML = `<h3> ${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`;

  fetch(`/emails/${mailbox}`, {
    method: "GET"
  })
  .then(response => response.json())
  .then(emailsData => mailboxEmails(emailsData, mailbox))

}


function mailboxEmails(data, mailbox) {

  const emailsContainer = document.createElement("ul");
  emailsContainer.className = "list-group";
  emailsContainer.addEventListener("click", event => displayEmail(event));

  data.forEach(emaildata => {

    email = emailPreview(emaildata, mailbox);
    emailsContainer.appendChild(email)

  });

  document.querySelector('#emails-view').append(emailsContainer)

}


function emailPreview(emaildata , mailbox) {

  const email = document.createElement("li")
  const emailPreviewContent = document.createElement("h5")
  const userDidSend = mailbox === "sent"

  
  let otherUsers = null;

  if (userDidSend){
    otherUsers = emaildata["recipients"];
  } 
  else {
    otherUsers = emaildata["sender"];

    const unreadNotification = document.createElement("span")
    unreadNotification.className = "badge badge-warning"
    unreadNotification.innerHTML = "Unread"
    email.appendChild(unreadNotification)
  }

  email.id = emaildata["id"]
  email.className = "list-group-item list-group-item-action list-group-item-light";

  emailPreviewContent.innerHTML = `${otherUsers} - ${emaildata["subject"]} - ${emaildata["body"] } - ${emaildata["timestamp"] }` 
  emailPreviewContent.style.textOverflow = "ellipsis"
  email.appendChild(emailPreviewContent)

  return email;
}


function displayEmail(event) {
  if (event.target) {
    console.log(event.target.id + " was clicked")
  }
  

  // document.addEventListener(bd-email-modal-lg)
}

Here's my HTML:


    <button class="btn btn-sm btn-outline-primary" id="inbox">Inbox</button>
    <button class="btn btn-sm btn-outline-primary" id="compose">Compose</button>
    <button class="btn btn-sm btn-outline-primary" id="sent">Sent</button>
    <button class="btn btn-sm btn-outline-primary" id="archived">Archived</button>
    <a class="btn btn-sm btn-outline-primary" href="{% url 'logout' %}">Log Out</a>
    <hr>

    <div id="emails-view">
    </div>

    <div id="compose-view">
        <h3>New Email</h3>
        <form id="compose-form">
            <div class="form-group">
                From: <input disabled class="form-control" value="{{ request.user.email }}">
            </div>
            <div class="form-group">
                To: <input id="compose-recipients" class="form-control">
            </div>
            <div class="form-group">
                <input class="form-control" id="compose-subject" placeholder="Subject">
            </div>
            <textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
            <input type="submit" class="btn btn-primary"/>
        </form>
    </div>

    <div class="modal fade bd-email-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-lg">
          <div class="modal-content">
            ...
          </div>
        </div>
      </div>

Anything helps, thank you!

Upvotes: 0

Views: 58

Answers (1)

Will Jenkins
Will Jenkins

Reputation: 9887

Your problem is that you've added your event listener to the outer container:

 emailsContainer.addEventListener("click", event => displayEmail(event));

So depending where your pointer is when the click happens, the click target might be an <li> (so it bubbles to the <ul> click handler with the id you expect) or it might be the containing <ul>, in which case the id will be undefined). If you reliably need the id from the item itself, you'll have to add the click handler to each item individually, and not on the container.

function emailPreview(emaildata , mailbox) {
    const email = document.createElement("li")
    email.addEventListener("click", event => displayEmail(event));
    ...

You also need to update your click handler to reference currentTarget rather than target. currentTarget gives you the item handling the event (your <li>), the latter is the item that was clicked (possibly the <li>, possibly any of its children).

function displayEmail(event) {
  if (event.target) {
    console.log(event.currentTarget.id + " was clicked")
  }
}

Upvotes: 1

Related Questions