Day 15 – Add a Coffee Plan Form

day-15-–-add-a-coffee-plan-form

Table of Contents

  • Create the AddCoffeePlan
  • Import AddCoffeePlan to PlanPicker
  • Conclusions
  • Resources
  • Github Repositories

On day 15, I extended the PlanPicker component to have a AddCoffeePlan component to add new coffee plans to the plan list. Then, the PlanPicker component has two child components that are AddCoffeePlan and CoffeePlan.

Create the AddCoffeePlan

  • Vue 3 application

Create a new components/AddCoffeePlan.vue file.

<style scoped>
input {
  padding: 0.5rem 0.75rem;
}

.add-plan-form {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.add-plan-form input {
  width: 70%;
  border-radius: 3px;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
  border: 1px solid #f1f5f8;
  color: #606f7b;
  padding: 0.5rem 0.75rem;
  box-sizing: border-box;
  font-size: 1rem;
  letter-spacing: 0.5px;
  margin: 0.5rem 0;
}
style>

Add scoped styles to style the add coffee plan form. The script tag has scoped attribute.

<script setup lang="ts">
import { ref } from 'vue';

const emit = defineEmits<{
  (e: 'newCoffeePlan', name: string): void
}>();

const newPlan = ref('');
function addPlan() {
    const trimmedPlan = newPlan.value.trim();
    if (!trimmedPlan) {
        return;
    }

    emit('newCoffeePlan', trimmedPlan);
    newPlan.value = '';
} 
</script>

The newPlan ref stores the new coffee plan to be added to the coffee plan list.

The defineEmits defines a custom newCoffeePlan event that emits the value of newPlan to the PlanPicker component.

The addPlan handles the form submit event, emits the newCoffeePlan event, and clears newPlan.


The template uses v-model.trim to bind the textbox to the newPlan ref.

The Add Plan button is disabled unless users input at least 5 characters to the textbox.

When users submit the form, the addPlan function validate the new coffee plan and emit the value to the parent component.

  • SvelteKit application

Create a new lib/add-coffee-plan.svelte file.

Create scoped styles in the add coffee plan form. By default, styles are scoped in a svelte component.

<style>
    input {
      padding: 0.5rem 0.75rem;
    }

    .add-plan-form {
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .add-plan-form input {
      width: 70%;
      border-radius: 3px;
      box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
      border: 1px solid #f1f5f8;
      color: #606f7b;
      padding: 0.5rem 0.75rem;
      box-sizing: border-box;
      font-size: 1rem;
      letter-spacing: 0.5px;
      margin: 0.5rem 0;
    }
style>
<script lang="ts">
interface Props {
    addCoffeePlan: (plan: string) => void;
}

const { addCoffeePlan }: Props = $props();

let newPlan = $state('');
const addPlan = (e: SubmitEvent) => {
    e.preventDefault();
    const trimmedPlan = newPlan.trim();
    if (!trimmedPlan) {
        return;
    }

    addCoffeePlan(trimmedPlan);
    newPlan = '';
}
</script>

The newPlan rune stores the new coffee plan to be added to the coffee plan list.

The PlanPicker component passes the addCoffeePlan function to the AddCoffeePlan component that is destructured from $props. This function is used to emit the new coffee to the PlanPicker component.

The addPlan handles the following things

  • listen to the form submit event,
  • prevents loading the page
  • notify the parent by calling the addCoffeePlan function
  • clears the rune.
 class="add-plan-form" onsubmit={addPlan}>
     type="text" placeholder="Add a new plan" bind:value={newPlan} />
     type="submit" class="btn btn-primary" disabled={newPlan.length < 5}>
        Add Plan
    
 

The template uses bind:value to bind the textbox to the newPlan rune.

The Add Plan button is disabled unless users input at least 5 characters to the textbox.

The form registers addPlan to listen to the onsubmit event. When users submit the form, the addPlan uses the AddCoffeePlan prop to pass the new value to the parent component.

  • Angular 19 application

Use the Angular CLI to create a new AddCoffeePlanComponent

ng g c AddCoffeePlan

The component defines the CSS in a separate add-coffee-plan.component.css file. Inline CSS styles are also supportted and it depends on the coding preferences.

input {
    padding: 0.5rem 0.75rem;
}

.add-plan-form {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.add-plan-form input {
    width: 70%;
    border-radius: 3px;
    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
    border: 1px solid #f1f5f8;
    color: #606f7b;
    padding: 0.5rem 0.75rem;
    box-sizing: border-box;
    font-size: 1rem;
    letter-spacing: 0.5px;
    margin: 0.5rem 0;
}
import { ChangeDetectionStrategy, Component, output, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-add-coffee-plan',
  imports: [FormsModule],
  template: `... inline template ...`,
  styleUrl: './add-coffee-plan.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AddCoffeePlanComponent {
  newPlan = signal('');

  addCoffeePlan = output<string>();

  addPlan() {
    this.addCoffeePlan.emit(this.newPlan());
    this.newPlan.set('');
  }
}

The component imports FormsModule so that ngSubmit is available and signals can be two-way binding to the HTML elements.

The newPlan signal stores the new coffee plan to be added to the coffee plan list.

addCoffeePlan is an output function that emits the new value to the PlanPicker component.

The addPlan method handles the ngSubmit event, prevents loading the page implicitely, emits the addCoffeePlan custom event, and clears the newPlan signal.

template: `
 class="add-plan-form" (ngSubmit)="addPlan()">
     name="newPlan" type="text" placeholder="Add a new plan" [(ngModel)]="newPlan" />
     class="btn btn-primary" type="submit" [disabled]="newPlan().length < 5">
        Add Plan
    
   
`

[(ngModel)] two-way binding the newPlan signal to the input. When users input new coffee plan to the text box, the newPlan receives a new value.

The Add Plan button uses the box syntax to bind an input to an attribute. [disabled] is true when users input less than 5 characters to the textbox.

The ngSubmit is a custom Angular event that fires when form submit occurs and the event handler method is addPlan. addPlan invokes the addCoffeePlan output to emit the new value to the parent component.

Import AddCoffeePlan to PlanPicker

  • Vue 3 application

Import AddCoffeePlan to PlanPicker

<script setup lang="ts">
import AddCoffeePlan from './AddCoffeePlan.vue'
</script>

Use the AddCoffeePlan in the template


The @newCoffeePlan custom event calls an inline function to append the new plan to the coffee plan list.

  • SvelteKit application

Import AddCoffeePlan to PlanPicker

<script lang="ts">
    import CoffeePlan from './coffee-plan.svelte';
</script>

Use the AddCoffeePlan in the template

 class="plans">
     addCoffeePlan={(plan) => plans.push(plan)}  />

The @newCoffeePlan custom event also call an inline function to append the new plan to the coffee plan list.

  • Angular 19 application

Import AddCoffeePlanComponent to PlanPickerComponent

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { AddCoffeePlanComponent } from '../add-coffee-plan/add-coffee-plan.component';
import { CoffeePlanComponent } from '../coffee-plan/coffee-plan.component';

@Component({
  selector: 'app-plan-picker',
  imports: [CoffeePlanComponent, AddCoffeePlanComponent],
  template: `... inline template ...`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PlanPickerComponent {
  plans = signal(['The Single', 'The Curious', 'The Addict', 'The Hacker']);

  addPlan(name: string) {
    this.plans.update((plans) => [...plans, name]);
  }
}

Add the AddCoffeePlanComponent component to the imports array.

The addPlan method uses the update method of the Signal API to append the new coffee plan to the plans signal.

 class="plans">
    (addCoffeePlan)="addPlan($event)" />

The addCoffeePlan custom event uses the special $event to pass the new coffee plan to the addPlan method to append the new coffee name.

Conclusions

We have successfully created an AddCoffeePlan component that can add new coffee plan to the coffee plan list in the PlanPicker component.

Resources

Github Repositories

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post
day-41/180-of-frontend-dev:-styling-forms-and-tables

Day 41/180 of Frontend Dev: Styling Forms and Tables

Next Post
rick-shiels-golf:-my-golf-improved!!!

Rick Shiels Golf: My Golf Improved!!!

Related Posts