Search code examples
javascripthtmlunderscore.jsunderscore.js-templating

How to get javascript variable to be interpreted as attribute in underscore templates


Lets say I have a the following attributes being passed in to an underscore template: name and animaltype. I also have an attribute that varies based on the animaltype. So for example, if animaltype is CAT, then the attribute is called cat_id. If is the animaltype is DOG, then the attribute is dog_id and so on.

I create an input box for each of the animaltype ids but only the box that has an id of the corresponding animaltype should be populated(mapped in via attributes). This ID input box is the one I cannot get to map to the attribute value because I am using javascript to create the name of the attribute is should be expecting. Therefore the actual javascript variable name is being inserted instead of the corresponding resolved attribute value that matches the javascript variable name.

Here is the fiddle http://jsfiddle.net/leopardy/fev4vqmg/1/

What I should get is
Name: Fluffy
Type: CAT
CAT ID: 005
DOG ID:
BIRD ID:

What I really get is
Name: Fluffy
Type: CAT
CAT ID: cat_id
DOG ID:
BIRD ID:
where the cat_id attribute did not resolve in the template.

As a side note, in my real code I am hiding the other ID input boxes that don't correspond to the animal type but for the sake of keeping things simpler, I didn't including the hiding/showing.


Solution

  • You have the common "I have a variable name in another variable" problem and the solution is the same as it always is: put the things you need to look up by name in a lookup table (i.e. an object in JavaScript).

    In your case, I would not _.extend(attributes, {animalTypes:animalTypes}); to mash everything into one pile, I would leave attributes and animalTypes separate so that your _.template call would look like this:

    var tmpl = _.template(template);
    var html = tmpl({
        animalTypes: animalTypes,
        attributes: attributes
    });
    

    Now you can say things like attributes['cat_id'] in your template. Of course, you'll have to refer to everything through animalTypes or attributes but that's pretty minor. Your template would look something like this:

    <table>
        <tbody>
                <tr>
                    <td>Name:</td>
                    <td>
                        <input name="name" type="text" value="<%= attributes.name %>"/>
                    </td>
                </tr>
                <tr>
                    <td>Type:</td>
                    <td>
                        <input name="animal_type" type="text" value="<%= attributes.animaltype %>"/>
                    </td>
               </tr>
               <% for (var key in animalTypes) { %>
                   <% var typeID= (key).toLowerCase() +"_id" %>
                   <tr>
                       <td><%= key %> ID:</td>
                       <% if (attributes.animaltype === key) { %> 
                           <td>
                               <input value="<%= attributes[typeID] %>" name="<%= typeID %>" type="text"/>
                           </td>
                       <% } else { %>
                           <td>
                               <input value="" name="<%= typeID %>" type="text"/>
                           </td>
                       <% } %>
                   </tr>
               <% } %>
        </tbody>
    </table>
    

    The part the solves your immediate problem is:

    <input value="<%= attributes[typeID] %>" name="<%= typeID %>" type="text"/>
    

    Updated demo: http://jsfiddle.net/ambiguous/qj3ru1mL/1/