teaching machines

CS 347: Lab 18 – Express Chat

November 3, 2020 by . Filed under fall-2020, labs, webdev.

Welcome to lab. By now you have already watched the lecture videos on your own. Now we will apply the ideas from those videos in an exercise, which you will complete in small groups.

Within your breakout room, designate one of your team to be the screen sharer. Screen sharer, share your screen and claim your group’s task on Crowdsource. Make sure to enter every group member’s JMU eID so that they receive credit. Your group will be assigned a task number.

Team, complete the assigned task below. Screen sharer, be careful not to dominate. All members should contribute ideas.

Task

This task is a continuation from last lab.

Your task is to write a bare-bones chat application. It will consist of two parts: an Express-based web service that manages an array of messages, and an HTML/CSS/JS client that sends and receives messages through the service.

Screen sharer, follow these steps:

  1. Open Visual Studio Code.
  2. Click File / Open Folder, create a new folder, and open it.
  3. With the Live Share extension installed, select View / Command Palette, and choose Live Share: Start Collaborative Session.
  4. Copy the invitation link to your chat.

All team members should join the session.

Chat Server

Follow these steps to create your chat server with Express and Node.js:

Chat Client

Follow these steps to create your chat client with HTML, CSS, and JavaScript:

Screen sharer, when your group is done or when time is up, submit your group’s solution on Crowdsource. Paste in both the server and the client.

app.js

const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors());
app.use(express.json());

const port = 3003;

const messages = [
  {
    username: 'Bot',
    message: 'Welcome.',
  },
];

app.post('/message', (request, response) => {
  messages.push({
    username: request.body.username,
    message: request.body.message,
  });
  response.send(':)');
});

app.get('/messages/:index', (request, response) => {
  response.send(messages.slice(request.params.index));
});

app.delete('/clear', (request, response) => {
  messages = messages.slice(0, 1);
  response.send(':)');
});

app.listen(port, () => {
  console.log(`Live on port ${port}!`);
});

chatter.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Chatter</title>
  <style>
* {
  box-sizing: border-box; 
}

body {
  margin: 0;
  padding: 10px;
  display: flex;
  flex-direction: column;
  height: 100vh;
}

#messages-root {
  flex-grow: 1;
  font-size: 1.5em;
}

#sender {
  display: flex;
  flex-direction: row;
  flex-basis: 5em;
}

#new-message-box {
  flex-grow: 1;
}
  </style>
</head>
<body>

  <div id="messages-root"></div>
  <div id="sender">
    <textarea id="new-message-box"></textarea>
    <button id="send-button">send</button>
  </div>

  <script>
const username = prompt('Username?');

const sendButton = document.getElementById('send-button');
const messagesRoot = document.getElementById('messages-root');
const newMessageBox = document.getElementById('new-message-box');

let nextId = 0;
const domain = '172.28.66.231';
const port = 3003;
const url = `http://${domain}:${port}`;

function sync() {
  fetch(`${url}/messages/${nextId}`)
    .then(response => response.json())
    .then(data => {
      nextId += data.length;
      for (let message of data) {
        const p = document.createElement('p');
        p.innerHTML = `<b>${message.username}</b>: ${message.message}`;
        messagesRoot.appendChild(p);
      }
    });
}

setInterval(sync, 1000);

newMessageBox.addEventListener('keydown', event => {
  if (event.key === 'Enter') {
    send();
  }
});
sendButton.addEventListener('click', send);

function send() {
  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({username, message: newMessageBox.value}),
  }
  fetch(`${url}/message`, options)
    .then(response => {
      newMessageBox.value = '';
    });
}

  </script>
</body>
</html>