In the first part we've built a web server capable to serve static files and expose each CRUD (create, read, update and delete) operation. In this second part we will develop a minimal interface to demonstrate the communication between the frontend and the backend components.
Note that frontend development is an iterative process. You usually start from some sketches and aim to get then validated with the users. Then you move into more details as you create a high fidelity design.
In the end you turn the design into HTML and CSS. Design principles are not covered here since we will be focusing on the technologies and we will be using frameworks like Bootstrap or Material UI.
This is the html document to start from. It contains the table and the form we will be using to implement the CRUD operations.
<!DOCTYPE html><html><head><title>Message list</title></head><body><h1>Messages</h1></body><div id="content"><table style="width:100%;"><tr><th>ID</th><th>Subject</th><th>Name</th><th>Message</th><th>Actions</th></tr><tr><td>1</td><td>Subject data</td><td>Name data</td><td>Message data</td><td><button>Edit</button><button>Delete</button></td></tr></table><form><input type="hidden" name="id" id="id" /><br />Name:<br /><input type="text" name="name" id="name" /><br />Subject:<br /><input type="text" name="subject" id="subject"><br/>Message:<br /><textarea name="message" id="message"></textarea> <br/><input type="submit" value="Save message"><input type="reset" value="Cancel"></form></div></html>
Each time a page is loaded the onload
event is triggered. We will use this event to fire the showMessages() function
<script type="text/javascript">window.onload = () => {console.log('Page loaded')}</script>
async function showMessages() {try {let results = await fetch('/messages').then(response => response.json())let html = ` <table style="width:500px;"><tr><th>ID</th><th>Subject</th><th>Name</th><th>Message</th><th>Actions</th></tr>`results.forEach(function(element) {html += `<tr><td>${element.id}</td><td>${element.name}</td><td>${element.subject}</td><td>${element.message}</td><td><button onClick="editMessage(${element.id})">Edit</button><button onClick="deleteMessage(${element.id})">Delete</button></td></tr>`})html += `</table>`document.getElementById('content').innerHTML = html} catch (error) {console.log(error)}}
Add the function on the eventonload
<script type="text/javascript">window.onload = () => {console.log('Page loaded')showMessages()}</script>
We noticed that the default behavior of a form is to submit data via the GET method. We need to override this by passing a function on the onSubmit
handle. This function will get the event that was triggered as a parameter.
<form onSubmit="saveMessage(event)">...</form>
async function saveMessage(event) {event.preventDefault()​let id = event.target.id.valuelet data = {name: event.target.name.value,subject: event.target.subject.value,message: event.target.message.value}let url = ''let method = ''if(id) {//make a request to PUT /messages/:idurl = '/messages/' + idmethod = 'PUT'} else {url = '/messages'method = 'POST'}try {let result = await fetch(url, {method: method,headers: {'Content-Type': 'application/json'},body: JSON.stringify(data)}).then(response => response.json())showMessages()} catch(err) {alert('unable to save message')}}
DELETE/messages/:id
async function deleteMessage(id) {try {let url = '/messages/' + idlet result = await fetch(url, {method: 'DELETE'})showMessages()} catch(err) {alert('unable to delete message')}}