Keywords: EJS Templates | JSON Iteration | Node.js | Template Engine | JavaScript Data Processing
Abstract: This article provides an in-depth exploration of common error patterns when handling JSON data in EJS templates, particularly issues arising from the misuse of JSON.stringify(). Through analysis of a typical example, it explains why directly iterating over stringified data yields unexpected results and presents correct solutions. The article also discusses the characteristics of JavaScript execution context in EJS templates, explaining why certain client-side code (like alert) doesn't work properly in EJS. Finally, by comparing the advantages and disadvantages of different approaches, it proposes best practices for efficiently processing JSON data in EJS.
Introduction: Common Misconceptions in JSON Processing with EJS Templates
When using the EJS (Embedded JavaScript) templating engine, developers frequently need to handle JSON data passed from the server to the client. A common requirement is to iterate through this data within templates to dynamically generate HTML content. However, due to insufficient understanding of EJS execution context and JavaScript data type conversion, many developers fall into typical traps.
Problem Analysis: Why JSON.stringify() Causes Iteration Errors
Consider this typical erroneous code example:
<% for(var i=0; i<JSON.stringify(data).length; i++) { %>
<tr>
<td>
<%= JSON.stringify(data)[i].id %>
</td>
</tr>
<% } %>The root cause of this problem lies in misunderstanding the JSON.stringify() method. JSON.stringify() converts JavaScript objects to JSON strings, rather than returning the original array. For example, with the following data:
var data = [
{ id: 1, name: "bob" },
{ id: 2, name: "john" },
{ id: 3, name: "jake" }
];JSON.stringify(data) actually returns:
"[{\"id\":1,\"name\":\"bob\"},{\"id\":2,\"name\":\"john\"},{\"id\":3,\"name\":\"jake\"}]"This is a string whose length is the character count (approximately 70 characters in this example), not the element count of the original array (3 elements). Therefore, when using JSON.stringify(data).length as the loop condition, the loop executes approximately 70 times instead of the expected 3 times.
Correct Solution: Using Raw Data Directly
The correct approach is to use the raw JavaScript array passed from the server directly, rather than converting it to a string. Here's the corrected code:
<table>
<% for(var i=0; i < data.length; i++) { %>
<tr>
<td><%= data[i].id %></td>
<td><%= data[i].name %></td>
</tr>
<% } %>
</table>How this code works:
datais the raw JavaScript array object passed from the serverdata.lengthcorrectly returns the element count of the array (3)data[i].idanddata[i].namedirectly access the properties of array elements- EJS's
<%= %>tags automatically convert values to strings for output
Execution Context Analysis: Why alert() Doesn't Work in EJS
Another common issue is attempting to use client-side JavaScript functions like alert() in EJS templates:
<% alert('t'); %> or <% window.alert('t'); %>This causes a "not defined" error because JavaScript code within EJS templates executes on the server side, not in the browser. The EJS templating engine runs on the Node.js server, converting templates to HTML strings before sending them to the client. In the server-side execution environment:
alert()and thewindowobject are browser-specific APIs that don't exist in Node.js- Code within
<% %>tags in EJS templates executes on the server - Only code within
<script>tags executes in the client browser
If you need to display an alert box on the client side, the correct approach is:
<script>
alert('t');
</script>Advanced Techniques: Safely Passing JSON Data
In some scenarios, you genuinely need to pass JSON data to client-side JavaScript. In such cases, security considerations are important:
<script>
var row = <%- JSON.stringify(data) %>;
// Now row is a JavaScript array available on the client side
console.log(row);
// Can be further processed in client-side JavaScript
row.forEach(function(item) {
console.log(item.id, item.name);
});
</script>Here, EJS's <%- %> tag (unescaped output) is used because JSON.stringify() already generates valid JSON strings. However, note:
- Ensure data doesn't contain malicious content
- For user-generated content, consider using
JSON.stringify()with appropriate filtering - Avoid XSS attacks by ensuring output content is properly escaped
Performance Optimization Recommendations
When handling large amounts of data, performance considerations become important:
- Avoid Repeated Calls: Don't repeatedly call
JSON.stringify(data)within loops, as this causes unnecessary performance overhead - Cache References: For frequently accessed data, cache it in local variables
- Use EJS Local Variables: EJS supports local variable passing, which can reduce global lookups
Best Practices Summary
Based on the above analysis, best practices for handling JSON data in EJS include:
- Using raw JavaScript objects directly in template logic, rather than stringified versions
- Clearly distinguishing between server-side execution (
<% %>) and client-side execution (<script>) code - When data needs to be passed to the client, using
<%- JSON.stringify(data) %>to safely output JSON - Always properly escaping and validating user input data
- Avoiding repeated calculations in loops and caching frequently used values to improve performance
By following these principles, developers can avoid common pitfalls and write secure, efficient EJS template code.