Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Feature request: Context delimeter for prefix free output #29

Closed
dannyc opened this Issue · 8 comments

5 participants

@dannyc

Hi,
It would be nice if there was a context delimeter. Instead of needing to add "it" as a prefix for every data reference.

<div>Hi {{=it.name}}!</div>
<div>{{=it.age || ''}}</div>

becomes

{{$ it}}
<div>Hi {{=name}}!</div>
<div>{{=age || ''}}</div>
{{$}}

Or in a more complex scenario with nesting

var data = {
  "name": "Jake",
  "age":31,
  "mother":"Kate",
  "father":"John",
  "interests": ["basketball","hockey","photography"],
  "contact": {
    "email":"jake@xyz.com",
    "phone":"999999999"
  }
}

Could be used like this:

{{$ it}}
  <div>I'm {{=name}} and I love..</div>
  <ul>
    {{~interests :value}}
      <li>{{=value}}!</li>
    {{~}}
  </ul>
  <div>Please contact me</div>
  {{$ contact}}
    Phone: {{=phone}}
    Email: {{=email}}
  {{$}}
{{$}}

I roughly tried something along these lines in my fork some time back but never really tested or used it. This give a few big advantages. 1) Easier to read the templates without "it" everywhere. 2) If the data structure ever changes- (i.e. something gets nested inside another object when previously it had not) fixing the template is simply a matter of adding a new context delimiter.

Thoughts?
Thanks!

@LarryBattle

Just use the with keyword in Javascript. Your feature would be really easy to implement since it's almost the same as the if condition, {{~}}. I didn't have any time so I didn't try but here's a working solution without hacking doT.js.

Use {{ with ( it ){ }}, {{ } }} in place of {{ $ it }}, {{ $ }} respectively.

Which gives the following.

var template = "{{with (it){ }}";
template += "<div>I'm {{=name}} and I love..</div>"
template += "<ul>"
template += "{{~interests :value}}"
template += "<li>{{=value}}!</li>"
template += "{{~}}"
template += "</ul>"
template += "<div>Please contact me</div>"
template += "{{ with ( contact ) { }}"
template += "Phone: {{=phone}}<br/>"
template += "Email: {{=email}}"
template += "{{ } }}"
template += "{{ } }}"

Live demo: http://jsfiddle.net/UVFnr/

@drkibitz

Personally the auto context in mustache, is the most annoying part about it. I like the option of completely ignoring it, but I also think there are plenty of ways to get it in there without the use of the 'with' keyword. Maybe auto generating closures that accept arguments (varname) that are equivalent to the keys of the context object.

Object it.contact {name: "John", age: 40} can be converted to (function (name, age) { return // template string }(it.contact.john, it.contact.age))

@drkibitz

Probably would be simpler and faster if just prepended the context in the compilation process.

@drkibitz

Not sure about the $ character either, but I still like the idea of just concatenating scope automagically to variable names in the compilation.

@olado
Owner

@LarryBattle 'with' would work though with is better avoided. @drkibitz auto-closures would be better. Concatenating automatically - I don't think this would work as we don't know which variables to concatenate to.
One more option is to do something similar to array iterator {{~ it name, age }} where you would have to list properties that you want to use.

@drkibitz

@olado I thought concatenation could work something like the following:

{{$ it}}
    This is {{foo}} // concatenates to "it.foo"
    {{$ bar}}
        This is {{foo}} // concatenates to "it.bar.foo"
        This is {{it.bar.foo}} // Matched scope variable name, no concatenation
    {{$ bar}}
{{$ it}}
This is {{it.baz}} // top level, no concatenation

Basically scope is a stack that always concatenates to the front of variable names.
We know the variable to concatenate from tags that must exist with the variable name.
There are some weird instances here, with the scope matching thing, that might be a bad idea because it.it.it is not possible with that type of functionality.

Alternatively I do like your Object iteration solution:

{{~ it foo, bar}}
    This is {{foo}} // should be value of it.foo
    {{~ bar foo}}
        This is {{foo}} // should be value of it.bar.foo
        This is {{it.bar.foo}} // should also be value of it.bar.foo
    {{~ bar}}
{{~ it}}
This is {{it.baz}} // should be value of it.baz

I'm on the fence here. The first is more like other popular template engines that people are use to. Then second is about the same in ease of use, but slightly more characters needed in the template, although very slightly in my comparison.

@olado
Owner

We don't know which variables to concatenate to because inside of {{ }} can be ANY javascript, not only reference to a variable. This is valid: {{= (function(foo) { return foo; })("hello") }}, same for all other delimiters. Code is allowed in all delimiters, access to global variables is allowed to. Basically all of Javascript is allowed. That's why I don't think automatic would work.

@Pointy

The configurable varname is one of the absolute best features of doT. Dropping that for the questionable convenience of implicit context reference would be a tragedy (to me).

Another problem with this is that doT syntax allows the expression inside {{= }} or {{! }} to be any JavaScript expression. Where would the implicit context go? I suppose that the implicit context thing could apply only to {{= }} expressions where there's nothing but an identifier, but then that'd mean that for more complicated situations you'd have to remember on your own to add the prefixes.

@olado olado closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.