Reputation: 308
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
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
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