Your First SØAD Application: Address Book
This chapter guides you through building a simple web application using the SØAD Framework. We’ll develop an Address Book where users can:
- View a list of contacts
- Add a new contact
- Edit an existing contact
- Delete a contact
Step 1: Create the Database Table
First, create a table to store contact details in your database.
Table Schema
Create a new table named contact with the following schema:
| Column Name | Data Type | Constraints |
|---|---|---|
| id | INT | NOT NULL, PRIMARY KEY, AUTO_INCREMENT |
| name | VARCHAR(100) | NOT NULL |
| contact_no | VARCHAR(20) | |
| VARCHAR(100) | ||
| created_date | DATETIME | |
| updated_date | DATETIME |
Example SQL Script:
CREATE TABLE contact (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
contact_no VARCHAR(20),
email VARCHAR(100),
created_date DATETIME,
updated_date DATETIME
);
After creating the table, SØAD automatically generates a corresponding model class named Contact.
Step 2: Create the Transaction
Next, create a transaction that manages the contacts. The transaction group is example, and the transaction code is address_book.
Create Transaction
In the SØAD Online IDE, go to the Transaction tab, and create:
- Group:
example - Code:
address_book - Transaction Name:
Address Book
This action generates:
Jython Code: address_book.py
from utils import render
from models import Contact
from java.time import LocalDateTime
class Address_book(object):
def view(self, ctx):
contacts = Contact.findAll().orderBy("name ASC")
ctx.output["contacts"] = contacts
ctx.go_to = render.as_view(ctx, "address_book")
def save(self, ctx):
"""POST"""
request = ctx.getRequest()
id = request.getParameter("id")
name = request.getParameter("name")
contact_no = request.getParameter("contact_no")
email = request.getParameter("email")
if id:
contact = Contact.findById(id)
else:
contact = Contact()
contact.set("created_date", LocalDateTime.now())
contact.set("name", name)
contact.set("contact_no", contact_no)
contact.set("email", email)
contact.set("updated_date", LocalDateTime.now())
contact.saveIt()
# Redirect to the view after saving
ctx.go_to = "/t/example/address_book"
def edit(self, ctx):
request = ctx.getRequest()
id = request.getParameter("id")
ctx.output["contact"] = Contact.findById(id)
self.view(ctx)
def delete(self, ctx):
"""POST"""
request = ctx.getRequest()
id = request.getParameter("id")
contact = Contact.findById(id)
if contact:
contact.delete()
# Redirect to the view after deletion
ctx.go_to = "/t/example/address_book"
Tip
-
Use
"""POST"""at the beginning of methods likesaveanddeleteto indicate that they only accept POST requests. This is particularly useful for handling form submissions securely. -
Implement
ctx.go_to = "/t/example/address_book"after save or delete actions to redirect users back to the main view. This follows the Post/Redirect/Get (PRG) pattern, preventing unintended form resubmissions when the page is refreshed.
HTML View: _example/address_book.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Address Book</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container my-4">
<h1 class="mb-4">Address Book</h1>
<form action="{{ctxPath}}/t/example/address_book/save" method="post" class="mb-4">
<input type="hidden" name="id" value="{{contact.id}}" />
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="name" value="{{contact.name}}" required />
</div>
<div class="mb-3">
<label class="form-label">Contact No</label>
<input type="text" class="form-control" name="contact_no" value="{{contact.contact_no}}" />
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" value="{{contact.email}}" />
</div>
<button type="submit" class="btn btn-primary">Save Contact</button>
</form>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Contact No</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{#each contacts}}
<tr>
<td>{{name}}</td>
<td>{{contact_no}}</td>
<td>{{email}}</td>
<td>
<a class="btn btn-sm btn-warning" href="{{../ctxPath}}/t/example/address_book/edit?id={{id}}">Edit</a>
<form action="{{../ctxPath}}/t/example/address_book/delete" method="post" style="display:inline;">
<input type="hidden" name="id" value="{{id}}">
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Delete this contact?')">Delete</button>
</form>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
This HTML leverages Bootstrap for styling the forms and tables to ensure a clean and responsive user interface.
Tip
- Use
{{ctxPath}}to dynamically generate the correct context path for your application. {{../ctxPath}}is used to access the context path from within nested Handlebars templates.
Step 3: Open in Browser
After creating the table and transaction, open the following URL:
You’ll see:
- A form to add and edit contacts
- A responsive table listing contacts
- Edit and delete buttons
Congratulations — you’ve created your first web application in SØAD!
Next, explore adding validations or integrating additional frontend enhancements.