Week 14 — Web apps and 'The Cloud'

This week's topic is about creating content for the Web.

Evaluation

Up to 10 points can be gained towards your final score by completing the in-class exercises on Friday.

What you will learn from this class

Preparation

This week's preparation is to watch three short videos about Web applications and three short videos about 'The Cloud', and then complete a couple of short exercises to experience some of the fundamental concepts.

Videos

Each set of three videos progresses from very simple to more detailed.

Web Apps

What is a Web App? 1:48 https://www.youtube.com/watch?v=qt6gSW-uYKI
What is a web application? 6:28 https://www.youtube.com/watch?v=Hv3czsQh8tg
Web pages, Websites, and Web Applications 6:36 https://www.youtube.com/watch?v=ylbQrYhfa18

The Cloud

Computer Basics: What Is the Cloud? 2:31 https://www.youtube.com/watch?v=4OO77HFcCUs
What is the cloud? 3:00 https://www.youtube.com/watch?v=i9x0UO8MY0g
The Three Ways to Cloud Compute 7:09 https://www.youtube.com/watch?v=SgujaIzkwrE

Notes

There are two exercises below. The first shows how to run code in the user's browser. The second shows how to run a program on the server to generate page content dynamically.

If you do not want to try the second exercise then you skip the rest of this section.

If you want to try the second exercise then you will need to install a local Web server that can run server-side scripts. The most popular language for that is called PHP. Run the following command to check if you already have PHP installed on your computer:

php --version

If your shell says “command not found” then expand the instructions below to learn how to install it.

Installing PHP

Web projects

The following two mini-projects illustrate (A) how to run a program in the client Web browser when displaying a page, and (B) how to run a program in the server to generate parts of a Web page dynamically. These techniques are the foundations of Web and cloud apps.

Project A: Create a small 'click counter' Web app that runs in your browser

We have already seen some of the necessary parts for making a small Web app:

To make a small 'app' such as a click counter requires just a few additional things, which we will investigate soon:

1. Create a file containing just the structure of the web page

Let's begin very simply and create a file containing just the HTML describing the visible structure of the application. (You can call file called anything you like, including “index.html”.) The structure will have the following parts:

<!DOCTYPE html>
<html>
  <body>
    <h1>Click counter</h1>
    <p>
      0
    </p>
    <p>
      <button>
        Count
      </button>
    </p>
  </body>
</html>
2. Modify the content of the first paragraph when the button is pressed

The text content of a paragraph is stored in the innerHTML attribute of the p element. Assigning a new value to the innerHTML property of a paragraph will dynamically change what is displayed inside that paragraph. For example, this will remove the old content of a p whose id is my-paragraph and replace it with a 'Welcome' message:

document.getElementById('my-paragraph').innerHTML = 'Welcome to some new content!'

To run this code whenever a button is clicked, put the code in the onclick property of the button. The first time the button is clicked, the 0 that is initially in the paragraph will be replaced by a longer message. Let's add the two things we need which are an id for the paragraph (we'll call it display)

<p id="display"> 0 </p>

and the onclick property for the button (containing the code that updates the paragraph's content).

<button onclick="document.getElementById('display').innerHTML = 'You clicked!';">

Click here to see the updated Web site code

3. Increment the counter when the button is clicked

The innerHTML property of an element can also be read, so we can also store information there. Let's store the value of the counter in the innerHTML property of the display paragraph.

One of the interesting things about JavaScript is that values can be used very freely. If a string 'looks like' a number then you can treat it as a number (and perform arithmetic on it). This means we can use the string stored in the innerHTML of the display paragraph to remember the numeric value of the counter and to represent the string that should be displayed in the paragraph.

The += operator will increment its left-hand side by its right-hand side. For example, x += 42 will increment x by 42. Instead of assigning a new string to the display, we'll use the += operator to add 1 to it.

<button onclick="document.getElementById('display').innerHTML = document.getElementById('display').innerHTML + 1;">

Click here to see the updated Web site code

Well, that almost worked!

Instead of adding 1 to the numeric value of the count (which is stored as a string), JavaScript converted the 1 into a string and then added that to the end of the displayed count.

JavaScript 'pro-tip': if you have a string that you know represents a decimal integer then to convert it into an actual integer you can use the 'unary +' operator. So, if x contains the string "41" then

x + 1

will be "411", whereas

+x + 1

will be 42, which is exactly the effect we want when incrementing our counter.

Putting a unary + in front of the left hand side of the binary + operator makes the counter work properly.

<button onclick="document.getElementById('display').innerHTML = +document.getElementById('display').innerHTML + 1;">

Click here to see the updated Web site code

4. Tidy up the code

More complex Web apps will, of course, have a lot more JavaScript code. The script element provides a place to put JavaScript code (in a similar way to the style element providing a place to put CSS code). One advantage of using a script element is that you can define things like 'helper functions' and global variables to store persistent values. Let's tidy up the code of our Web app in the following ways:

<script>
  var display = document.getElementById("display");
 
  function count(amount)
  {
    display.innerHTML = +display.innerHTML + amount;
  }
</script>

The first line of this script creates the global variable display and assigns to it the element whose id is display. (In other words, the variable will remember the p paragraph element that is holding and displaying the current counter value.)

The last four lines of this script declare a function called count with one parameter amount. When the function count is called with a numeric argument it first converts display.innerHTML to an integer, adds amount to that integer, and then stores the result back in display.innerHTML. Storing the results back into the display.innerHTML has the side effect of causing the browser to redraw the changed parts of the screen, thereby showing the updated counter.

The final Web app looks like this:

<!DOCTYPE html>
<html>
  <body>
    <h1>Click counter</h1>
    <p id="display">
      0
    </p>
    <script>
      var display = document.getElementById("display");
 
      function count(amount)
      {
	display.innerHTML = +display.innerHTML + amount;
      }
    </script>
    <p>
      <button onclick="count(1)">
        Count
      </button>
    </p>
  </body>
</html>
Exercises and challenges

1. Does it matter where you put the script element? What happens if you move it to the start of the body?

2. Add a second button that decrements the counter.

3. Replace the buttons with a row of four buttons labelled -10, -1, +1, and +10. Make the buttons add the appropriate amount to the counter. Add another row containing just one button labelled reset that resets the counter to 0 when it is clicked.

4. Explore some more pieces of JavaScript. Maybe start with the functions ''setInterval'' and ''clearInterval'' which can be used to call a function regularly, for example, once every second. Use these functions to implement a stop watch with three buttons: “start”, “stop”, and “clear”.

Project B: Create a simple 'text chat' Cloud app that executes on both server and client

Note: to run this example you (or one of your friends) need to have a computer with PHP installed. PHP only needs to be installed on the server, so you can still try this example by connecting your browser (the client) to the app running on your friend's Web server where PHP is installed. To do this, instead of visiting localhost:8000/chat.php just replace localhost with the IP address of your friend's computer. Since the app is 'served' from your friends Web server, there is nothing left for you to do (except maybe help them to implement the chat app!).

However, if you did install PHP on your computer, then please have fun following along with the rest of this project.

0. Start a Web server that can run server-side scripts

If you are still running the Python Web server, stop it first.

Create a directory for your chat project. Change to that directory and start the PHP Web server on port 8000.

mkdir WebChat
cd WebChat
php -S localhost:8000

(If you want your friends to be able to connect to your server, run “php -S 0.0.0.0:8000” instead.)

1. Create a file containing just the structure of the web page

What is the simplest text chat app that you can imagine? Obviously, at the very least, the client would need:

It could look something like the window shown on the right. So, just as with the simple counter Web app, let's begin by entering the HTML that we need to display the static structure of the page.

Because we will be running some PHP code every time the web page is accessed, we have to use a file name ending in .php (instead of .html). You can call your file anything you like, but something like chat.php would be appropriate.

Inside a .php file you can write HTML, including CSS style and JavaScript that runs on the client, exactly like any other Web page. The following HTML will create the basic static structure of the page:

<html>
<head>
  <title>PHP Chat</title>
</head>
<body>
  <p>
    <textarea rows="10" cols="80">
    </textarea>
  </p>
  <p>
    <form>
      <input type="text" size="70" />
      <input type="submit" value="send" />
    </form>
  </p>
</body>
</html>

The new elements here are textarea, form, and input.

A textarea creates a box of a given size (rows and columns) that can display and/or allow editing of text.

input creates various kinds of input element according to its type attribute. A text input creates a single-line text box that you can type into. A submit input creates a button whose value attribute can be used to set its label.

A form groups several input elements together and allows data from those elements to be sent ('posted') back to the server. Within the form, clicking the submit input button will cause the form's data to be posted back to the server. One source of data sent back to the server is the content of any text input boxes. (Conveniently, pressing Enter inside a text input box will also post the content of the form back to the server.)

2. Add some dynamically generated content to the page

To demonstrate how PHP generates content in the page, let's insert the name of the server into the page title.

In addition to normal HTML, a .php file can also contain opening “<?php” and end “?>” tags. Between those tags is PHP code that is run on the server before the content of the file is sent back to the client in the response to the HTTP GET request. The tags and PHP code are removed from the page contents, but anything that the PHP code prints while it is running is added to the page content.

The following PHP code prints the name of the server:

echo gethostname()

Adding that code into the content of the title element, between <?php and ?> tags, inserts the server name into the page title every time the client fetches the page.

<head>
  <title>PHP Chat @ <?php echo gethostname() ?></title>
</head>
3. Make the "send" button upload the text input area to the server

To send the form data back to the server we have to do three things:

  1. tell the form how to reload the page when the submit button is pressed,
  2. tell the text input how to name its content while the form is reloading, and
  3. add the uploaded data to the textarea content as the page is reloading.

First, add two attributes to the form to make it reload the page when its data is submitted. The method attribute says how to send the form data back to the server. GET and POST are the usual ways, and we'll use POST. The action attribute says what URL should be used to reload a 'result' Web page. We will use the original chat app URL. In PHP, variable names all begin with a dollar sign “$”. The PHP variable $_PHP_SELF contains the URL of the app page.

<form action="<?php $_PHP_SELF ?>" method="POST">
  <input type="text" size="70" name="send" />
  <input type="submit" value="send" />
</form>

The name attribute has been added to the text input element. Setting that attribute to send will allow the server retrieve the content of the text input element using the name send when the page reload request is received.

If you reload the page you should now find that either clickling the send button, or pressing Enter in the text input field, will cause the page to reload.

4. Echo the uploaded data in the text area

The input text is currently being thrown away by the server. Let's instead insert that text into the text area, so that we can see the data is being uploaded properly.

To do this we will insert some PHP code into the textarea content. This code has to

  1. retrive the data from the text input that was uploaded along with the page request (under the name send), and
  2. if the uploaded data is not empty, echo it to provide the content for the textarea.

When the page is reloaded, the PHP variable $_REQUEST contains all the information about the request sent by the client. It behaves like an array, indexed by the name of the data you want. The data send from the input text is included in the $_REQUEST array. We previously asked the form element to call that data send (using the name attribute of the text input). The data of interest is therefore available as $_REQUEST["send"].

Inside the textarea we will add some PHP code that retrieves the $_REQUEST["send"] data, store it in the variable $send, and if it is not empty then echo it (to make it become the conent of the textarea element).

<p>
  <textarea rows="10" cols="80"><?php
    $send = $_REQUEST["send"];
    if ($send) echo $send;
?></textarea>
</p>

5. Accumulate the chat text in a file on the server

PHP can write to, and read from, files stored on the server. Let's append each line of text sent in $_REQUEST["send"] into a 'chat log' file, and then insert the contents of that file into the page as the content of the textarea element. The effect will be to collect all the text sent to the chat app and echo them all in the display area.

The code will have to

  1. add a newline to the end of the uploaded text,
  2. append the line to a 'chat log' file,
  3. get the entire contents of the 'chat log' file, and
  4. echo the contents of the 'chat log' file to provide the contents of the textarea element.

Let's store the 'chat log' in a file called chatlog.txt. Instead of echoing the $send text into the textarea, first (if it is not empty) append a newline ("\n") to it (using the string concatenation operator “.”) and then use the function file_put_contents to append the result to the chatlog.txt file.

Next, let's use file_get_contents to retrive the entire contents of chatlog.txt and (if it is not empty) echo those contents to make them become the content of the textarea element.

  <textarea rows="10" cols="80"><?php
    $send = $_REQUEST["send"];
    if ($send) {
      $send = $send."\n";
      file_put_contents("chatlog.txt", $send, FILE_APPEND);
    }
    $chat = file_get_contents("chatlog.txt");
    if ($chat) echo $chat;
?></textarea>

We now have a working Web chat app! Your complete app should look like this:

<!DOCTYPE html>
<html>
<head>
  <title>PHP Chat @ <?php echo gethostname() ?></title>
</head>
<body>
  <p>
    <textarea rows="10" cols="80"><?php
      $send = $_REQUEST["send"];
      if ($send) {
        $send = $send."\n";
        file_put_contents("chatlog.txt", $send, FILE_APPEND);
      }
      $chat = file_get_contents("chatlog.txt");
      if ($chat) echo $chat;
  ?></textarea>
  </p>
  <p>
    <form action="<?php $_PHP_SELF ?>" method="POST">
      <input type="text" size="70" name="send" />
      <input type="submit" value="send" />
    </form>
  </p>
</body>
</html>
Excercises and challenges

1. Automatically set the focus to the text input area when the page (re)loads.

Currently it is necessary to click in the text input area to begin typing into it. One way to cure this is to set focus to the correct element when the page has finished loading. Similar to the onclick attribute for button elements, you can use the onload attribute of the body element to run some JavaScript when the page has finished loading completely.

The code you need will look something like this:

document.getElementById('text').focus()

2. Scroll the textarea element to the bottom when the page is (re)loaded.

When the chat textarea has more lines of content than space to display them, it displays the oldest lines instead of the newest ones. To fix this, you can

The JavaScript to scroll a textarea to the bottom looks like this:

var chat = document.getElementById('chat');
chat.scrollTop = chat.scrollHeight;

3. Prepend the time to each message.

In PHP you can obtain the time as a string like this:

date("H:i:s")

If you prepend this to the message (in the same statement that appends the newline character to it) you will get timestamps in the chat.

4. Add each participant's name to their chat messages.

Add another text input field to the form that contains your name. Automatically include your name at the start of the message. The easiest way to do this is to send your name (along with chat message text) to the server then the send button is pressed, then use that value both to include your name in the message and to re-initialise the value attribute of the same text input field which will preserve your name across page reloads.

Is this a Web app or a cloud app?

Calling this a 'cloud app' is maybe debatable, but it does…

The server-side data is stored in a simple text file and the server code runs only on one server. If the persistent data were instead stored a distributed database, and if multiple servers cooperated to share the work needed to handle thousands of simultaneous users, then there would be no question that this qualifies as a 'cloud app'.