useState setters and the reducer?GET, POST, PATCH, DELETE) reflect the operating being performed?We have arrived at the last big idea of the semester: managing global state. To deal with complex and shared data in our React apps, we will push the data into an object managed by Redux. With this new manage of managing the data, we’ll have to find new ways of changing state and triggering re-rendering of our components.
Here’s your TODO list:
Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
We look at the mechanics of web services last time. Today we build up a non-toy web service for a time capsule application. Behind our web service will be a MySQL database, and our service will endpoints for the four common CRUD operations for operating on our database’s records: creating, rreading, updating, and deleting.
Here’s your TODO list:
sudo apt install nginx.today-api.twodee.org.sudo certbot certonly --dry-run --apache -d NEW-DOMAIN. Replace NEW-DOMAIN with your new domain name. Once that reports success, run the command again without --dry-run. We include --dry-run initially because Let’s Encrypt blocks you if you make too many failing requests in an hour. We include --apache because our Nginx server is not set up to serve out the files that Let’s Encrypt expects to verify that you own the server.Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
Many websites pull down data from web services, just as we did with the News API. But how are these web services made exactly? That’s what we explore in this lecture. We’ll use Express to create our own web service that responds to HTTP requests and serves back its data through JSON. We’ll also see more advanced uses of the fetch function and overcome an issue of multi-server resource sharing.
Here’s your TODO list:
Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
Your app must meet the following expectations:
fetch and not through any helper library.twodee.Listen 443 line in your virtual host configuration file. This line is already included in another configuration file, and including it twice will result in an error.ufw to block all ports but the ones you need for SSH and your allowed web servers.pm2 so that it stays running.twodee.By the due date, share in a direct message on Slack a brief but itemized breakdown of how you believe you have met the expectations listed above.
]]>The first theme of this course has been learning the foundational technologies of the web: HTML, CSS, and JavaScript. Today we officially reach the second theme: designing modern web apps with React. Systems like React ease the burden of designing interactive sites with dynamic content.
Here’s your TODO list:
props.Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
Today we hit up higher-order functions, a feature of modern languages that will shorten up your code considerably. Once you know a few of these higher-order functions, you may never write loops again. Why? Because so much of our looping algorithms follow certain patterns, we can generalize those patterns into reusable functions. For the parts of the algorithms that differ, we take in functions from the callers are parameters.
We’ll be using these higher-order functions frequently when we build React apps, starting next week.
Here’s your TODO list:
map, filter, reduce, or higher-order functions in general. This might be a question you really don’t know the answer to or one that you do know the answer to and are putting forward as a challenge to your peers.Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
Last time we examined objects and how to pass them around using JSON. This time, we apply these ideas by consuming a web service: News API. We’ll use JavaScript’s builtin fetch function to grab and send JSON data.
We started looking at this before spring breeeaaak happened, but I’ve re-implemented the example we started for the sake of completeness.
Here’s your TODO list:
fetch, or web services. This might be a question you really don’t know the answer to or one that you do know the answer to and are putting forward as a challenge to your peers.Your participation in this thread is not graded. I include it so that we can maintain some real human interaction.
See you next time.
There’s a pandemic going on right now, and it has turned the world upside down. We are no longer able to meet in person. But we’ll try to finish out this semester through the web. How apt.
Our format for the rest of this constrained is constrained by a few things. First, we are not all in the same time zone. Second, even if we were in the same time zone, some of you don’t have control over your schedule. You may be caring for family, sharing the internet with others with less flexible schedules, or nursing orphaned lambs on the family farm. Third, not all of us have great internet connections in our bunkers. I am one of those people. Cable doesn’t reach our house, nor DSL. We don’t own a television, so a satellite doesn’t seem worth it. Our only real option is our mobile data plan, but our connection speeds do not really support streaming video. For all of these reasons, synchronous virtual lectures are simply not an option.
Instead I will be sharing pre-recorded videos that you can watch at your convenience. These will be available on YouTube—and perhaps elsewhere. I’ve chosen YouTube because it does a reasonably good job at generating transcriptions of my words, and it allows you to increase the playback speed. However, some of you are in a country where YouTube is blocked. If you are unable to access YouTube, please let me know. I will find an alternative way to share these videos with you.
So, without further ado, here’s your TODO list our first virtual lecture, in which we formally investigate objects in JavaScript:
Your participation in this thread is not graded.
When the semester officially resumes next week, I’ll shared a revised grading scale. Project 1 will be due April 12.
See you next time.
Last time we started looking at how JavaScript brings actions into normally sedate HTML. We used it to dynamically generate an HTML structure. Today we look at using JavaScript to deal with form input. We’ll also use it to get content from external sources. In particular, we’ll generate a web application for consuming the latest news headlines.
It’s not often that we generate HTML directly like we did in the preceding example. More often we write code to handle events that are triggered by the user interacting with our page.
Suppose we have a form for getting a 7-digit number for the user. We might create this HTML structure:
<!DOCTYPE html>
<html>
<head>
<title>...</title>
</head>
<body>
<label for="number-input">Enter a 7-digit number:</label>
<input id="number-input" type="text">
<input id="submit-button" type="button" value="Submit">
</body>
</html>
Let’s sanitize the user data. We’ll disable the submit button and only enable it when we get exactly seven digits using this JavaScript:
const submitButton = document.getElementById('submit-button');
const numberInput = document.getElementById('number-input');
submitButton.disabled = true;
numberInput.addEventListener('input', () => {
if (numberInput.value.match(/^\d{7}$/)) {
submitButton.disabled = false;
} else {
submitButton.disabled = true;
}
});
Let’s include this script in the HTML file with this tag in head:
<head>
<script src="form.js"></script>
</head>
Our script fails. That’s because the elements the script grabs handles to do not exist at the time the script is loaded. We either have to place the script tag at the bottom of the page, or we must add the defer attribute to schedule it to be executed after the HTML is parsed. The defer attribute feels like better organization. We use it like this:
<head>
<script defer src="form.js"></script>
</head>
This works nicely, but be warned. Suppose we were going to send this data up to a server somewhere and maybe throw it into a database. Sanitizing the user input only on the client is not enough. Because the browser lets us enter the JavaScript sandbox, users can programmatically modify the page. We can execute our own code to free up the submit button. You must always verify that the data is valid on the server.
With exactly one neighbor, claim your task on Crowdsource. (Everyone will be assigned task 1.) Then recreate the following calculator:

When the operand inputs change, automatically update the sum. Build your solution off of this starter code:
<!DOCTYPE html>
<html>
<head>
<title>...</title>
<style>
body {
font-family: sans-serif;
}
</style>
</head>
<body>
<!-- Add your HTML and JavaScript here. -->
</body>
</html>
If you are stuck, I can offer a couple of hints.
value on a form element, you are probably going to get a string back. Convert it to a number with parseInt or parseFloat.
The sum is just a span element with an id. You can update its contents by setting its innerText property.
Submit your solution on Crowdsource.
After we get this working, as a class we’ll add a select menu to allow the user to pick the arithmetic operation.
It’s often the case that an application must get its data from an external resource—perhaps a resource that is far away. When that resource is exposed through HTTP, we call it a web service. We can bring down data from a web service through JavaScript’s fetch function.
When we call fetch, the browser does not wait around until the result comes in. Rather, it returns immediately and the browser starts executing the next instruction. If we have code that we want to run once we have the data, we have to register that code as a callback. The mechanism that JavaScript provides to accomplish this asynchronicity is called a promise. The fetch function returns a promise of some future data, and we register our callback function with the then method, like so:
const fetchPromise = fetch(url);
fetchPromise.then(response => ...);
If our web service gives us back data in JSON form, we need to parse the JSON into an object. The response object has a json that returns not the object, but another promise because parsing might be slow. So, to actually act on the data, we need something like this:
const fetchPromise = fetch(url);
const jsonPromise = fetchPromise.then(response => response.json);
jsonPromise.then(data => {
// ...
});
Normally we see this code chained together with no intermediate variables.
fetch(url).
then(response => response.json).
then(data => {
// ...
});
Let’s create a page that consumes the News API web service. We’ll create a select menu to choose a news source, and then we’ll show the 20 most recent headlines for that source. We start with this core HTML:
<select id="sources-picker"></select>
<ul id="headlines-list"></ul>
JavaScript will be responsible for populating these elements. We load up a script with this element in head:
<script defer src="news.js"></script>
The News API requires that we get an API key to request data. We definitely should not publicly release this API key, as others could get a hold of it and do nefarious things under our name. But for today we will be irresponsible and just include it in the JavaScript. Let’s also grab handles to our two elements.
const API_KEY = '...';
const sourcesPicker = document.getElementById('sources-picker');
const headlinesList = document.getElementById('headlines-list');
The News API documentation tells us about the sources endpoint. We call fetch on the URL and provide the language parameter to get all sources that publish in English. We also need to send along our key using a custom HTTP header. The code gets a bit ugly, so we’ll hide it in a function.
function loadSources() {
fetch('http://newsapi.org/v2/sources?language=en', {
headers: {
'X-Api-Key': API_KEY,
},
}).
then(response => response.json()).
then(data => {
// ...
});
}
In our callback, we want to turn each source into an option and append it to our select menu. Instead of crafting the literal HTML, we’ll create an element directly using the API that the browser provides.
if (data.status === 'ok') {
for (let source of data.sources) {
const option = document.createElement('option');
option.value = source.id;
option.textContent = source.name;
sourcesPicker.appendChild(option);
}
}
When we call loadSources, our menu fills up.
Now let’s grab articles for the selected source. News API provides another endpoint for this. We retrieve the headline data much like we retrieve the source data.
function loadHeadlines(source) {
fetch(`http://newsapi.org/v2/everything?language=en&sources=${source}&pageSize=20`, {
headers: {
'X-Api-Key': API_KEY,
},
}).
then(response => response.json()).
then(data => {
// ...
});
}
For our callback, we want to create an a element wrapped up in an li element.
if (data.status === 'ok') {
for (let article of data.articles) {
const link = document.createElement('a');
link.href = article.url;
link.textContent = article.title;
link.target = '_blank';
const li = document.createElement('li');
li.appendChild(link);
headlinesList.appendChild(li);
}
}
At the top-level of our script (our “main”), we must initialize the sources and handle change events.
loadSources();
sourcesPicker.addEventListener('change', () => {
loadHeadlines(sourcesPicker.value);
});
We can now load headlines! But after selecting our second headline, we see that the first articles we grabbed are still around. We need to clear out the list before we append the new articles. Let’s add a helper method for this.
function clearChildren(parent) {
while (parent.children.length > 0) {
parent.removeChild(parent.lastChild);
}
}
Then we call this method at the beginning of our callback.
clearChildren(headlinesList);
We now have a web app for consuming the news. But it’s probably not good for our mental health to actually use it.
Here’s your TODO list for next time:
See you next time.
P.S. It’s time for a haiku!
The news has been grim
Disable your ad blocker
The smiles will return
P.P.S. Here’s the code we wrote together in class…
]]>