I am creating dashboard where I have created a layout for sidebar and different pages of sidebar have different content.
here is the layout.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= pageTitle %></title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/layout.css">
<%- css %>
</head>
<body>
<div class="admin-container">
<!-- Enhanced Sidebar -->
<button class="mobile-menu-toggle">
<i class="fas fa-bars-staggered"></i>
</button>
<!-- Add overlay div -->
<div class="sidebar-overlay"></div>
<aside class="sidebar">
<div class="sidebar-header">
<a href="/admin" class="sidebar-brand">
<i class="fas fa-court fa-fw"></i>
CourtCraft
</a>
</div>
<nav class="sidebar-menu">
<div class="menu-title">Main Menu</div>
<div class="menu-item">
<a href="/admin" class="menu-link <%= path === '/admin' ? 'active' : '' %>">
<span class="menu-icon">
<i class="fas fa-chart-line"></i>
</span>
<span class="menu-text">Dashboard</span>
</a>
</div>
<div class="menu-item">
<a href="/admin/vendor-requests" class="menu-link <%= path === '/admin/vendor-requests' ? 'active' : '' %>">
<span class="menu-icon">
<i class="fas fa-user-plus"></i>
</span>
<span class="menu-text">Vendor Requests</span>
</a>
</div>
<div class="menu-item">
<a href="/admin/venues" class="menu-link <%= path === '/admin/venues' ? 'active' : '' %>">
<span class="menu-icon">
<i class="fas fa-building"></i>
</span>
<span class="menu-text">All Venues</span>
</a>
</div>
<div class="menu-title">System</div>
<div class="menu-item">
<a href="/admin/manage-notification" class="menu-link <%= path === '/admin/manage-notification' ? 'active' : '' %>">
<span class="menu-icon">
<i class="fas fa-bell"></i>
</span>
<span class="menu-text">Notifications</span>
</a>
</div>
<div class="menu-item">
<a id="logout-button" class="menu-link">
<span class="menu-icon">
<i class="fas fa-sign-out-alt"></i>
</span>
<span class="menu-text">Logout</span>
</a>
</div>
</nav>
</aside>
<!-- Main Content -->
<main class="main-content">
<div class="top-bar">
<h1 class="page-title"><%= pageTitle %></h1>
<div class="user-menu">
<div class="notifications">
<i class="fas fa-bell notification-icon"></i>
<span class="notification-badge">3</span>
</div>
<div class="user-profile">
<img src="https://ui-avatars.com/api/?name=Admin&background=0D8ABC&color=fff" alt="Admin" class="user-avatar">
<div class="user-info">
<div class="user-name">Admin</div>
<div class="user-role">Super Admin</div>
</div>
<div class="dropdown-menu">
<a href="/admin/change-password" class="dropdown-item">Change Password</a>
<a id="logout-button" class="dropdown-item">Logout</a>
</div>
</div>
</div>
</div>
<div class="content-wrapper">
<%- body %>
</div>
</main>
<div id="logout-modal" class="logout-modal">
<div class="modal-content">
<h3>Are you sure you want to logout?</h3>
<p>Do you really want to log out from your account?</p>
<div class="modal-actions">
<button id="confirm-logout" class="btn btn-confirm">Yes, Logout</button>
<button id="cancel-logout" class="btn btn-cancel">Cancel</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const menuToggle = document.querySelector('.mobile-menu-toggle');
const sidebar = document.querySelector('.sidebar');
const overlay = document.querySelector('.sidebar-overlay');
function toggleSidebar() {
sidebar.classList.toggle('active');
overlay.classList.toggle('active');
}
menuToggle.addEventListener('click', toggleSidebar);
overlay.addEventListener('click', toggleSidebar);
// Close sidebar when clicking outside on mobile
document.addEventListener('click', (e) => {
if (window.innerWidth <= 1024) {
if (!sidebar.contains(e.target) &&
!menuToggle.contains(e.target) &&
sidebar.classList.contains('active')) {
toggleSidebar();
}
}
});
// Handle window resize
window.addEventListener('resize', () => {
if (window.innerWidth > 1024) {
sidebar.classList.remove('active');
overlay.classList.remove('active');
}
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const logoutButton = document.getElementById('logout-button');
const logoutModal = document.getElementById('logout-modal');
const confirmLogoutButton = document.getElementById('confirm-logout');
const cancelLogoutButton = document.getElementById('cancel-logout');
logoutButton.addEventListener('click', (e) => {
e.preventDefault();
logoutModal.style.display = 'flex';
});
confirmLogoutButton.addEventListener('click', () => {
window.location.href = '/admin/logout';
});
cancelLogoutButton.addEventListener('click', () => {
logoutModal.style.display = 'none';
});
window.addEventListener('click', (e) => {
if (e.target === logoutModal) {
logoutModal.style.display = 'none';
}
});
});
</script>
</body>
</html>
I have created on page for dashboard which is working fine and one page for vendor request which always give me error and I have verified many times for closing page
here is vendor-request page content:
<%- include('layouts/admin-layout', {
css: `<link rel="stylesheet" href="/css/vendor-requests.css">`,
body: `
<div class="vendor-requests-container">
<div class="header">
<h1>Vendor Requests</h1>
<p>Manage incoming vendor requests seamlessly</p>
</div>
<div id="vendor-requests-list" class="vendor-tiles">
<%- if (vendorRequests && vendorRequests.length > 0) { %>
<% vendorRequests.forEach(function(request) { %>
<div class="vendor-tile">
<img src="/images/vendor-placeholder.png" alt="Vendor Image" class="vendor-img" />
<div class="vendor-info">
<h2 class="vendor-name"><%= request.name %></h2>
<p class="vendor-email"><%= request.email %></p>
<p class="request-date">Request Sent: <%= request.requestDate %></p>
</div>
<div class="vendor-actions">
<button class="action-dots" data-id="<%= request.id %>">⋮</button>
<div class="dropdown-menu" id="dropdown-<%= request.id %>">
<button class="dropdown-item btn-details" data-id="<%= request.id %>">View Details</button>
<button class="dropdown-item btn-accept" data-id="<%= request.id %>">Accept</button>
<button class="dropdown-item btn-reject" data-id="<%= request.id %>">Reject</button>
</div>
</div>
</div>
<% }) %>
<% } else { %>
<p class="no-requests">No vendor requests available</p>
<% } %>
</div>
</div>
<script>
document.addEventListener('click', function(e) {
if (e.target.classList.contains('action-dots')) {
const dropdownId = e.target.dataset.id;
document.querySelectorAll('.dropdown-menu').forEach(menu => {
if (menu.id === 'dropdown-' + dropdownId) {
menu.classList.toggle('show');
} else {
menu.classList.remove('show');
}
});
} else {
document.querySelectorAll('.dropdown-menu').forEach(menu => menu.classList.remove('show'));
}
});
</script>
`
}) %>
now if I remove the this code part:
<div id="vendor-requests-list" class="vendor-tiles">
<%- if (vendorRequests && vendorRequests.length > 0) { %>
<% vendorRequests.forEach(function(request) { %>
<div class="vendor-tile">
<img src="/images/vendor-placeholder.png" alt="Vendor Image" class="vendor-img" />
<div class="vendor-info">
<h2 class="vendor-name"><%= request.name %></h2>
<p class="vendor-email"><%= request.email %></p>
<p class="request-date">Request Sent: <%= request.requestDate %></p>
</div>
<div class="vendor-actions">
<button class="action-dots" data-id="<%= request.id %>">⋮</button>
<div class="dropdown-menu" id="dropdown-<%= request.id %>">
<button class="dropdown-item btn-details" data-id="<%= request.id %>">View Details</button>
<button class="dropdown-item btn-accept" data-id="<%= request.id %>">Accept</button>
<button class="dropdown-item btn-reject" data-id="<%= request.id %>">Reject</button>
</div>
</div>
</div>
<% }) %>
<% } else { %>
<p class="no-requests">No vendor requests available</p>
<% } %>
</div>
The view renders fine but with this always give me error of:
Could not find matching close tag for "<%-".
Any help will be appreciated to resolve this issue
Your vendor-request page contains an EJS tag <%-
that appears in a string inside another EJS tag. This cannot be handled by the EJS parser, but you can circumvent it by writing the percent sign in the string as \x25
.
For example, instead of
<%- "<%- %>" %>
write
<%- "<\x25- \x25>" %>
But if you want the inner percent sign to be treated by EJS like the outer, you must explicitly compile the string containing the \x25
, as demonstrated by the following example (much simplified compared to your question):
test.ejs
<!DOCTYPE html>
<html>
<%- include("include", {
body: compile("<div><\x25- name \x25></div>")(locals)
}) %>
</html>
include.ejs
<body>
<%- body %>
</body>
Node.js
const {compile} = require("ejs");
app.get("/", function(req, res) {
res.render("test.ejs", {name: "...", compile});
});