tj / ejs

Embedded JavaScript templates for node
4.47k stars 513 forks source link

Can't check for undefined locals #44

Open samholmes opened 12 years ago

samholmes commented 12 years ago

I can't do typeof someUndefinedLocal == 'undefined' because that will give me an error output saying, "someUndefinedLocal is undefined". Normally, I would be able to do this in JS just fine. If EJS is truely "Embedded JavaScript" then it should at least act like it. For now I have to use typeof this.someUndefinedLocal == 'undefined', but I really wish didn't.

samholmes commented 12 years ago

Actually, I'm not even sure if this.someUndefinedLocal references the local someUndefinedLocal in ejs. x__x

samholmes commented 12 years ago

typeof someUndefinedLocal... works only only if not buffered.

this.someUndefinedLocal does not reference the local.

In conclusion, this issue is about bringing support for undefined locals in buffered outputs <%- %> and <%= %>.

RandomEtc commented 12 years ago

Have you tried hasOwnProperty('someUndefinedLocal') to check for the existence of a parameter? It's not pretty but it might be nicer than checking for undefined.

ForbesLindesay commented 12 years ago

I think you're probably misunderstanding this. EJS literally takes your javascript and puts it in a function then executes it.

Both of these work fine:

<%= typeof foo === "undefined"?'foo is undefined':foo %>
<%- typeof foo === "undefined"?'foo is undefined':foo %>

This won't work, not because of a bug in EJS, but because they don't make sense as javascript.

<%= if(true){"Truth"}else{"False"} %>

Buffered EJS can only accept things that would work as an argument to a function (specifically Array.push). Consider the following invalid JavaScript

function doSomething(arg){
    console.log(arg);
}

doSomething(if(false){"Truth"}else{"False"});

It's the same reason you can't use while, for etc. inside a buffered block (unless you also wrap it in a self-calling function.

If that's not what's causing your problem, then I apologise. Perhaps you could post the full contents of the buffered block that causes the failure.

P.S. I didn't have a variable called foo defined inside my view when running these tests.

web-bert commented 11 years ago

Have you considered implementing a 'safe navigation operator', similar to Grails, which uses a question mark? I found it quite useful.

My use case is a bit different, in that I have an object for the values of a form (because the names conflict with some locals), so for each value attribute on the form elements, I want to pre fill the value; it would be nice to use a compact syntax for that:

<input type="text" value="<%= form?.title %>">
< textarea><%= form?.message %>

Currently I am creating a form object and all its properties to keep the view logic simple, as I don't want to have this in each value:

<%= typeof form === 'undefined' || typeof form.title === 'undefined' ? '' : form.title %>

I know it is deviating slightly from standard JS, but in the context of views I think it is acceptable? It also might make it easier to basically replace the ? with a typeof, so maybe the syntax should be:

<input type="text" value="<%= form?.title? %>">
< textarea><%= form?.message? %>

So it will keep the implementation logic simple?

ForbesLindesay commented 11 years ago

I think that is probably too much bloat to put in ejs itself (it's a fairly complex operation requiring AST manipulation. If it should exit, it should be a language level feature of JavaScript, not a feature specific to Embedded JavaScript.