Skip to content

Instantly share code, notes, and snippets.

@getify
Created September 11, 2012 06:21
Show Gist options
  • Save getify/3696453 to your computer and use it in GitHub Desktop.
Save getify/3696453 to your computer and use it in GitHub Desktop.
how does your templating approach handle this task?
{
"settings" : {
"foo" : "low",
"bar" : "high",
"baz" : "low"
}
}
<!--
NOTE: see this comment for clarification of why this
scenario is structured this way intentionally:
https://gist.github.com/3696453#gistcomment-570903
Scenario:
Given the data structure above in "1.json", how would you
use a templating engine to generate this snippet of html
as a string? NOTE: the spirit of this question is to
generate a string of markup with a template engine, NOT
to do DOM manipulation. Imagine needing to generate this
kind of markup server-side to send over the wire.
-->
<h1>Settings</h1>
<h2>foo</h2>
<input type="radio" name="foo" value="low" checked> low
<input type="radio" name="foo" value="high"> high
<h2>bar</h2>
<input type="radio" name="bar" value="low"> low
<input type="radio" name="bar" value="high" checked> high
<h2>baz</h2>
<input type="radio" name="baz" value="low" checked> low
<input type="radio" name="baz" value="high"> high
here's how "grips" template engine would handle this scenario:
https://gist.github.com/3706912
@Pointy
Copy link

Pointy commented Sep 12, 2012

Yes, @getify, in doT a loop looks like this:

{{~ collection :item :index }}
  ... template content ...
{{~}}

Inside the loop, "item" and "index" are bound to the array element and its index, respectively. (Loops like that only work on arrays, but that's not a problem because it's so easy to transform an object into an array of name/value pairs.)

@getify
Copy link
Author

getify commented Sep 12, 2012

@simonblee

a few comments:

  1. Imagine if there were 50, 100, 1000 items in the list, and each had 10 possible values (imagine a big survey page grid of radio buttons, for instance). you're talking about creating a huge "sparse" data structure of a bunch of repeated values, so you can specify the "columns" over again for each "row". doesn't that seem crazy inefficient?

    I understand you prefer the idea of being generic, but in some cases, like for a survey, there's a fixed set (or range) of values for the "columns", and it's the UI designer who controls that in the template, not the back-end data layer. Asking the UI designer to create a complex data transform, AND have a whole bunch of extra data in memory, seems unnecessary to me. This is one of those cases where I think the template engine should assist.

  2. If the options array that you loop over had a property called name, would that shadow/override the outer loop's {name} so that you couldn't easily reference it inside the inner loop? How does that sort of variable scoping complication get handled in Dust?

@getify
Copy link
Author

getify commented Sep 12, 2012

@Pointy

So, for a nested loop, would I do this?

{{~ collection :item :index }}
  ... blah ...
  {{~ collection :item2 :index2 }}
     outer item: {{! item }}  and inner item: {{~ item2 }}
  {{~}}
  ... blah ...
{{~}}

@Pointy
Copy link

Pointy commented Sep 12, 2012

Yes, exactly. It seems very natural to me because I'm coming from a JSP background, and that's pretty much exactly how iterating looks in JSP (except of course it's 1000% uglier in JSP :-)

@getify
Copy link
Author

getify commented Sep 12, 2012

@Pointy what happens if you accidentally name the inner loop variables the same as the outer loop variables?

@Pointy
Copy link

Pointy commented Sep 12, 2012

Then the template doesn't work. I try to avoid that :-) I have a hard time thinking of a time that happened to me in JSP (or JavaScript for that matter) any time recently (or not-so-recently even). Generally I use pretty good names (not huge javaProgrammerApproved names but good ones), so that I can stay sane, so unless I've got a list of things with the same sort of thing inside it's pretty easy to keep the names straight. Heck even with a nested loop for a table, I can at least use "row" and "col".

@pasaran
Copy link

pasaran commented Sep 13, 2012

@fearphage
Copy link

doT.js

{{##def.radiogroup:
<h2>{{! name}}</h2>
{{~['low', 'high'] :value}}
<input type="radio" name="{{! name }}" value="{{= value }}"{{? it.settings[name] == value }} checked="checked"{{?}}/>
{{~}}
#}}

{{##def.settings:
<h1>Settings</h1>
{{~Object.keys(it.settings) :name}}
{{#def.radiogroup}}
{{~}}
#}}

{{#def.settings}}

@fearphage
Copy link

doT.js (cleaned up a bit)

{{##def.radiogroup:
  <h2>{{= name}}</h2>
  {{~['low', 'high'] :value}}
    <input type="radio" name="{{= name }}" value="{{= value }}"{{? it.settings[name] == value }} checked="checked"{{?}}/>
  {{~}}
#}}

{{##def.settings:
  <h1>Settings</h1>
  {{~Object.keys(it.settings) :name}}
    {{#def.radiogroup}}
  {{~}}
#}}

{{#def.settings}}

@BorisMoore
Copy link

BorisMoore commented Sep 15, 2012

Here's one approach you can use with JsRender: https://gist.github.com/3730412

UPDATE: The gist has been deleted. It is very easy to do in JsRender using the {{props}} tag

@getify
Copy link
Author

getify commented Sep 16, 2012

thanks @BorisMoore!

@patrick-steele-idem
Copy link

As requested, here's the solution for Raptor Templates. The below template will produce the exact output (less extra whitespace):

<c:template xmlns:c="core" params="settings">

    <h1>Settings</h1>
    <c:for each="(name,value) in settings">
        <h2>$name</h2>
        <c:for each="option in ['low', 'high']">
            <input type="radio" 
                name="$name" 
                value="$option" 
                checked="${value === option ? null : undefined}" /> 
            $option
        </c:for>
    </c:for>

</c:template>

Admittedly, it is a little odd to use "null" as the value for attributes that do not have a value in the resulting HTML, but it works. However, I prefer to to output checked="checked" at the expense of a few extra bytes since it's cleaner in my implementation and it still produces valid HTML:

<c:template xmlns:c="core" params="settings">

    <h1>Settings</h1>
    <c:for each="(name,value) in settings">
        <h2>$name</h2>
        <c:for each="option in ['low', 'high']">
            <input type="radio" 
                name="$name" 
                value="$option" 
                checked="{?value === option;checked}" /> 
            $option
        </c:for>
    </c:for>

</c:template>

You can easily try out the templates online at http://raptorjs.org/raptor-templates/try-online/

Let me know what you think.

Thanks,
Patrick

@patrick-steele-idem
Copy link

For reference, I created a Gist that shows the input Raptor template, the generated HTML and the compiled template:
https://gist.github.com/3966647

--Patrick

@getify
Copy link
Author

getify commented Oct 28, 2012

Thanks so much Patrick! Very much appreciate the input for Raptor. :)

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