htmlnode.jsexpresssyntaxejs

EJS Syntax issue Could not find matching close tag for "<%-" in node js


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


Solution

  • 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});
    });