- Svelte 56.9%
- TypeScript 39.5%
- JavaScript 2.5%
- HTML 1.1%
| assets | ||
| e2e | ||
| src | ||
| static | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| .prettierignore | ||
| .prettierrc | ||
| contact.sql | ||
| drizzle.config.ts | ||
| local.db.bak | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| recipes.sql | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
Lab 10: Review of CA1 + Practice
Enda Lee 2025
Getting Started
- Clone or download this repository.
- Open the app folder in Visual Studio Code.
- Create a .env file in the application root using .env.example as a template.
- Rename
local.db.baktolocal.db - In the terminal, run npm install to install dependencies.
- Start the development server with npm run dev.
Overview
This lab reviews the CA1 solutions.
1. Common setup
1.1 Application setup
- Routes setup, see:
src/routes. - BootStrap is imported in the shared
+layout.svelte
1.2 Database and Schema
- Database and schema setup, see:
src/lib/server/db/schema.ts. Note the Type exports. - Requires
npm run db:pushto create the table(s) and execution of sample data SQL, e.g. in DB Browser. - Data access layer functions, see:
src/lib/server/data-access - Service layer functions, see:
src/lib/server/services
2. Display Recipes
-
Display data in a table:
src/routes/recipes -
+page.server.ts: get recipes from the database and return -
+page.svelte: Display recipes in a table. -
Split the ingredients and instructions strings to form arrays. Then display each araay element in a list:
<!-- Split ingredients by comma and display each as a list item --> {#each recipe.ingredients.split(',') as i} <li>{i}</li> {/each} -
Filter by difficulty:
- The
selectedDifficulty$state variable stores the filtered. filteredRecipesis a filtered recipe list, derived fromrecipes.- The event handling function
handleFilterClick()is called when the filter buttons are clicked. It setsselectedDifficultywith the required difficulty level.
- The
3. Display Contact messages
-
Display data in a table:
src/routes/viewcontacts -
+page.server.ts: get contacts from the database and return -
+page.svelte: Display contacts in a table. -
The event handling function
handleFilterClick()is called when the filter buttons are clicked. It returns a list of contacts filtered by based on the status parameter value.
Column sorting
- In the example, the **createdAt (Date/ Time) column ** is sorted by default:
// Holds table sort state. Initialized to reflect table sorted by createdAt descending
let sortBy = $state({ col: 'createdAt', ascending: false });
- The sort functions takes a column name as a parameter for sorting.
- If the
columnvalue matchessortBy.col. then reverse the current order. - If this is a new
column(not equalsortBy.col) then setsortBy.col = columnand set sort ascending. - The sort process makes a copy of
contactsand uses the JavaScript Array sort() method.
- If the
4. Review of Forms
The solution also includes a form to add new contact messages (not part of the assessment). This can be found in src\routes\contact
1. The form is defined in src\routes\contact\+page.svelte See the code comments for details
2. The <form> tag sets some important attributes:
3. The form input fields follow, this is the firstName input
4. The server-side
When the form is submitted, the data is sent to the createContact action handler which can be found in src/routes/contact/+page.server.ts
5. Form validation
Step 3 above uses the contactSevice to validate and add the contact message to the database.
const result = await contactService.createContact(contactData);
The service can be found at src/lib/server/services/contact-service.ts
It in turn validates using the Zod validation schema which is defined in src/lib/server/db/validation.ts. Here you will find the validation checks and error messages to be displayed if an input does not match requirments.
// src/lib/server/db/validation.ts
import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
import { z } from 'zod';
import { recipe, contact } from './schema.js';
export const selectRecipeSchema = createSelectSchema(recipe);
export const selectContactSchema = createSelectSchema(contact);
export const insertContactSchema = createInsertSchema(contact, {
firstName: z.string().min(1, 'First name is required'),
lastName: z.string().min(1, 'Last name is required'),
email: z.email('Invalid email'),
subject: z.string().min(1, 'Subject is required'),
message: z.string().min(1, 'Message is required'),
});
Exercises
- Add cuisine filtering for recipes.
- Add the required functionality to allow addition of new recipes to the database.
- Add the ability to delete contact messages.
- Require authenication to view contact messages, add contacts and messages, and delete messages. All users should have access to the recipes list and the contact form.
Enda Lee 2025



