Where should I define JS function to call in EJS template
Asked Answered
C

8

33

I am working on a template where I am trying to render template using express and ejs. As to the standard structure of node app, I have app.js file which which contains functions like following:

app.locals.getFlag = function(country) {
var flag_img_name = "";
if (country.toLowerCase() == "us") {
    flag_img_name = "flag_us16x13.gif";
}   
else if (country.toLowerCase() == "ca"){
    flag_img_name = "flag_ca16x13.gif";
}
return flag_img_name;
}

I have some_template.ejs file which calls this function like follows:

<img src="http://some_url_path/<%=getFlag(data_point[0].country_name) %>" width="16" height="14" alt="country" >

and it works just fine. However, I have around 15-20 functions like this and I don't want to define all of them in app.js. Is there any other place where I can define these functions and call them in the template same way as I am doing now? If yes, what would be the way to define them so that they are accessible like they are right now.

I am new to node, express and ejs and not sure of different techniques. If someone could shed a light over it, it would be great. Thank you in advance.

Crazed answered 29/5, 2015 at 17:7 Comment(0)
C
55

Just posting this answer here for someone who would might end up on this question while resolving same issue.

All you have to do is create new file (say functions.ejs) and include it in the .ejs file where you want to call that function. So, I have function like this in file named functions.ejs:

<%
getPriceChgArrow = function(value) {
    arrow_img_name = "";
    if (value < 0) {
        arrow_img_name = "arrow_down12x13.gif";
    }
    else {
        arrow_img_name = "arrow_up12x13.gif";
    }
    return arrow_img_name;
}
%>

Then include functions.ejs into the file you want to call function from. Say, I want to call this function in quote.ejs file. So, I would include it as follows:

<% include *file_path*/functions %> 

Just use this function at appropriate location in your ejs file from where you want to call it. For example:

<img src = "http:/some_url/<% getPriceChgArrow(data_point[0].value) %>" />

and you are all set. Hope this helps someone.

Crazed answered 29/5, 2015 at 21:54 Comment(5)
I get function_name is not defined any ideas?Lita
Is your function inside opening and closing tags (<% .... %>) in the file where you have defined it?Crazed
It didn't work for me too, but worked in that way.Incisor
Can i call this <img src = "http:/some_url/<% getPriceChgArrow(data_point[0].value) %>" /> from js directly ?Avarice
Good luck testing this! I think that Faaiq's answer should be the accepted one.Verina
W
39

Create common functions in js file helper.js.

function common1() {
    //function body
}
function common2(key) {
    //function body
}
module.exports = {
    common1: common1,
    common2: common2
}

And then require this file in your node function

var helper = require('./helper');

and then pass this helper with ejs render

res.render('index', { helper:helper });

And use your function is ejs file

<%= helper.common1() %>

That's It

Whacky answered 31/1, 2020 at 7:6 Comment(5)
For me doesn't work; module.exports shouldn't have key value pairs. @Rik's comment below shows correct module.exports formatting.Bower
module.exports does in fact have key-value pairs; the alternate syntax of module.exports = { oneFn, anotherFn } is taking advantage of an ES6 feature called Enhanced Object Literals, specifically property value shorthand. The key-value pairs are just happening transparently.Bootery
This worked for me. I was able to easily pass a reference to a Functions file I use in Models and Controllers to the EJS context like: res.status(200).render('view', { Functions: Functions, other:data })Therewith
This worked for me and should be the accepted answer tbh. I struggled way to long to try and get the accepted answer to even compile. I had this answer working and refactored within 30mins and is a great way of doing this.Limit
Even now that <%= helper.common1 %> prints the function definition. When I try to use the function with a button in the ejs file. It doesn't work. <button onclick="<%= helper.common1() %>">Helper 1</button>Penitent
L
13

Well, for some reason the accepted answer didn't worked out for me. Also it doesn't makes sense to create a separate *.ejs file for each of my functions and then importing the file in view - specially when I have very simple logic to be implemented.

In fact it is very simple and easy to define function and use it in the view

I did this:

<%
   // ------ Define a function
   get_tree = function(tree){
      for(var i in tree){
%>
     <%= tree[i].title %>
<%
      }
   }
  // ----- Call the above declared function
  get_tree(tree);
%>

And it works!

Thanks

Leanto answered 5/12, 2016 at 6:57 Comment(2)
Yes your approach makes sense too. The only reason I created separate functions.ejs file is because I wanted to keep all my functions together. The one I have shown below is just one of the many functions that I am using throughout application.Crazed
Okay I understand but, in first of all its not a good practice to have logic on "view", well of course there cud be exceptions but, again all computations and calculations should be implemented in logic side, once done then you send it to view to " render".Leanto
L
8

You can just require a separate file and set app.locals to this

app.locals = require('./path/helpers')

In helpers.js:

getFlag = function(country) {
var flag_img_name = "";
if (country.toLowerCase() == "us") {
    flag_img_name = "flag_us16x13.gif";
}   
else if (country.toLowerCase() == "ca"){
    flag_img_name = "flag_ca16x13.gif";
}
return flag_img_name; 
}
anotherFunction=function(x){
return 'hello '+x
}

   module.exports={getFlag, anotherFunction}
Leary answered 6/1, 2019 at 0:55 Comment(2)
in my controller action, ReferenceError: app is not defined . Where do you put your first snippet? (That is to say: where should app.locals be assigned?)Sialoid
To answer my own comment, anywhere where const app = express(); is defined or imported, such as app.js itself.Sialoid
E
3

It seems the easiest way to do this is to pass the function in attached to the object with all the data for the render:

in your js:

const data = {
  ...all other data,
  getFlags: function(country) {
    var flag_img_name = "";

    if (country.toLowerCase() == "us") {
      flag_img_name = "flag_us16x13.gif";
    } else if (country.toLowerCase() == "ca"){
      flag_img_name = "flag_ca16x13.gif";
    }

    return flag_img_name;
  }
};

ejs.render(template, data);

in your template:

<img src="http://some_url_path/<%=getFlag(data_point[0].country_name) %>" width="16" height="14" alt="country" >
Engenia answered 6/8, 2018 at 19:44 Comment(0)
G
2

The order you setup your file has an importance on how the functions are defined. The execution is top to bottom not on document evaluation. Example below to setup your functions.

document.html

<section class="container">
    <%- include('./helpers/common') %>
    <%- include('./home') %>
</section>

common.ejs

<%
MyFunction = function() {
    // Write your code here
}
%>

home.ejs

<% if(MyFunction() ) { %>
    <!-- Write your HTML markup -->
<% }%>
Guarneri answered 7/1, 2020 at 20:5 Comment(0)
P
0

I have two solutions that may not suit everyone.

1. The "grab and run" method

At the top of main.ejs write the following construct

<% const helpers = {}; include('./helpers', { helpers }); %>

Inside helpers.ejs write the following:

<%

Object.assign(helpers, {
  lower(arg) { return String(arg).toLowerCase() },
  upper(arg) { return String(arg).toUpperCase() },
  // some other helpers here

})

%>

Now in main.ejs we can use these functions

<h1><%= helpers.upper('your text here') %></h1>

2. World mutation method

This is similar to the previous method, but instead of mutating the local helpers variable, a "variable_object" from the parent context is passed inside the helpers.ejs file, which is supplemented with the necessary variables.

This is what it looks like:

At the top of main.ejs write the following:

<% include('./helpers', { locals }); %>

In helpers.ejs

Object.assign(locals, {
  lower(arg) { return String(arg).toLowerCase() },
  upper(arg) { return String(arg).toUpperCase() },
  // some other helpers here
});

now in main.ejs

<%= upper('lololo') %>

Good luck!

Profess answered 23/9, 2023 at 23:4 Comment(0)
L
-1

In a js file, create a instance of the function like: if your function name is test (), Var ren = test (); will create a reference to this function.

Before rendering data to the ejs page add the reference variable ren to that object:

Data.ren = ren();

Res.render(Data)

And now in ejs while when you call <% ren() %> it will call the fonction.

Lucillalucille answered 18/11, 2018 at 10:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.