如何在Node.js与EJS中为本地JSON数据添加排序功能?
Hey there! Let's figure out how to add sorting functionality to your EJS template that renders data from a local JSON file. I'll walk you through two practical approaches—server-side sorting (pre-rendering sorted data) and client-side sorting (sorting after the page loads)—so you can pick what works best for your use case.
This approach sorts your JSON data before passing it to the EJS template, which is great for default sorting or if you want to avoid client-side processing. If you want to let users toggle sort order (ascending/descending), we can add URL parameter support too.
Step 1: Sort data in your server code
Assuming you're using Express to serve your EJS templates, here's how to read your JSON file, sort the t_upcoming array, and pass it to the template:
const fs = require('fs'); const express = require('express'); const app = express(); app.set('view engine', 'ejs'); app.get('/your-page-route', (req, res) => { // Read and parse your local JSON file const rawJson = fs.readFileSync('./path/to/your/data.json'); const data = JSON.parse(rawJson); // Get sort preferences from URL params (default to date/time ascending) const sortOrder = req.query.order || 'asc'; const sortBy = req.query.sortBy || 'dateTime'; // Create a copy of the array to avoid modifying the original JSON data let sortedUpcoming = [...data.t_upcoming]; // Sort by date + time (convert strings to Date objects for accurate comparison) if (sortBy === 'dateTime') { sortedUpcoming.sort((a, b) => { const dateTimeA = new Date(`${a.date} ${a.time}`); const dateTimeB = new Date(`${b.date} ${b.time}`); return sortOrder === 'asc' ? dateTimeA - dateTimeB : dateTimeB - dateTimeA; }); } // Pass sorted data + current sort state to EJS res.render('your-template', { data: { ...data, t_upcoming: sortedUpcoming }, currentSort: sortBy, currentOrder: sortOrder }); });
Step 2: Add sort controls to your EJS template
Update your table header to let users click and toggle sort order:
<thead> <tr> <th> <a href="?sortBy=dateTime&order=<%= currentOrder === 'asc' ? 'desc' : 'asc' %>" style="color: inherit; text-decoration: none;"> Date & Time <% if (currentSort === 'dateTime') { %> <span><%= currentOrder === 'asc' ? '↑' : '↓' %></span> <% } %> </a> </th> <th>Camera</th> <th>Course</th> </tr> </thead> <!-- Your existing tbody rendering code stays mostly the same --> <tbody> <% data.t_upcoming.forEach((record) => { %> <tr> <td><%=record.date%> <span style="display: block;font-size:10pt;"><%=record.time%></span> <p class="timer" style="font-size: 8pt; color: red;"></p> </td> <td> <input type="image" class="web_camera" src="/img/camera.png"> </td> <td><a style="color:black;" href='/course-...'>...</a></td> </tr> <% }) %> </tbody>
If you want a smooth, no-refresh sorting experience (great for small datasets), you can handle sorting entirely in the browser.
Step 1: Store raw data in your EJS template
Add a script tag to your template to make the raw JSON data accessible to client-side JS:
<script> // Expose the raw upcoming data to client-side code const upcomingRecords = <%= JSON.stringify(data.t_upcoming) %>; let currentSortOrder = 'asc'; </script>
Step 2: Write client-side sort logic
Add a function to sort the data and re-render the table:
<script> function sortUpcomingByDateTime() { // Sort the records const sorted = [...upcomingRecords].sort((a, b) => { const dateTimeA = new Date(`${a.date} ${a.time}`); const dateTimeB = new Date(`${b.date} ${b.time}`); return currentSortOrder === 'asc' ? dateTimeA - dateTimeB : dateTimeB - dateTimeA; }); // Re-render the tbody const tbody = document.querySelector('tbody'); tbody.innerHTML = ''; sorted.forEach(record => { const row = document.createElement('tr'); row.innerHTML = ` <td>${record.date} <span style="display: block;font-size:10pt;">${record.time}</span> <p class="timer" style="font-size: 8pt; color: red;"></p></td> <td><input type="image" class="web_camera" src="/img/camera.png"></td> <td><a style="color:black;" href='/course-...'>...</a></td> `; tbody.appendChild(row); }); // Toggle sort order and update icon currentSortOrder = currentSortOrder === 'asc' ? 'desc' : 'asc'; document.getElementById('sort-icon').textContent = currentSortOrder === 'asc' ? '↑' : '↓'; } </script>
Step 3: Add a clickable header for sorting
Update your table header to trigger the sort function:
<thead> <tr> <th onclick="sortUpcomingByDateTime()" style="cursor: pointer;"> Date & Time <span id="sort-icon">↑</span> </th> <th>Camera</th> <th>Course</th> </tr> </thead>
Quick Comparison of Approaches
- Server-Side: Better for large datasets, SEO-friendly, and works well if you need to enforce access controls on sorted data. Requires page reloads for sort changes.
- Client-Side: Smooth, no-refresh experience, perfect for small to medium datasets. Less efficient for very large data since you're loading all records upfront.
内容的提问来源于stack exchange,提问作者dutchkillsg

