I have a MaterializeCSS dropdown menu implemented with this HTML. The event listener works only if the dropdown item is clicked in the upper portion.
<div class="left">
<span id="notificationTotal" class="new badge red" style="display:none">
</span>
<a class="dropdown-trigger" href="#!" data-target="notificationsDropdown">
<i class="material-icons"> message</i>
</a>
</div>
<ul id="notificationsDropdown" class="dropdown-content">
</ul>
I'm using the following Javascript to populate the menu with notifications. This is working just fine.
// Reset Notification Dropdown
notificationsDropdown.innerHTML = '';
notifications.forEach(notif => {
const displayTime = moment(notif.date).fromNow();
let typeIcon = 'sms';
if (notif.type === 'chat') {
typeIcon = 'lock';
}
notificationsDropdown.innerHTML += `<li class="notification">
<a style="margin-top:0px;margin-bottom:0px;padding-bottom: 0;font-size:14px" href="#" class="blue-text">
<span class="js-patientName">
${notif.contact.firstName} ${notif.contact.lastName}</span>
<span class="js-notificationPhone" style="display:none">${
notif.contact.phone
}</span>
<span class="js-patientId" style="display:none">${
notif.patientId
}</span>
<span class="js-patientDOB" style="display:none">${
notif.contact.birthDate
}</span>
<p style="margin-top:0px;margin-bottom:0px;padding-bottom: 0;padding-top: 0;">
<i style="display: inline-flex; vertical-align:middle" class="tiny material-icons">${typeIcon}</i>
<span class="black-text" style="font-size:12px">
${displayTime}
</span>
</p>
</a></li>`;
});
notificationsDropdown.innerHTML += `<li class="divider" class="blue-text"></li><li><a href="/notifications" class="blue-text">See All Notifications</a></li>`;
}
The dropdown gets populated and when a user clicks on a particular dropdown .li entry depending on the exact location they click, it may or not work. The user must click at the main top of the dropdown item.
This is the event listener code that extracts the values from the hidden span elements.
document
.querySelectorAll('#notificationsDropdown', '.li .a .notification')
.forEach(input =>
input.addEventListener('click', async e => {
// console.log('clicked', e.target);
console.log(e.target.parentNode);
const name = e.target.children[0].textContent.trim();
const phone = e.target.children[1].textContent.trim();
const patientId = e.target.children[2].textContent.trim();
const birthDate = e.target.children[3].textContent.trim();
console.log('patientid ', patientId);
const patient = {
name,
patientId,
phone,
birthDate
};
Is there a way I can rewrite the eventListener code to resolve this issue? Possibly instead of using e.target.children[insert_number_here].textContent I could use .closest('js-patientId') or similar ?
This is how the HTML is rendered to the page. This is an example of a single notification:
<ul
id="notificationsDropdown"
class="dropdown-content"
tabindex="0"
style="display: block; width: 177.297px; left: 1648.7px; top: 0px; height: 251px; transform-origin: 100% 0px; opacity: 1; transform: scaleX(1) scaleY(1);"
>
<li class="notification">
<a
style="margin-top:0px;margin-bottom:0px;padding-bottom: 0;font-size:14px"
href="#"
class="blue-text"
>
<span class="js-patientName">ANDREW TAYLOR</span>
<span class="js-notificationPhone" style="display:none">
5555551212
</span>
<span class="js-patientId" style="display:none">
1
</span>
<span class="js-patientDOB" style="display:none">
1960-01-01
</span>
<p style="margin-top:0px;margin-bottom:0px;padding-bottom: 0;padding-top: 0;">
<i
style="display: inline-flex; vertical-align:middle"
class="tiny material-icons"
>
sms
</i>
<span class="black-text" style="font-size:12px">
2 hours ago
</span>
</p>
</a>
</li>
<li class="divider" />
<li>
<a href="/notifications" class="blue-text">
See All Notifications
</a>
</li>
</ul>;
I was able to remove the in each li. Then adjust the value assignment to use the following:
e.target.parentNode.children[0].textContent.trim();