Advanced Templating

String concatenation, inline pipes, and special variables

DBindly v2.3.0 introduces powerful templating features for more flexible data rendering.

Template Syntax

Basic Interpolation

Use double curly braces to insert field values:

<div dbind_repeat="users">
  <p>Hello, {{name}}!</p>
</div>

Nested Properties

Access nested data with dot notation:

<div dbind_repeat="orders">
  <p>Customer: {{customer.name}}</p>
  <p>Email: {{customer.contact.email}}</p>
  <p>Address: {{shipping.address.city}}, {{shipping.address.country}}</p>
</div>

String Concatenation

Combine multiple fields and literals using +:

<div dbind_repeat="users">
  <!-- Combine first and last name -->
  <h3>{{firstName + ' ' + lastName}}</h3>
 
  <!-- Build a full address -->
  <p>{{address.street + ', ' + address.city + ' ' + address.zip}}</p>
 
  <!-- Mix fields with static text -->
  <p>{{'Welcome, ' + displayName + '!'}}</p>
</div>

Rules for Concatenation

  • Use + to join parts
  • String literals must be in single or double quotes
  • Field names are unquoted
  • Spaces around + are optional
<!-- All valid -->
<span>{{first + ' ' + last}}</span>
<span>{{first+' '+last}}</span>
<span>{{"Hello, " + name}}</span>
<span>{{'Hello, ' + name}}</span>

Inline Pipes (Filters)

Apply formatting filters directly in templates:

<div dbind_repeat="products">
  <h3>{{name|uppercase}}</h3>
  <p>{{price|currency:USD}}</p>
  <p>{{description|truncate:100}}</p>
  <time>{{createdAt|date:relative}}</time>
</div>

Pipe Syntax

{{fieldName|filterName}}
{{fieldName|filterName:parameter}}

Available Filters

Text Filters

FilterDescriptionExample
uppercaseConvert to uppercase{{name|uppercase}}
lowercaseConvert to lowercase{{email|lowercase}}
capitalizeCapitalize first letter{{title|capitalize}}
titlecaseCapitalize each word{{name|titlecase}}
trimRemove whitespace{{input|trim}}
truncate:NLimit to N characters{{desc|truncate:50}}
slugURL-friendly string{{title|slug}}
nl2brNewlines to <br>{{bio|nl2br}}
striphtmlRemove HTML tags{{content|striphtml}}

Number Filters

FilterDescriptionExample
numberFormat with locale{{count|number}}
currency:CODEFormat as currency{{price|currency:USD}}
percentFormat as percentage{{rate|percent}}

Date Filters

FilterDescriptionExample
dateFormat date{{createdAt|date}}
date:shortShort date format{{date|date:short}}
date:longLong date format{{date|date:long}}
timeFormat time{{timestamp|time}}
datetimeDate and time{{updated|datetime}}
relativeRelative time{{posted|date:relative}}

Other Filters

FilterDescriptionExample
booleantrue/false string{{active|boolean}}
yesnoYes/No string{{subscribed|yesno}}
default:valueFallback value{{nickname|default:Anonymous}}
jsonJSON stringify{{data|json}}
urlencodeURL encode{{query|urlencode}}

Chaining Filters

Apply multiple filters in sequence:

<!-- Trim, then truncate, then capitalize -->
<p>{{description|trim|truncate:100|capitalize}}</p>
 
<!-- Lowercase then URL encode -->
<a href="/search?q={{query|lowercase|urlencode}}">Search</a>

Special Variables

Loop Index Variables

Within dbind_repeat loops, special variables are available:

VariableDescription
{{_index}}Zero-based index (0, 1, 2...)
{{_number}}One-based number (1, 2, 3...)
<ol dbind_repeat="items">
  <li>
    <span class="number">{{_number}}.</span>
    <span>{{name}}</span>
  </li>
</ol>

Using Index for Styling

<div dbind_repeat="products">
  <div class="product" style="animation-delay: calc({{_index}} * 0.1s)">
    <span class="rank">#{{_number}}</span>
    <h3>{{name}}</h3>
  </div>
</div>

Combining Features

Concatenation + Pipes

<div dbind_repeat="users">
  <!-- Full name, uppercase -->
  <h3>{{firstName + ' ' + lastName|uppercase}}</h3>
 
  <!-- Note: Pipe applies to entire expression -->
</div>

Complex Templates

<div dbind_repeat="orders">
  <div class="order-card">
    <header>
      <span class="order-number">Order #{{_number}}</span>
      <time>{{createdAt|date:relative}}</time>
    </header>
 
    <div class="customer">
      <h4>{{customer.firstName + ' ' + customer.lastName}}</h4>
      <p>{{customer.email|lowercase}}</p>
    </div>
 
    <div class="shipping">
      <p>{{shipping.address.street}}</p>
      <p>{{shipping.address.city + ', ' + shipping.address.state + ' ' + shipping.address.zip}}</p>
      <p>{{shipping.address.country|uppercase}}</p>
    </div>
 
    <div class="total">
      <span>Total: {{total|currency:USD}}</span>
    </div>
 
    <footer>
      <span class="status {{status|lowercase}}">{{status|capitalize}}</span>
    </footer>
  </div>
</div>

Template in Attributes

Use templates in data attribute values:

<div dbind_repeat="products">
  <!-- Dynamic classes -->
  <div class="product {{category|lowercase}}">
    <img
      dbind_src="image"
      dbind_alt="name"
      loading="lazy"
    >
    <h3 dbind_data="name"></h3>
 
    <!-- Dynamic href with template -->
    <a href="/products/{{slug}}">View Details</a>
  </div>
</div>

Default Values

Provide fallback values for missing data:

<div dbind_repeat="users">
  <img src="{{avatar|default:/images/default-avatar.png}}">
  <h3>{{displayName|default:Anonymous User}}</h3>
  <p>{{bio|default:No bio provided}}</p>
</div>

Escaping

Templates are automatically HTML-escaped to prevent XSS:

<!-- Safe: HTML entities are escaped -->
<p>{{userInput}}</p>
<!-- If userInput is "<script>alert('xss')</script>" -->
<!-- Output: &lt;script&gt;alert('xss')&lt;/script&gt; -->

For trusted HTML content, use dbind_html:

<!-- Only use with trusted content! -->
<div dbind_html="richContent"></div>

Complete Example

<section class="team">
  <h2>Our Team</h2>
 
  <div class="team-grid" dbind_repeat="team">
    <article class="team-member" dbind_transition="fade">
      <div class="member-rank">#{{_number}}</div>
 
      <img
        src="{{avatar|default:/images/placeholder.jpg}}"
        alt="{{firstName + ' ' + lastName}}"
        loading="lazy"
      >
 
      <div class="member-info">
        <h3>{{firstName + ' ' + lastName}}</h3>
        <p class="role">{{role|titlecase}}</p>
        <p class="department">{{department|uppercase}}</p>
        <p class="bio">{{bio|truncate:120|default:No bio available}}</p>
 
        <div class="meta">
          <span>Joined {{joinDate|date:relative}}</span>
        </div>
 
        <div class="social">
          <a href="mailto:{{email|lowercase}}">Email</a>
          <a href="{{linkedin|default:#}}">LinkedIn</a>
          <a href="{{twitter|default:#}}">Twitter</a>
        </div>
      </div>
    </article>
  </div>
</section>
 
<style>
.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}
 
.team-member {
  position: relative;
  padding: 20px;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
 
.member-rank {
  position: absolute;
  top: 12px;
  right: 12px;
  font-weight: bold;
  color: #666;
}
</style>

Next Steps