Skip to content

Dust little less know language constructs

vybs edited this page Sep 12, 2012 · 2 revisions

Dust little less know constructs

Dust templating provides features to reuse and write DRY markup. Here are some of the concepts that can be used together to create resusable Dust UI components/ modules.

Template Inheritance

Dust by default allows template inheritance with the concept of partials and inline partials

Example 1:

partial.tl ( this serves as the base template )

   {+greeting} Hola {/greeting}
   {+world} World {/world}

main_without_override.tl ( this serves as the child template )

  {>partial/}

output -- When the main_without_override.tl is rendered ...

Hola World

main_with_override.tl ( this serves as the child template )

  {>partial/}
   {<greeting}
     Hello
   {/greeting}
   {<world/}   {! self closing to use the body of the base template !}

output -- When the main_with_override.tl is rendered ...

Hello World

main_with_loops.tl

  {>partial/}
   {#projects
     {<greeting}
       Hello {.name}
    {/greeting}
    {/projects}
    {<world}{/world} {! override to print nothing !}

output -- when the main_with_loops.tl is rendered ... ( says projects has three entries with the name field )

Hello project 1 Hello project 2 Hello project 3

Example 2

base.tl

    {+greeting}hello{/greeting}
    {+world/}

footer.tl

  Common footer

base_end.tl

    {>"footer"/}
    {+bye} bye {/bye}

main.tl

      {>"head"/}
        BODY
      {>"foot"/}

head.tl

     {>"base"/}
     {<world} World {/world}
        START

foot.tl

      END
      {>"base"/}
      {<greeting}bye{/greeting}

foot_with_no_end.tl

      END
      {>"base_end"/}
      {<bye}{! Do not print bye !}{/bye}

output --when I render main.tl with foot.tl

hello World START BODY END bye

output -- when I render main.tl with foot_with_no_end.tl

hello World START BODY END common footer

Composable templates

Using conditionals and inline partials and blocks

{^xhr}
  {>base_template/}
{:else}
  {+main/}
{/xhr}
{<title}
  Child Title
{/title}
{<main}
  Child Content
{/main}

Dynamic Partials

The name of the partial can be determined at render time. Primarily useful when a partial is loaded based on the ab-test key.

{>"/path/{abkey}.tl"/}

Dynamic Partials allow to conditionally chose between one block or other block of markup based on the context. Since Dust is inherently logic less, dynamic partials allow us to write conditional markup that can be reused based on current context.

Global Aliases

Most often we tend to reuse the same data in the template again and again ... One way to avoid been repetitive is use aliases. So a common question was, how does Dust support this?

Well, in Dust there is more than one way neat way to do this.

Use Inline Partials

Inline partials never output content themselves, and are always global to the template in which they are defined, so the order of their definition has no significance.

Key points to note : They are global to the template., there is no ordering and can be defined anywhere

Step 1 create global alias

 {<greeting}Hello, Hola{/greeting}   

Step 2

 {#names}
   {.} {+greeting/} 
 {/names}

 {#projects}
   {.} {+greeting/}
 {/projects}

Block Aliases

Inline parameters appear within the section's opening tag. Parameters are separated by a single space.

 {#profile bar="baz" bing="bong"}
  {name}, {bar}, {bing}
 {/profile}

There are 3 flavors

{#test greeting="hello"} // constant hello
 {greeting}
{/test}

{#test greeting=hello} // looks for a json context hello in the JSON hierarchy
 {greeting}
{/test}

{#test greeting="{hello}"} // resolves hello when greeting is referenced in the block and it resolves to the first one in the hierarchy starting with the current context
 {greeting}
{/test}

{#test greeting="{hello} and welcome"} // Same as the third example but append " and welcome"
 {greeting}
{/test}

@ helpers

Dust supports the exists (?) and not exists (^?). Nested exists block easily allow for (exp1 AND exp2 AND exp3), but (exp1 OR exp2 ) is not possible.

@select helper to choose from one of the many options @if helper comes handy in cases where an OR operation is required.

@select

Example

{@select key="foo"}
  {@eq value="some string with spaces"}prints if foo == "some string with spaces"{/eq}
  {@lt value="10"}prints if foo < 10{/lt}
  {@gt value="20"}prints if foo > 20{/gt}
  {@else}prints if none of the others matched{/else}
{/select}

@if

Example 1:

 {@if cond="('{x}'.length || '{y}'.length ) || (2 > 3) && {a}-{b} == 9"}
  render if
 {:else}
  render else
 {/if}

*Example 2: Inside lists of primitives,

JSON : {"skills": ["jasmine", "qunit", "javascript"]}
{#skills}
 <li>
 <span class='
  {@if cond="{$idx} == '{skills}'.split(',').length -1"}
    last
  {/if}
  '>
 {.}</span> 
 </li>
{/skills}

Example 5: @if with else

{@if cond="'{names}'.split(',').length == 3 "}
 {@i18n key="yes" text="Yes, there are 3 names"/} 
{:else}
 {@i18n key="no" text="No, there are less than 3 names"/}
{/if}

Traversing JSON using Dust


Given JSON

   {
        "team": {
            "projects": [{
                "name": "x"
            }, {
                "name": "y"
            }, {
                "name": "z"
            }],
        },
        "groups": [{
            "groupId": 1,
        "team": {
            "projects": [{
                "name": "a1"
            }, {
                "name": "a2"
            }, {
                "name": "a3"
            }],
         },
           "discussions": [{
              "discussionId": 1,
              "comments": [{
                    "commentId": 1,
                }, {
                    "commentId": 2,
                }]
            }, {
                "discussionId": 2,
                "comments": [{
                    "commentId": 1,
               }]
            }]
         }, {
            "groupId": 2,
            "team": {
              "projects": [{
                 "name": "p1"
               }, {
                  "name": "p2"
              }, {
                 "name": "p3"
              }],
           },
            "discussions": [{
                "discussionId": 1,
                "comments": [{
                    "commentId": 1,
                }, {
                    "commentId": 2,
                }]
             }, {
                "discussionId": 2,
                "comments": [{
                    "commentId": 1,
                }]
            }]
         }],
     }

     {#groups}
      {#discussions}
       {#comments}
        {#discussions}
         {#team}
           {#projects}
            print {name} {~n}
           {/projects}
         {/team}
       {/discussions}
      {/comments}
    {/discussions}
   {/groups}

It outputs: a1,a2,a3,p1,p2,p3 ....

How does this work?

team and discussions are siblings, team is not a child of discussions. Also, team and discussions are not children of comments either.

So here is how Dust traverses the JSON tree

a block is resolved ( recursively walking up the json tree )

  • first, by looking into the immediate child, if it finds it, then we are done
  • if not found, it looks a the parent's children ( in fact in its siblings )
  • if not found, it walks up the tree and trys to find in the grand parents until it reachesthe top level
  • If it reached the top level, where the root is null, finally it looks if any of the siblings in the top level satisfy the condition and tries to resolve the block reference
  • If none of the above resolves, it gives up

Summary : Dust does bottom up traversing from a section, not top down traversing


Another example

     {
        "team": {
            "projects": [{
                "name": "x"
            }, {
                "name": "y"
            }, {
                "name": "z"
            }],
            "title": "Presario"
        },
        "groups": [{
            "groupId": 1,
            "discussions": [{
                "discussionId": 1,
                "comments": [{
                    "commentId": 1,
                }, {
                    "commentId": 2,
                }]
            }, {
                "discussionId": 2,
                "comments": [{
                    "commentId": 1,
                }]
            }]
         }, {
            "groupId": 2,
            "discussions": [{
                "discussionId": 1,
                "comments": [{
                    "commentId": 1,
                }, {
                    "commentId": 2,
                }]
            }, {
                "discussionId": 2,
                "comments": [{
                    "commentId": 1,
                }]
            }]
          }]
      }

Note: groups and team are siblings and do not share a common parent, but yet Dust can resolve team

    {#groups}
     {#team}
       {#projects}
         print {name} {~n}
      {/projects}
      {/team}
   {/groups}

It outputs: x,y,z ....


FAQ

Are logic helpers required in logic less templates?

How to effectively use the @, partials, inline partials? Is one better than the other?

Is there support for creating reusable markup/UI modules? What are the best practices or patterns to use?