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>
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}
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 … }
}
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>
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>
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>
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}
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 … }
}
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>
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>
}
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:
Vue 3 conditional directives:
v-else-if: https://vuejs.org/api/built-in-directives.html#v-else-if
v-else: https://vuejs.org/api/built-in-directives.html#v-else
Svelte control-flow syntax: https://svelte.dev/docs/svelte/if
Angular control-flow syntax: https://angular.dev/api/core/@if
Github Pages:
- https://railsstudent.github.io/fundamental-vue3/
- https://railsstudent.github.io/fundamental-angular
- https://railsstudent.github.io/fundamental-svelte
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.
Top comments (0)