DEV Community

Connie Leung
Connie Leung

Posted on

Day 7 - Conditional Rendering with built-in control flow syntax or directives.

On day 7, I will show how Vue 3, SvelteKit, and Angular perform conditional rendering with built-in control flow syntax or directives. Vue 3 uses v-if, v-else-if, and v-else directives to render conditionally. Svelte and Angular use if/else-if/else to perform conditional rendering of elements in HTML templates.

Case 1: Display the Unordered List when the list has items

  • Vue 3 application
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref} from 'vue'

const items = ref<Item[]>([])
const deleteItem = (id: number) => {  save logic as before  }
</script>

<template>
  <template v-if="items.length > 0">
    <ul>
      <div class="list-item" v-for="item in items" :key="item.id">
        <li>{{ item.id }} - {{ item.label }}</li>
        <button aria-label="Delete" @click="deleteItem(item.id)">
          <Icon icon="ic:baseline-remove" />
        </button>
      </div>
    </ul>
  </template>
  <p v-else>Nothing to see here.</p>
</template>
Enter fullscreen mode Exit fullscreen mode

First, I wrapped the unordered list inside the &lgt;template> element. On the &lgt;template> element, I applied the v-if directive to display the list when the items ref has at least one element. v-if="items.length > 0" ensures that the unordered list is shown when the length of the items array is positive.
When the items ref is empty, the paragraph element is rendered, and the text, "Nothing to see here.", is displayed. It is achieved by adding the v-else directive to the p element.

  • SvelteKit application
<script lang="ts">
    import Icon from '@iconify/svelte';

    let items = $state([] as Item[]);

    function deleteItem(id: number) {  same as logic before  }
</script>

{#if items.length > 0}
<ul>
    {#each items as item (item.id)}
       <div class="list-item">
        <li>{item.id} - {item.label}</li>
        <button onclick={() => deleteItem(item.id)}
            aria-label="delete an item"
        >
            Icon icon="ic:baseline-remove" />
        </button>
        </div>
    {/each}
</ul>
{:else}
    <p>Nothing to see here</p>
{/if}
Enter fullscreen mode Exit fullscreen mode

The #if branch encloses the unordered list, so the if-block displays the list when the condition is true. {#if items.length > 0} is true when the items rune stores a non-empty array.
When the items rune holds an empty array, the {:else} branch becomes true. The paragraph element is rendered, and the text, "Nothing to see here.", is seen.

  • Angular 19 application
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { matAdd, matRemove, matSave } from '@ng-icons/material-icons/baseline';

@Component({
  selector: 'app-shopping-cart',
  imports: [FormsModule, NgIcon],
  viewProviders: [provideIcons({ matRemove, matAdd, matSave })],
  template: `
    @if (items().length > 0) {
      <ul>
        @for (item of items(); track item.id) {
          <div class="list-item">
            <li>{{ item.id }} - {{ item.label }}</li>
            <button aria-label="Delete an item" (click)="deleteItem(item.id)">
                <ng-icon name="matRemove"></ng-icon>
              </button>
          </div>
        }
      </ul>
    } @else {
      <p>Nothing to see here.</p>
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
  items = signal<Item[]>([]);

  deleteItem(id: number) {  same logic as before  }
}
Enter fullscreen mode Exit fullscreen mode

Angular 17 introduced the new control-flow syntax to render components or elements conditionally.
@if renders the HTML elements when the condition is true.
@else renders the HTML elements when none of the condition is true.
The @if branch encloses the unordered list, so the if-block displays the list when the condition is true. @if (items().length > 0) is true when the items signal stores a non-empty array.
When the items signal holds an empty array, the @else branch becomes true. The paragraph element is rendered, and the text, "Nothing to see here.", is seen.

Case 2: Display Add Item Form Conditionally After Button Click Event

  • Vue 3 application

The demo adds an isEditing ref to store the state of the Add Item Form. When isEditing is true, the form is visible, and it is being edited. When the ref is false, the form is hidden and cannot be edited.

The toggleEditing function sets the isEditing ref to show or hide the Add Item Form. Moreover, newItem and newItemHighPriority are reset to blank to clear the form.

<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref, computed } from 'vue'

const items = ref<Item[]>([])
const newItem = ref('')
const newItemHighPriority = ref(false)

const saveItem = () => {
   same logic as before 
}

const isEditing = ref(false)

const toggleEditing = (value: boolean) => {
  isEditing.value = value
  newItem.value = ''
  newItemHighPriority.value = false
}
</script>

<div class="header">
    <button v-if="isEditing" @click="toggleEditing(false)" aria-label="Cancel">
      <Icon icon="ic:outline-close" />
    </button>
    <button v-else @click="toggleEditing(true)" aria-label="Add Item">
      <Icon icon="ic:outline-add" />
    </button>
</div>
Enter fullscreen mode Exit fullscreen mode

When the Add Item button is clicked, isEditing is set to true. The form is visible and can be edited to add items. The Cancel button is also displayed.
When the Cancel button is clicked, the toggleEditing function sets the isEditing ref to false.
Then, the Add Item button reappears, and the form is hidden.

<form v-if="isEditing" @submit.prevent="saveItem">
    <input v-model.trim="newItem" placeholder="Add new item" />
    <label>
      <input type="checkbox" v-model="newItemHighPriority" />
      <span> High Priority</span>
    </label>
    <button aria-label="Save Item">
      <Icon icon="ic:outline-save" />
    </button>
 </form>
Enter fullscreen mode Exit fullscreen mode

isEditing determines the visibility of the Add Item form. The v-if directive displays the form when the ref is true. Otherwise, the form remains hidden.

  • SvelteKit application

The demo adds an isEditing rune to store the state of the Add Item Form. When isEditing is true, the form is visible, and it can be edited. When the rune is false, the form is hidden and cannot be edited.

The toggleEditing function sets the isEditing rune to show or hide the Add Item Form. Moreover, newItem and newItemHighPriority runes are reset to blank to clear the form.

<script lang="ts">
    import Icon from '@iconify/svelte';

    let newItem = $state('');
    let newItemHigherPriority = $state(false);
    let items = $state([] as Item[]);

    let isEditing = $state(false);

    function saveItem() {  same logic as before  }

    async function handleSubmit(event: SubmitEvent) {
        same logic as before 
    }

    function toggleEdit(value: boolean) {
    isEditing = value;
    newItem = '';
    newItemHigherPriority = false;
    }
</script>


<div class="header">
    {#if isEditing}
        <button onclick={() => toggleEdit(false)} aria-label="Cancel">
            <Icon icon="ic:outline-close" />
    </button>
     {:else}
    <button onclick={() => toggleEdit(true)} aria-label="Add Item">
            <Icon icon="ic:outline-add" />
    </button>
     {/if}
</div>
Enter fullscreen mode Exit fullscreen mode

When isEditing is true, the form is visible and is being edited. The Cancel button is displayed; when clicked, the toggleEditing function sets the isEditing ref to false.
Otherwise, the Add Item button is displayed. When the toggleEditing function sets the isEditing ref to true, the form is shown to add new items.

{#if isEditing}
    <form method="POST" onsubmit={handleSubmit}>
    <input id="newItem" name="newItem" type="text" placeholder="Add item" bind:value={newItem} />
    <label>
        <input id="newItemHigherPriority" name="newItemHigherPriority" type="checkbox"
        bind:checked={newItemHigherPriority}
         />
         <span> Higher Priority</span>
    </label>
    <button aria-label="Save Item">
         <Icon icon="ic:outline-save" />
    </button>
     </form>
{/if}
Enter fullscreen mode Exit fullscreen mode

isEditing rune determines the visibility of the Add Item form.
The #if branch displays the Add Item form when the isEditing rune is true. This is achieved by {#if isEditing }.
Nothing is displayed when the isEditing rune is false. Therefore, there is no #else if or #else branch.

  • Angular 19 application

Similarly, the items signal uses the update method to create a new array without the items with the matching ID.
The callback function uses the Array.filter method to iterate the array, remove an item, and return the new array. Similarly, the item signal is updated with the new value.

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { matAdd, matRemove, matSave } from '@ng-icons/material-icons/baseline';

@Component({
  selector: 'app-shopping-cart',
  imports: [FormsModule, NgIcon],
  viewProviders: [provideIcons({ matRemove, matAdd, matSave })],
  template: `... inline template …`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
  items = signal<Item[]>([]);
  newItem = signal('');
  newItemHighPriority = signal(false);
  isEditing = signal(false);

  toggleEditing(value: boolean) {
    this.isEditing.set(value);
    this.newItem.set('');
    this.newItemHighPriority.set(false);
  }

  saveItem() {   same logic as before  }
}
Enter fullscreen mode Exit fullscreen mode

The demo adds an isEditing signal to store the state of the Add Item Form. When isEditing is true, the form is visible and can be edited. When the signal is false, the form is hidden and cannot be edited.

The toggleEditing method sets the isEditing signal to show or hide the Add Item Form. Moreover, newItem and newItemHighPriority signals are reset to blank to clear the form.

<div class="header">
      @if (isEditing()) {
        <button (click)="toggleEditing(false)" aria-label="Cancel">
          <ng-icon name="matRemove"></ng-icon>
        </button>
      } @else {
        <button (click)="toggleEditing(true)" aria-label="Add Item">
          <ng-icon name="matAdd"></ng-icon>
        </button>
      }
 </div>
Enter fullscreen mode Exit fullscreen mode

The initial value of isEditing is false; therefore the Add Item button is displayed and can be clicked.

Then, the toggleEditing method sets the isEditing signal to true, and the Cancel button appears. When clicking the button, the toggleEditing function sets the isEditing signal to false.
The Add Item button is displayed again. Clicking it again opens the Add Item form for adding new items.

@if (isEditing()) {
   <form class="add-item-form" (ngSubmit)="saveItem()">
        <input type="text" placeholder="Add new item" name="newItem" [(ngModel)]="newItem" />
        <label>
          <input type="checkbox" [(ngModel)]="newItemHighPriority" name="newItemHighPriority" />
          <span> High Priority</span>
        </label>
        <button type="submit" aria-label="Save Item">
          <ng-icon name="matSave"></ng-icon>
        </button>
   </form>
}
Enter fullscreen mode Exit fullscreen mode

isEditing signal determines the visibility of the Add Item form.
The @if branch displays the Add Item form when the isEditing signal is true. This is achieved by @if (isEditing()).
When the isEditing signal is false, nothing is displayed. Therefore, there is no @else if or @else branch.

Resources:

Github Pages:

We have successfully updated the shopping cart component to display different parts of the UI based on the events that occurred and the reactive state.

Sentry image

Make it make sense

Make sense of fixing your code with straight-forward application monitoring.

Start debugging →

Top comments (0)

ACI image

ACI.dev: Fully Open-source AI Agent Tool-Use Infra (Composio Alternative)

100% open-source tool-use platform (backend, dev portal, integration library, SDK/MCP) that connects your AI agents to 600+ tools with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Check out our GitHub!