Skip to content

Instantly share code, notes, and snippets.

@Pointy
Created September 12, 2012 15:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pointy/3707350 to your computer and use it in GitHub Desktop.
Save Pointy/3707350 to your computer and use it in GitHub Desktop.
An approach with doT templates to handling the "option"/"radio" coding mess
<!--
This is the template source for the page containing a "select". In doT
templates the data object is by convention called "it" (though it can
be set to be anything). In this example, I'm inventing a field called
"choice", whose value would presumably have come from the server via
JSON (or whatever) as the property "choice" of the "it" parameter.
In the option elements you'll see the doT construct to fetch a value
from the "it" object, and you'll see that it involves what looks like
a function call. It *is* a function call, a call to another doT template
that is really the point of this. That's in a separate file.
-->
<form id='...' method=post action='...'>
<select name=choice>
<option {{= $T.optionVal("value1", it.choice) }}>The First Choice
<option {{= $T.optionVal("value2", it.choice) }}>The Second Choice
<option {{= $T.optionVal("value3", it.choice) }}>The Third Choice
</select>
<!--
Handling the list of options case
Assume that our "it" object looks like this:
{
"settings" : {
"foo" : "low",
"bar" : "high",
"baz" : "low"
}
}
and we want a labeled set of radio button pairs.
I'll assume a sub-template, "$T.radioVal", that's
like the "optionVal" template only for radio buttons
("checked" instead of "selected" basically). Because
the "settings" value is an object and not an array (which,
if I had control of the server's JSON, I wouldn't do)
I'll need a function to transform that into an array,
which is of course a trivial utility.
-->
{{~ $T.toArray(it.settings) :setting }}
<h2>{{! setting.name }}</h2>
{{~ ["low", "high"] :lowHigh }}
<input type=radio name={{! setting.name }} {{= $T.radioVal(setting.value, lowHigh) }}> {{= lowHigh }}
{{~}}
{{~}}
<!--
This is my doT "optionVal" template. I compile my templates server-side
as part of my Ant-based application build (it's a Java application).
The build includes a home-grown Ant task that extracts templates from
the source and runs them through doT.js via Rhino. The templates are
then combined into a single JavaScript source file as properties of
an eventually global object called $T (my company is called "Tango" :-)
so references to templates is always via that symbol.
This simple template exploits the ability to override the default doT
template signature. I'll show what my code actually looks like; the
little header line is interpreted by the above-mentioned Ant task in
a way that should be obvious.
This template is extremely simple, and an invocation of it is not
much less typing than the code would be, but it's purpose is more to
reduce the chances for a typo in templates that call it.
-->
<%-- template optionVal(value, actual) --%>
value={{! value }} {{= value == actual ? "selected" : "" }}
<!-- The "toArray" function (as a template, though it wouldn't have to be this way -->
<%-- template toArray(obj) --%>
{{
var key, rv = [];
for (key in obj)
if (obj.hasOwnProperty(key))
rv.push({name: key, value: obj[key]});
return rv;
}}
@getify
Copy link

getify commented Sep 12, 2012

I appreciate this gist, but it misses a little bit of the point I was trying to get at with the previous scenario.

The point I was making before was, when you have an arbitrary list of data (like an arbitrary list of select options, in your variation), and for each one, you actually have another >1 list of sub-options, how do you nest loops effectively (dealing with the scoping of data involved).

Secondarily, how, inside the inner most loop, do you do your conditional test. THAT part you've dealt with, but the complications of the first part combined with the second are what I'm trying to explore.

In your case, you don't need an inner loop, because there's only one select. But in my scenario, there's intentionally two choices per option (2 radio buttons), to force the issue how how you deal with nested loops and data namespaces.

@Pointy
Copy link
Author

Pointy commented Sep 12, 2012

OK, well I'll re-read your gist but I'm not sure I see what the difficulty is. Nested loops in doT are just nested JavaScript loops, and the whole template is contained in a single JavaScript function. Thus nesting loops in doT looks essentially the same as nested loops in JavaScript.

@getify
Copy link

getify commented Sep 12, 2012

the difficulty, at least for a lot of templating engines, is that there's some namespace scope collision difficulty with two nested loops, when inside the inner loop you need to reference the key/iterator from the outer loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment