# 8: Let's Build A Webapp (and Bonus Generics) ###### tags: `Tag(sp22)` ## Logistics See the [policy slides](https://docs.google.com/presentation/d/1UgTF9UNs7y1wlhSBaCpga8rQumvidELfiYCPzUGKvrc/edit?usp=sharing). ## Let's Build A Webapp! This part of class is meant to prepare you better for this week's lab and for the front-end development coming in Sprint 3. (For many students who have disliked the back-end work in Sprints 1 and 2, being able to learn front-end development in Sprints 3 and 4 has been a lot of fun. And if you _did_ enjoy the back-end material, you might enjoy this stuff as well.) ### The Puzzle The New York Times website had a [puzzle](https://www.nytimes.com/interactive/2015/07/03/upshot/a-quick-puzzle-to-test-your-problem-solving.html) a few years back that I love to use in class. It went something like this: ![](https://i.imgur.com/EOIDbbx.png) ### The Problem Last Fall I went to run the puzzle in class, and the page was paywalled. Although Brown provides access through your logins, it's kind of a pain to set up. So, while you should definitely try the NYT's version if you can, _let's build our own_. We're going to write a web app today. Crucially, it will have _no back-end code_, and can just be run in your browser. ### HTML, CSS, and JavaScript (or, for us, TypeScript) How does a webpage work, anyway? Let's take a look at one I've got on my laptop: ![](https://i.imgur.com/mHfPDg4.png) Let's view the source of the page, to see what the browser is _really_ working with. In Safari, just hit command+option+U. (Similar shortcuts exist in other browsers.) We'll see something like this: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is a static page</title> <link rel="stylesheet" href="styles/main.css" type="text/css"> </head> <body> <p>Here is a paragraph of text</p> <p>Another paragraph, with <strong>bold</strong> text</p> <p>And a list that never changes: <ul> <li>Item 1</li> <li>Item 2</li> </ul> </p> <div class="demo-style"> And a section with custom styling for the background and text style </div> <div class="demo-style-2"> Here's another custom styled section with a fixed-width font, suitable for code </div> </body> </html> ``` What do you notice about the document? Hopefully: * it's _tree structured_: tags like `<html>` are either opened and closed symmetrically, or are leaf nodes that just provide some extra information. * it provides some _metadata_: what language the page is in, how the characters are encoded, and other hints that make it easier to process. * it turns the raw text of the page into a _formatted_ document: a list here, a paragraph there, that text should be emphasized, etc. This language is called HTML: HyperText Markup Language. "HyperText" because it's intended to contain links to other documents. "Markup" because it's structured in the way an old-school literature teacher might leave annotations on a student's paper: make that a list, bold here, restructure there. **HTML is responsible for giving _structure_ to the page.** You might have also noticed a reference to another file: `styles/main.css`. Let's take a look at that: ```css .demo-style { background-color: lightgreen; font-style: italic; } .demo-style-2 { background-color: lightblue; font-family: 'Courier New', Courier, monospace; } ``` A Cascading Style Sheet (CSS) file tells the browser how to _style_ the structure given in the HTML file. Exactly which font should be used? What color is the background? **CSS is responsible for giving _style_ to the page.** This is a classic separation of concerns. The HTML describes the document's structure, but not the low-level details of how to actually display that structure. This eases quite a few tasks. For example, user-specific settings for font size or color scheme don't need to interfere with the basic structure of the document! But, so far at least, this page is static. It never changes. We can't add anything to that list based on user input or anything else. ### Adding Dynamic Behavior Neither HTML nor CSS alone suffice to build a good web application. We need a way to add programmatic behavior to the page, and to do that, we probably want a programming language. There are dozens of options (including Java) but one tends to be far more popular than others: JavaScript. In fact, many popular web programming languages actually compile to JavaScript---which means browser developers can focus on optimizing JavaScript performance in their engine, confident in a broad impact. **JavaScript is responsible for _dynamic_ behavior in the page.** ### Getting Started with TypeScript Follow the instructions in this week's lab. For this lecture I've already [installed Node](https://nodejs.org/en/download/) so that I can run JavaScript locally. We'll also be using TypeScript in 0320. TypeScript is essentially JavaScript with types, and as you get experience with JavaScript, you'll very quickly see why those types are a good thing. So I also installed TypeScript via Node's package manager: ``` npm install -g typescript ``` Wherever we plan to put our TypeScript code, we need to initialize that directory with: ``` tsc --init ``` Here, I'll do that in a new `scripts` sub-folder. TypeScript compiles down to plain JavaScript, but we'd prefer not to have to constantly re-run the compiler. So, when we're ready to actually try the app (and make adjustments to the code), we'll execute: ``` tsc -w ``` in that folder, which tells TypeScript to constantly watch for changes, and automatically update the corresponding JavaScript, which is what the browser knows how to execute. ### Framing the Web App We Want Let's start writing the actual NYT puzzle clone. The old HTML won't really work: we need to have a document structure that (roughly) mirrors the puzzle. I won't type all this in live, but we'll talk through the rough structure. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="styles/main.css" type="text/css"> </head> <body> <main class="container"> <section id="old-rounds"> </section> <section class="new-round"> <div class="guess-round-current"> <label for="guess-1">Guess 1</label> <input type="number" id="guess-1"> <label for="guess-2">Guess 2</label> <input type="number" id="guess-2"> <label for="guess-3">Guess 3</label> <input type="number" id="guess-3"> </div> <div> <button id="guess-button" type="button">Guess!</button> </div> </section> </main> <script src="scripts/main.js"></script> </body> </html> ``` What would this page look like _without_ the script? Like this: ![](https://i.imgur.com/HFGkFX8.png) Clicking the button does nothing; we've not enabled any dynamic behavior yet. But the shape of the page roughly matches the NYT quiz. What would we *like* to happen when the button is clicked? Maybe: * the user has made a guess, supposedly, but we should validate that the guess is well-formed * we should check whether the guess matches, or fails to match, the hidden condition; * we should color the guess depending on its correctness and (since we want to allow more guesses), create a new block of text inputs for the next guess. All of this should happen when the button is clicked. Let's start from there, and build our `main.js` (which we'll actually call `main.ts` and let the compiler produce the JavaScript version). ```javascript // A reference to the guess button. let guessButton: HTMLButtonElement // When the window loads, the value of window.onload executes // the () => ... syntax is just JavaScript syntax for an unnamed function (lambda) window.onload = () => { // On window load, get the reference to the guess button. We'll need that! guessButton = document.getElementById("guess-button") as HTMLButtonElement // When the button is clicked, run this function // console.log is the System.out.println of Javascript (but where does it go?) guessButton.addEventListener("click", () => console.log('click!')) } ``` Because there isn't always a good place to print text in a webpage, the output of `console.log` goes to the _web console_: ![](https://i.imgur.com/JLmSDHs.png) You can do all kinds of useful debugging in the console, like evaluate expressions: ![](https://i.imgur.com/eLmYqTo.png) Now that we know how to do something when the button is clicked, let's do something more involved. ### The Result We might end up somewhere like this: ```javascript= // Each guess is stored as an array of strings. GUESSES stores all previous guesses. let GUESSES: Array<Array<string>> = [] // A reference to the guess button. let guessButton: HTMLButtonElement window.onload = () => { // On window load, get the reference to the guess button guessButton = document.getElementById("guess-button") as HTMLButtonElement guessButton.addEventListener("click", () => updateGuesses()) } /** * Tells whether or not a guess was correct. * @param {string[]} guess A guess of three integers in string form. */ function pattern(guess: string[]): boolean { return !(guess.length !== 3 || parseInt(guess[0]) >= parseInt(guess[1]) || parseInt(guess[1]) >= parseInt(guess[2])) } /** * When the guess button is clicked, updates the GUESSES array and re-renders HTML. */ function updateGuesses() { const firstGuess = document.getElementById("guess-1") as HTMLInputElement const secondGuess = document.getElementById("guess-2") as HTMLInputElement const thirdGuess = document.getElementById("guess-3") as HTMLInputElement GUESSES.push([firstGuess.value, secondGuess.value, thirdGuess.value]) console.log("Guesses:", GUESSES) renderOldGuesses() } /** * Handles rendering HTML when GUESSES is updated. */ function renderOldGuesses() { let newHtml: string = '' GUESSES.map((guess: string[], guessNumber: number) => { const correct: boolean = pattern(guess) newHtml += `<div class="${correct ? "correct-guess" : "incorrect-guess"}"> <p>Guess #${guessNumber + 1}</p> <input value="${guess[0]}" readonly /> <input value="${guess[1]}" readonly /> <input value="${guess[2]}" readonly /> </div>` }) const oldGuesses = document.getElementById("old-rounds") as HTMLDivElement oldGuesses.innerHTML = newHtml } ``` ## Bonus Generics 1 (of ?) We're going to do a livecoding demo of writing a generic `Pair` class in Java. Here is the final code: ```java= /** * Wrapper for a pair of values. The values do not need to be the same type. * Any two pairs having the same value types should be comparable, first by * the first ("left") element, and then by the second ("right") element in case * of equal left elements. * * We enforce the comparable requirement by implementing the Comparable interface, * which is itself generic. The declaration says that a Pair<A,B> must provide a method: * compareTo, which accepts one argument with type Pair<A, B>. * * @param <A> Type of the first ("left") value * @param <B> Type of the second ("right") value */ class Pair<A extends Comparable<A>, B extends Comparable<B>> implements Comparable<Pair<A, B>> { private final A left; private final B right; public Pair(A a, B b) { left = a; right = b; } public A getLeft() { return left; } public B getRight() { return right; } @Override public String toString() { return "(" + left + " . " + right + ")"; } @Override public int compareTo(Pair<A, B> other) { int leftCompare = this.left.compareTo(other.left); if(leftCompare != 0) return leftCompare; int rightCompare = this.right.compareTo(other.right); return rightCompare; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Pair)) return false; // we'll come back to this later Pair<?, ?> otherPair = (Pair<?, ?>) o; // don't care about the exact types return Objects.equals(left, otherPair.left) && Objects.equals(right, otherPair.right); } @Override public int hashCode() { return Objects.hash(left, right); } /** * This method exists to make sure we can actually create and use pairs. * Normally, such a class wouldn't have a demo() method, but we want to * more easily run the in-class exercise. */ public static void demo() { List<Pair<Integer, String>> lst = Arrays.asList( new Pair<>(4, "potato"), new Pair<>(2, "apple"), new Pair<>(7, "pizza")); Collections.sort(lst); System.out.println(lst); // Requirement: get this to run. } } ```