Ignoring undefined data / vars in an underscore te

2019-06-15 03:39发布

Still learning backbone so bear with me;

I'm trying to add a new model with blank fields to a view, but the template I've created has a whole bunch of

<input value="<%= some_value %>" type="whatever" />

Works perfectly fine when fetching data, it populates it and all goes well. The trouble arises when I want to create a new (blank) rendered view, it gives me

Uncaught ReferenceError: some_value is not defined

I can set defaults (I do already for a few that have default values in the db) but that means typing out over 40 of them with blanks; is there a better way of handling this?

I'm fiddling around with the underscore template itself, trying something like <%= if(some_value != undefined){ some_value } %> but that also seems a bit cumbersome.

8条回答
老娘就宠你
2楼-- · 2019-06-15 04:11

You can abstract @Dmitri's answer further by adding a function to your model and using it in your template.

For example:

Model :

new Model = Backbone.Model.extend({
    defaults: {
        has_prop: function(prop) {
            return _.isUndefined(this[property]) ? false : true;
        }
    }
});

Template:

<% if(has_prop('property')) { %>
    // Property is available
<% } %>

As the comment in his answer suggests this is more extendable.

查看更多
手持菜刀,她持情操
3楼-- · 2019-06-15 04:12

Actually, you can use arguments inside of your template:

<% if(!_.isUndefined(arguments[0].foo)) { %>
       ...
<% } %>
查看更多
手持菜刀,她持情操
4楼-- · 2019-06-15 04:20

If you check source code for generated template function, you will see something like this:

with (obj||{}) {
  ...
  // model property is used as variable name
  ...
}

What happens here: at first JS tries to find your property in "obj", which is model (more about with statement). This property is not found in "obj" scope, so JS traverses up and up until global scope and finally throws exception.

So, you can specify your scope directly to fix that:

<input value="<%= obj.some_value %>" type="whatever" />

At least it worked for me.

查看更多
Juvenile、少年°
5楼-- · 2019-06-15 04:23

Actually, you can access vars like initial object properties.

If you'll activate debugger into template, you can find variable "obj", that contains all your data.

So instead of <%= title %> you should write <%= obj.title %>

查看更多
We Are One
6楼-- · 2019-06-15 04:24

Pass the template data inside a wrapper object. Missing property access won't throw an error:

So, instead of:

var template = _.template('<%= foo %><%= bar %>');
var model = {foo:'foo'};
var result = template(model); //-> Error

Try:

var template = _.template('<%= model.foo %><%= model.bar %>');
var model = {foo:'foo'};
var result = template({model:model}); //-> "foo"
查看更多
该账号已被封号
7楼-- · 2019-06-15 04:28

A very simple solution: you can ensure that your data collection is normalized, i.e. that all properties are present in each object (with a null value if they are unused). A function like this can help:

function normalizeCollection (collection, properties) {
  properties = properties || [];
  return _.map(collection, function (obj) {
    return _.assign({}, _.zipObject(properties, _.fill(Array(properties.length), null)), obj);
  });
}

(Note: _.zipObject and _.fill are available in recent versions of lodash but not underscore)

Use it like this:

var coll = [
  { id: 1, name: "Eisenstein"},
  { id: 2 }
];

var c = normalizeCollection(coll, ["id", "name", "age"]);
// Output =>
// [
//  { age: null, id: 1, name: "Eisenstein" },
//  { age: null, id: 2, name: null }
// ]

Of course, you don't have to transform your data permanently – just invoke the function on the fly as you call your template rendering function:

var compiled = _.template(""); // Your template string here
// var output = compiled(data); // Instead of this
var output = compiled(normalizeCollection(data)); // Do this 
查看更多
登录 后发表回答