Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

functions in ejs

What I'd like to have is something like this:

app.js (node process, includes etc excluded for brevity but using ejs as rendering engine):

app.get('/', function(req, res){

    var ejsVariables = {
        title : 'ideal ejs function example',
        listData1 : {
            listTitle : 'my list',
            listItems : [
                { name : 'first item', class : 'foo' },
                { name : 'second item', class : 'bar' },
                { name : 'last item', class : 'foo' }                ]
        },
        listData2 : {
            listTitle : 'your list',
            listItems : [
                { name : 'a widget', class : 'foo' },
                { name : 'another widget', class : 'baz' }
            ]
        }
    };

    res.render('index', ejsVariables);
});

index.ejs:

<html>
    <head>
        <title><%= title %></title>
    </head>
    <body>
        <h1><%= title %></h1>

        <% makeList(listData1) %>

        <p>lorem ipsum</p>

        <% makeList(listData1) %>
    </body>
</html>

???


result:

<html>
    <head>
        <title>ideal ejs function example</title>
    </head>
    <body>
        <h1>ideal ejs function example</h1>

        <ul>
            <li class="foo">first item</li>
            <li class="bar">second item</li>
            <li class="foo">another item</li>
        </ul>

        <p>lorem ipsum</p>

        <ul>
            <li class="foo">a widget</li>
            <li class="baz">another widget</li>
        </ul>
    </body>
</html>

Question : what goes in the ??? section and/or should be changed above?


What I've tried so far

Attempt 1

- I really want this to work, it just doesn't

index.ejs

<html>
    <head>
        <title><%= title %></title>
    </head>
    <body>
        <h1><%= title %></h1>
        <% var makeList; %>
        <!-- this variable is declared here as those declared within the include are not
        accessible from the file from which it is called, I'm guessing some sort of 
        function scope is coming into play here -->

        <% include makeList %>

        <% makeList(listData1) %>

        <p>lorem ipsum</p>

        <% makeList(ListData2) %>
    </body>
</html>

makeList.ejs

<% function makeListItem(itemData){ %>
        <li class="<%= itemData.class %>" ><%= itemData.name %></li>
<% } %>

<% makeList = function(data){ %>
    <% if(data){ %>
        <ul>
            <% data.map(makeListItem) %>
        </ul>
    <% } %>
<% } %>

In this situation both makeListItem and makeList are being called, it just appears that due to scoping or something else, when they come to be called they are unable to actually output to the template.


Attempt 2

- this actually works, I just dislike the way I end up using includes instead of some sort of function call.

index.ejs

<html>
    <head>
        <title><%= title %></title>
    </head>
    <body>
        <h1><%= title %></h1>

        <% var data = listData1 %>
        <% include makeList %>

        <p>lorem ipsum</p>

        <% var data = listData2 %>
        <% include makeList %>
    </body>
</html>

makeList.ejs

<% function makeListItem(itemData){ %>
        <li class="<%= itemData.class %>" ><%= itemData.name %></li>
<% } %>

<% if(data){ %>
    <ul>
        <% data.map(makeListItem) %>
    </ul>
<% } %>

Attempt 3

- this basically involved messing around with ejs-locals, however I found the functionality somewhat lacking.

If I'm going to include another npm module in my application I'd really want it to be a more complete solution, but even then in an ideal world I'd rather do without and write it myself.


Apologies for the length of this post, it got out of hand quite quickly. I commend you if you've got this far.

Any input would be greatly appreciated.

like image 256
Joshua Avatar asked Apr 14 '13 22:04

Joshua


People also ask

Can we use document getElementById in EJS?

But the problem is, you cannot use document. getElementById in EJS.


1 Answers

How about this:

// app.js
var ejs = require('ejs');
var fs  = require('fs');

app.locals({
  makeList  : function(list) {
    var template = fs.readFileSync('makeList.ejs', 'utf-8');
    return ejs.render(template, list);
  }
});

// index.ejs
<%- makeList(listData1) %>
  ^ important!

// makeList.ejs
<ul>
  <% listItems.forEach(function(item) { %>
    <li class="<%= item.class %>"><%= item.name %></li>
  <% }); %>
</ul>
like image 183
robertklep Avatar answered Oct 16 '22 07:10

robertklep