HTL Tutorial #6: data-sly-test - Conditional Rendering

HTL Tutorial #6: data-sly-test - Conditional Rendering

What is data-sly-test?

data-sly-test evaluates an expression and:

  • If true: renders the element
  • If false: completely removes the element from output

Basic Syntax

<element data-sly-test="${condition}">
  This appears only if condition is true
</element>

Simple Example

<!-- Show only if title exists -->
<h1 data-sly-test="${properties.title}">
  ${properties.title}
</h1>

If properties.title is empty/null:

<!-- No output - element completely removed! -->

If properties.title = "Welcome":

<h1>Welcome</h1>

Truthy and Falsy Values

HTL considers falsy (= false):

  • false (boolean)
  • 0 or 0.0 (zero number)
  • "" (empty string)
  • [] (empty array)
  • null / undefined

Everything else is truthy (= true):

  • true
  • Any non-zero number
  • Any non-empty string
  • Arrays with elements
  • Objects
<!-- ❌ Does NOT show (falsy) -->
<div data-sly-test="${false}">No</div>
<div data-sly-test="${0}">No</div>
<div data-sly-test="${''}">No</div>
<div data-sly-test="${[]}">No</div>

<!-- ✓ Shows (truthy) -->
<div data-sly-test="${true}">Yes</div>
<div data-sly-test="${1}">Yes</div>
<div data-sly-test="${'hello'}">Yes</div>
<div data-sly-test="${[1,2,3]}">Yes</div>

Conditions with Operators

Comparison Operators

<!-- Equality -->
<div data-sly-test="${user.role == 'admin'}">
  Admin Panel
</div>

<!-- Greater/Less than -->
<div data-sly-test="${product.stock < 10}" class="alert-warning">
  Only ${product.stock} items left!
</div>

<div data-sly-test="${user.age >= 18}">
  Adult content
</div>

Logical Operators

<!-- AND: both conditions must be true -->
<div data-sly-test="${user.isLoggedIn && user.isPremium}">
  Premium Content
</div>

<!-- OR: at least one must be true -->
<div data-sly-test="${properties.showAlways || wcmmode.edit}">
  Visible in edit mode or if showAlways is true
</div>

<!-- NOT: inverts the condition -->
<div data-sly-test="${!user.isLoggedIn}">
  <a href="/login">Please log in</a>
</div>

IN Operator

<!-- Check if tag present in array -->
<span data-sly-test="${'featured' in properties.tags}" class="badge-featured">
  Featured
</span>

<!-- Substring in string -->
<div data-sly-test="${'@gmail.com' in user.email}">
  Gmail User
</div>

IF / ELSE Pattern

HTL doesn't have a native else construct, but you can simulate it:

Pattern 1: Negation

<!-- IF -->
<div data-sly-test="${user.isLoggedIn}">
  <p>Welcome, ${user.name}!</p>
</div>

<!-- ELSE (NOT) -->
<div data-sly-test="${!user.isLoggedIn}">
  <p>Please <a href="/login">log in</a></p>
</div>

Pattern 2: Variable

<!-- Save test result in variable -->
<div data-sly-test.hasContent="${properties.content}">
  ${properties.content}
</div>

<!-- Use negated variable for else -->
<div data-sly-test="${!hasContent}">
  No content available
</div>

Pattern 3: IF / ELSE IF / ELSE

<!-- IF -->
<div data-sly-test="${score >= 90}">
  <span class="grade-a">Excellent!</span>
</div>

<!-- ELSE IF -->
<div data-sly-test="${score >= 70 && score < 90}">
  <span class="grade-b">Good</span>
</div>

<!-- ELSE IF -->
<div data-sly-test="${score >= 50 && score < 70}">
  <span class="grade-c">Sufficient</span>
</div>

<!-- ELSE -->
<div data-sly-test="${score < 50}">
  <span class="grade-f">Insufficient</span>
</div>

Saving the Result in a Variable

The data-sly-test.varName syntax saves the test result:

<!-- Test AND save in variable -->
<div data-sly-test.isAdmin="${user.role == 'admin'}">
  <!-- isAdmin is now available -->
  <p>Admin Mode: ${isAdmin}</p>
</div>

<!-- Variable does NOT exist outside the block -->

Advanced usage - save non-null object:

<!-- If user exists, save it in variable -->
<div data-sly-test.currentUser="${user}">
  <!-- currentUser is available here -->
  <h2>${currentUser.name}</h2>
  <p>${currentUser.email}</p>
</div>

Complete Practical Examples

Example 1: Navigation Menu

<nav data-sly-use.nav="com.example.NavigationModel">
  <ul class="menu">
    <!-- Show Home only if we're not on home -->
    <li data-sly-test="${currentPage.path != '/'}">
      <a href="/">Home</a>
    </li>

    <!-- Menu items from model -->
    <li data-sly-list.item="${nav.items}">
      <!-- Highlight current page -->
      <a href="${item.url}"
         class="${currentPage.path == item.url ? 'active' : ''}">
        ${item.title}
      </a>
    </li>

    <!-- Conditional Login/Logout -->
    <li data-sly-test="${!user.isLoggedIn}">
      <a href="/login">Login</a>
    </li>

    <li data-sly-test="${user.isLoggedIn}">
      <a href="/logout">Logout (${user.name})</a>
    </li>
  </ul>
</nav>

Example 2: Product Card with Badges

<div class="product" data-sly-use.product="com.example.ProductModel">
  <h3>${product.name}</h3>

  <!-- "New" badge if published less than 7 days ago -->
  <span data-sly-test="${product.daysOld < 7}" class="badge-new">
    New!
  </span>

  <!-- "On Sale" badge -->
  <span data-sly-test="${product.hasDiscount}" class="badge-discount">
    -${product.discountPercent}%
  </span>

  <!-- "Out of Stock" badge -->
  <div data-sly-test="${product.stock == 0}" class="out-of-stock">
    <strong>Out of Stock</strong>
  </div>

  <!-- Buy button only if available -->
  <button data-sly-test="${product.stock > 0}" class="btn-buy">
    Add to Cart
  </button>

  <!-- Low stock alert -->
  <div data-sly-test="${product.stock > 0 && product.stock < 5}"
       class="alert-warning">
    Only ${product.stock} items left!
  </div>
</div>

Example 3: User Dashboard

<div class="dashboard" data-sly-use.user="com.example.UserModel">
  <!-- Save isAdmin in variable -->
  <div data-sly-test.isAdmin="${user.role == 'admin'}"></div>

  <!-- Header with name -->
  <h1>Welcome, ${user.name}</h1>

  <!-- General stats -->
  <div class="stats">
    <div class="stat">
      <strong>${user.postCount}</strong>
      <span>${user.postCount == 1 ? 'post' : 'posts'}</span>
    </div>
  </div>

  <!-- Admin section -->
  <section data-sly-test="${isAdmin}" class="admin-panel">
    <h2>Administration Panel</h2>
    <!-- admin content -->
  </section>

  <!-- Moderator section -->
  <section data-sly-test="${user.role == 'moderator' || isAdmin}">
    <h2>Moderation Tools</h2>
    <!-- moderation content -->
  </section>

  <!-- Message for basic users -->
  <div data-sly-test="${user.role == 'user' && !user.isPremium}">
    <p>
      <a href="/premium">Upgrade to Premium</a> for more features!
    </p>
  </div>

  <!-- Premium badge -->
  <div data-sly-test="${user.isPremium}" class="premium-badge">
    ✨ Premium User
  </div>
</div>

Example 4: Alert System

<div class="alerts" data-sly-use.system="com.example.SystemModel">
  <!-- Error -->
  <div data-sly-test="${system.hasErrors}" class="alert alert-danger">
    <strong>Error!</strong> ${system.errorMessage}
  </div>

  <!-- Warning -->
  <div data-sly-test="${system.hasWarnings && !system.hasErrors}"
       class="alert alert-warning">
    <strong>Warning:</strong> ${system.warningMessage}
  </div>

  <!-- Success -->
  <div data-sly-test="${system.hasSuccess && !system.hasErrors && !system.hasWarnings}"
       class="alert alert-success">
    <strong>Success!</strong> ${system.successMessage}
  </div>

  <!-- Info (default) -->
  <div data-sly-test="${!system.hasErrors && !system.hasWarnings && !system.hasSuccess}"
       class="alert alert-info">
    All good, no notifications.
  </div>
</div>

Combination with Other Statements

With data-sly-text

<p data-sly-test="${properties.description}"
   data-sly-text="${properties.description}">
  Placeholder description
</p>

With data-sly-list

<!-- List only if it has elements -->
<ul data-sly-test="${properties.items}"
    data-sly-list.item="${properties.items}">
  <li>${item}</li>
</ul>

With data-sly-attribute

<!-- Conditional attribute -->
<div data-sly-test="${properties.customId}"
     data-sly-attribute.id="${properties.customId}">
  Content
</div>

Best Practices

  1. Prefer simple evaluations: ${variable} instead of ${variable != null}
  2. Use variables for complex conditions: data-sly-test.varName
  3. ELSE pattern with negation: ${!condition}
  4. Combine with other statements when it makes sense
  5. Test for existence before accessing: avoid errors
  6. Leverage truthy/falsy: cleaner code

Common Mistakes

❌ Test on literal string

<!-- WRONG - always true! -->
<div data-sly-test="${'false'}">
  This always appears!
</div>

❌ Confusing = with ==

<!-- WRONG - assignment not supported -->
<div data-sly-test="${user.role = 'admin'}">

<!-- CORRECT - comparison -->
<div data-sly-test="${user.role == 'admin'}">

❌ Accessing variable outside scope

<div data-sly-test.myVar="${something}">
  ${myVar} <!-- OK -->
</div>
${myVar} <!-- ERROR - out of scope! -->

Practical Exercises

  1. Login Widget: Show login form if not logged in, otherwise user dashboard
  2. Product Filter: Show products only if price is between min and max
  3. Access Control: Admin panel visible only for admins, moderators have partial access

Next Lesson

In the next lesson we'll discover data-sly-list and data-sly-repeat for iterating over arrays and collections.


Lesson #6 of the HTL Tutorial series. ← Previous lesson | Next lesson →