checking for undefined variable in underscore temp

2019-04-18 16:20发布

问题:

I show a modal view of libraryPrep objects in my template like this:

if (_.isUndefined(this.libraryPreps)) {
                this.$el.html(this.template({  }));
            } else {
                this.$el.html(this.template({ libraryPreps: this.libraryPreps.toJSON() }));
            }

The else statement works when I have a libraryPreps object. In my template, I use it like this:

<select id="libraryPreps" >
                    <%  if (!_.isUndefined(libraryPreps)) { %>
                    <% _.each(libraryPreps, function (libraryPrep) { %>
                    <option value="<%=libraryPrep.id%>"><%= libraryPrep.name %></option>
                    <% }); %>
                    <% } %>
                </select>

When I don't have a libraryPreps object, I don't get my template to render and I get an error on the console that libraryPreps is undefined. Am I checking for undefined incorrectly in my template? I feel like I'm checking it the same way in my backbone modal view, but for some reason, in my actual template, it doesn't seem to work. Is my template notation correct? Thanks.

回答1:

If you're passing the variable to a function, it is getting evaluated and will throw an error as there is no such variable. In your backbone view, in contrast, you're accessing a property of an object which will always work (and return the undefined value if no property with that name exists).

Instead, you will have to use the typeof operator on it, that will even work for undeclared variables (have a look at variable === undefined vs. typeof variable === "undefined" and JavaScript check if variable exists (is defined/initialized)):

<select id="libraryPreps"><%
    if (typeof libraryPreps !== "undefined") {
        _.each(libraryPreps, function (libraryPrep) { %>
            <option value="<%=libraryPrep.id%>"><%= libraryPrep.name %></option><%
        });
    }
%></select>

To use _.isUndefined in your template, you'd need to make the value explicitly available in the template. From the docs:

By default, template places the values from your data in the local scope via the with statement. However, you can specify a single variable name with the variable setting. This can significantly improve the speed at which a template is able to render.

_.template("Using 'with': <%= data.answer %>", {answer: 'no'}, {variable: 'data'});
=> "Using 'with': no"

So with that, you can write templates like this:

 <% if (!_.isUndefined(data.libraryPreps)) { %> …
 <% if ("libraryPreps" in data) { %> …


回答2:

I had a similar problem, I found the following solution:

Instead of: if (typeof libraryPreps !== "undefined") {

Use: if (!_.isUndefined(obj.libraryPreps)) {



回答3:

I know this involves a old thread. But this issue still remaines active.

I've created a solution for my own stack. Might be usefull for other programmers.

This code checks whether variables are undefined or null. In case variables are undefined or null the variable name is returned. (With template syntax).

This change is tested for underscorejs v1.6.0. With minor changes this will work up to 1.9.1. Further looking to Lodash. This will work with minor adjustments!

In the dev build of underscore on:

v1.6.0 rule: 1239

Newer versions rule: 1575

Old code:

if (escape) {
  source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
}
if (interpolate) {
  source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
}
if (evaluate) {
  source += "';\n" + evaluate + "\n__p+='";
}

New code:

if (escape) {
    source += "'+\n((typeof " + escape + " === \"undefined\" || " + escape + " === null) ? \"<%-" + (escape.toString()) + "%>\": _.escape(" + escape + "))+\n'";
}
if (interpolate) {
    source += "'+\n((typeof " + interpolate + " === \"undefined\" || " + interpolate + " === null) ? \"<%=" + (interpolate.toString()) +"%>\":" + interpolate + ")+\n'";
}
if (evaluate) {
    source += "';\n" + evaluate + "\n__p+='";
}