You are on page 1of 242

HTML Concepts

Thursday, July 7, 2022 2:21 AM

HTML and CSS (Intermediate level)

HTML Concepts
1 Introduction
2 Emmet
3 SVG
4 Tables

CSS Concepts
1 Default Styles
2 CSS Units
3 More Text Styles
4 More CSS Properties
5 Advanced Selectors
6 Positioning
7 Css Functions
8 Custom Properties
9 Browser Compatibility
10 Frameworks and Preprocessors

Forms
1 Form Basics
2 Form Validations
3 Project: Sign-up Form

HTML and CSS Page 1


Introduction
Thursday, July 7, 2022 2:16 AM

There is a lot that you can do with CSS that you’ll learn throughout this course,
such as variables, functions, shadows and of course grid layouts! So buckle up! By
the time you finish this course you’ll be able to recreate just about any web design
you can find on the internet… which is an important skill to carry forward. Even if
you are not shooting for a front-end specific job, being able to make your portfolio
pieces look nice is important when it comes to making yourself stand out.
Assignment:
1. Read through this HTML elements reference to get an overview of what other
HTML elements are available to you. No need to commit this to memory
because you’ll be learning the important parts as we go, but having a glance
now will help the content stick later.
2. Take a glance at a somewhat overwhelming looking CSS Cheat Sheet. Again,
we don’t need you to learn anything specific, or memorize anything from this
list, just use it to get a feel for what you still have left to learn!

HTML and CSS Page 2


Emmet
Thursday, July 7, 2022 2:17 AM

Introduction
Emmet is a plugin, built into VS Code, that helps you write HTML and CSS more
efficiently by providing a bunch of clever shortcuts. You must have written a good
amount of HTML and CSS, and if you have been using VS Code there’s a big chance
that you have already encountered Emmet in some way.

Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Use some of Emmet’s most useful shortcuts.
• Set up custom Emmet key bindings in VS Code.

Emmet
Emmet is a really useful tool for anyone that works a lot with HTML and CSS.
Luckily, Emmet does not have that big of a learning curve, and if you already know
how to write HTML and CSS you’ll have no trouble picking up Emmet
abbreviations.
Let’s start off by generating an HTML boilerplate with Emmet. Opening up an
empty html file in VS Code and entering ! should trigger Emmet suggestions like so:

Pressing enter should generate the following text:

HTML and CSS Page 3


We have just used one of many Emmet abbreviations. There are lots of useful
Emmet abbreviations that you should check out, like Wrap with Abbreviation and
Remove Tag. Definitely go through those before moving forward.

Assignment

1. This is a good video on Emmet. Go ahead and watch it.

2. Take a look at the Emmet cheat sheet. You don’t have to memorize it, but it’s
good that you get familiar with the different ways it can be used.
3. Go through the Emmet documentation. Once again, no need to memorize
everything but it would be good if you played around with all the different
possibilities.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• Emmet Keybindings by Andrés Gutiérrez, is a set of Emmet keybinds for Visual
Studio Code. It can be used as a pre-defined group of keybinds, in case you
don’t know what to map to which keys.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.

HTML and CSS Page 4


This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Why should you use Emmet?
• What are some useful Emmet abbreviations?
• What syntax would you use to create this element <p class="text"></p>?
• What syntax expands to an element with a child element inside of it? For
example: <div><p></p></div>
• What syntax would you use to create three elements that have the same class
name?

HTML and CSS Page 5


SVG
Thursday, July 7, 2022 2:17 AM

Introduction
SVGs are a very common image format on the web. They can be a little confusing
at first, but once you know how to use them, they are an incredibly powerful tool
for creating high-quality, dynamic images for your website.
In this lesson, we will learn exactly what SVGs are, what they’re used for, and how
you can embed them in your websites.
Learning Outcomes
1. What SVGs, Vector Graphics, and XML are
2. How to create simple SVGs and add them to your websites
3. When to use SVGs, and when a different image format would be more
appropriate
What are SVGs?
SVGs are a scalable image format, which means they will easily scale to any size
and retain their quality without increasing their filesize. They’re also very useful if
you need to create or modify your images programmatically, because you can
change their properties through CSS and JavaScript.
SVGs are often used for:
1. Icons
2. Graphs/Charts
3. Large, simple images
4. Patterned backgrounds
5. Applying effects to other elements via SVG filters

Okay, but what are they?


“SVG” stands for “Scalable Vector Graphic”. Vector graphics are simply images
defined by math, as opposed to traditional “raster graphics,” where your image is
defined by a grid of pixels. With raster graphics, the detail is limited to the size of
that pixel grid. If you want to increase the size of the image (scale it), you have to
increase the size of that grid. How do you decide what all those new pixels should
look like? There’s no simple solution. Additionally, the larger the grid, the bigger
your filesize grows.
With vector graphics on the other hand, there’s no grid. Instead, you have
formulas for different shapes and lines. Since these are just formulas, it doesn’t
matter how large or small you want them to appear–they can scale to any size you
want, and it will have no effect on the quality or the size of the file.
SVGs have another interesting aspect to them: they’re defined using XML. XML
HTML and CSS Page 6
SVGs have another interesting aspect to them: they’re defined using XML. XML
(aka, “Extensible Markup Language”) is an HTML-like syntax which is used for lots
of things, from APIs, to RSS, to spreadsheet and word editor software.
The fact that SVG source-code is XML has a few key benefits.
First, it means that it is human-readable. If you were to open up a JPEG in a text
editor, it would just look like gobbledygook. If you were to open up an SVG,
however, it would look something like this:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect x=0 y=0 width=100 height=50 />
<circle class="svg-circle" cx="50" cy="50" r="10"/>
</svg>

It might still be confusing, but hey–those are words! Tags! Attributes! Compared to
binary file formats like JPEG, we’re definitely in familiar territory.
The second benefit of XML is that it’s designed to be interoperable with HTML,
which means you can put the above code directly in an HTML file, without any
changes, and it should display the image. And because these can become elements
in the DOM just like HTML elements, you can target them with CSS and create
them using the Element WebAPI you’ve already been using!
Drawbacks
So, clearly SVGs are awesome! Time to go convert all of our images to SVG, right?
Well, not quite. SVGs are great for relatively simple images, but because every
single detail of the image needs to be written out as XML, they are extremely
inefficient at storing complex images. If your image is supposed to be photo-
realistic, or it has fine detail or texture (“grunge textures” are a great example),
then SVGs are the wrong tool for the job.
Anatomy of an SVG
Typically, you will not want to create SVGs from scratch in your code. Most often
you will download the file or copy the code either from a website, or from an
image editor that can create them (Adobe Illustrator and Figma are two popular
apps that can create SVGs). However, it’s pretty common to download an SVG and
want to tweak or adjust it just a little bit, so knowing what all the bits and pieces
are, and how they work is very useful.
1. xmlns - stands for “XML NameSpace”. This specifies what dialect of XML
you’re using–in our case, that dialect is the SVG language spec. Without it,
some browsers will not render your image or will render it incorrectly. If
you’re interested in a full breakdown of what this attribute is and why it’s
necessary, check out this excellent MDN article.
2. viewBox - defines the bounds of your SVG. When you have to define the

HTML and CSS Page 7


2. viewBox - defines the bounds of your SVG. When you have to define the
positions of different points of the elements in your SVG, this is what that’s
referencing. It also defines the aspect ratio and the origin of your SVG. So it’s
doing quite a lot! Be sure to play around with different values in the example
above to get a feel for how it affects the shapes.
3. class, id - these attributes function just like they do in HTML. Using these in
SVGs allows you to easily target an element via CSS or JavaScript, or to reuse
an element via the use element.
4. Elements such as <circle>, <rect>, <path>, and <text> are defined by the SVG
namespace. These are our basic building-blocks. Although you can make
extremely complex images with SVG, they are mostly created with just a
dozen or so of these basic elements. You can see a complete list of SVG
elements here.
5. Many SVG attributes, such as fill and stroke, can be changed in your CSS.
Play around with the code above and try to get a feel for what’s happening. What
happens when you change the viewBox dimensions? Or the attributes of an
element?
Embedding SVGs
There are two main approaches when deciding how to actually place the SVG in
your document: linked, and inline.
Linking SVGs works basically the same way as linking any other image. You can use
an HTML image element such as <img>, or link it in your CSS using background-
image: url(./my-image.svg). They will still scale properly, but the contents of the
SVG will not be accessible from the webpage.
The alternative is to inline your SVGs by pasting their contents directly into your
webpage’s code, rather than linking to it as an image. It will still render correctly,
but the SVG’s properties will be visible to your code, which will allow you to alter
the image dynamically via CSS or JavaScript.
Inlining SVGs allows you to unlock their full potential, but it also comes with some
serious drawbacks: it makes your code harder to read, makes your page less
cacheable, and if it’s a large SVG it might delay the rest of your HTML from loading.
Some of the drawbacks of inlining SVG code can be avoided once you’ve learned a
front-end JavaScript framework like React, or a build-tool like webpack. We aren’t
quite ready to get into those yet, so just keep that in the back of your mind.
For now, just do whichever works best for your use-case. Linking is generally
cleaner and simpler, so prefer that unless you need to tweak the SVG code
alongside your HTML.
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it

HTML and CSS Page 8


This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
1. There are lots of great free SVG icon libraries. A few worth checking out:
Material icons, Feather icons, and The Noun Project.
2. If you want a deep-dive into the details of SVGs and their elements, the MDN
tutorial is a great place to start.
3. If you want to get started making your own SVGs, you’ll want some sort of
visual editor.
a. This is a great little SVG editor for learning how the SVG markup works. It
not only shows the XML, but also lets you see the “commands” you’re
using to generate the SVG. This website isn’t really designed for making
complex graphics, though.
b. For that, an excellent option is Inkscape, which is not only free but open
source!
c. And if you’re really invested in creating your own SVGs, you might want
to check out some of the powerful paid options out there, such as
Affinity Designer.
4. If you want to use SVGs to generate images programmatically, there are at
least two major, modern libraries for that: snap.svg and SVG.js.
5. For data visualization, d3 has been the standard for many, many years.
6. If you’re interested in some of the more advanced things you can do with
SVGs, check out this video on SVG animation, and this article on SVG Filters,
and Why They’re Awesome!

Knowledge Check
• What is the xmlns attribute?
• What are some situations where you wouldn’t want to use SVG?
• What are the benefits of “inlining” your SVGs? What are the drawbacks?

HTML and CSS Page 9


Tables
Thursday, July 7, 2022 2:18 AM

Introduction
HTML Tables allow you to create two-dimensional tables made of rows and
columns. In this lesson, you will learn everything you need to know about HTML
Tables.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Create advanced HTML tables.

HTML Tables
Some data just really needs to be displayed in a table. HTML tables might be less
commonly used than buttons, links, lists and everything else you’ve learned so far,
but there are some cases where they’re the perfect tool. Some of the more
advanced features can get a little tricky to set up correctly but getting started with
tables is pretty easy. You create a table with <table></table> tags and then put the
elements for rows, columns, headers, or anything else that’s possible inside those
table elements.

Assignment
1. Read these Tables Basics and Tables Advanced tutorials from MDN. They
should teach you all the syntax behind HTML tables. It’s pretty
straightforward. Make sure to code along!
2. Do this Tables Assessment from MDN. It’s good to put your newly learned
skills to practice!

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
• Pencil & Paper published a great article about things you can achieve with
tables if you dare to spend some time giving them some love. They suggest
some good habits on how you should format your data which is pretty simple
and makes a huge difference. These are not a list of must dos to a table, but
ideas worth keeping in mind for the next time a table is bothering you with
how it looks.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
HTML and CSS Page 10
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is a table?
• Why is it a bad idea to use HTML Tables for page layout?
• What are caption elements useful for?
• What is the scope attribute?

HTML and CSS Page 11


CSS Concepts
Thursday, July 7, 2022 2:22 AM

Here we'll dive into CSS concepts that'll make your web projects shine.

HTML and CSS Page 12


Default Styles
Thursday, July 7, 2022 2:22 AM

Introduction
Browsers, by default, inject a little bit of style into your web projects. You may not
have thought about this specifically, but you have definitely encountered it.
Learning Outcomes
• You’ll learn about default browser styles
• You’ll learn how to use a CSS reset to remove, or change those default styles.

Default Styles
An h1, for instance, is bigger and bolder than regular text. Links (a) are blue and
underlined. Lists (ul and ol) both have a bunch of padding surrounding them.
Browsers accomplish this by inserting a little bit of CSS into every webpage. (Here
is Chrome’s default HTML stylesheet)
The problem with this is that there is no guarantee that different browsers will
style everything the same. In general, inconsistencies are going to be pretty minor,
but they DO exist. Also, in many cases as a developer you’re going to end up
undoing or redoing all of this default styling to make your site look exactly how you
envision it.
To counter this, many developers start their projects with a “CSS Reset”; a file that
undoes browser defaults, so that every element behaves the same in every
browser.
You don’t have to use a CSS reset. In many cases you’re going to end up undoing,
or redoing a lot of the styles that a reset will provide for you. You can decide
whether or not you want to use one on a regular basis, but it’s worth taking the
time to dig through a couple now. Understanding exactly how they’re doing what
they’re doing is a useful exercise!
Assignment
1. The Meyer Reset is almost certainly the most popular. It’s very simple and
basically removes every default style.
2. Normalize.css is another popular one. It’s a little different in that it doesn’t
remove all the default styles, but tweaks them slightly to ensure that browsers
are consistent.
3. Reboot, Resets and Reasoning is a CSS tricks article that goes a little more in
depth, and mentions a few other popular resets.
4. Maybe more trivial than useful, this Browser Default Styles site is fun to play
with.

HTML and CSS Page 13


Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something
• A Look at CSS Resets in 2018 is another article that talks about the various
resets out there.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Why would you want to use a CSS reset?

HTML and CSS Page 14


CSS Units
Thursday, July 7, 2022 2:22 AM

Introduction
There are many different units that you can use to define sizes in CSS. This lesson
will introduce the most important to you, and show you where to learn about the
rest of them.
Learning Outcomes
• You’ll learn the difference between relative and absolute units
• You’ll learn when it’s appropriate to use the different units.

Absolute Units
Absolute units are those that are always the same in any context. px is an absolute
unit because the size of a pixel doesn’t change relative to anything else on the
page. In fact, px is the only absolute unit you should be using for web projects. The
rest of them make more sense in a print setting because they are related to
physical units such as in (inch) and cm (centimeter).
Relative Units
Relative units are units that can change based on their context. There are several
of them that you are likely to encounter and want to use.
em and rem
em and rem both refer to a font size, though they are often used to define other
sizes in CSS. You’ll see both of them often so we’re going to explain both, but as a
rule-of-thumb, prefer rem.
1em is the font-size of an element (or the element’s parent if you’re using it to set
font-size). So, for example, if an element’s font-size is 16px, then setting its width
to 4em would make its width 64px (16 * 4 == 64).
1rem is the font-size of the root element (either :root or html). The math works
the same with rem as it did with em, but without the added complexity of keeping
track of the parent’s font size. Relying on em could mean that a particular size
could change if the context changes, which is very likely not the behavior you
want.
Using a relative size like rem to define font sizes across your website is
recommended. Many browsers allow users to change the base font-size to
increase readability. If at all possible, it is advisable to respect a user’s wishes
regarding font size. You’ll learn more about this from the reading assignments.
Viewport Units
The units vh and vw relate to the size of the viewport. Specifically, 1vh is equal to
HTML and CSS Page 15
The units vh and vw relate to the size of the viewport. Specifically, 1vh is equal to
1% of the viewport height and 1vw is equal to 1% of the viewport width. These can
be useful any time you want something to be sized relative to the viewport,
examples including full-height heroes, full-screen app-like interfaces.
Assignment
1. CSS values and units covers all the available units.
2. The article CSS units goes in depth on how and when you might want to use
em, rem, or px.
3. Fun with Viewport Units demonstrates some interesting things you can do
with vh and vw.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
• It looks like this lesson doesn’t have any additional resources yet. Help us
expand this section by contributing to our curriculum.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Why would you want to use em or rem for font-size instead of px?
• What are some instances where you might want to use vh and vw?
• What are some instances

HTML and CSS Page 16


More Text Styles
Thursday, July 7, 2022 2:23 AM

Introduction
You’ve already done a bit of text-manipulation in our Foundations lessons. This
lesson will cover a few more useful CSS properties that can be used when working
with text.
Learning Outcomes
• You’ll learn how to use custom fonts on your web projects.
• You’ll learn some more text-related CSS properties.
Fonts
In our Foundations lesson, we covered changing the font-family of an element, but
there is some nuance and detail that we left out at the time.
The System Font Stack
If you use the font-family property to change to a font like impact or Times New
Roman, and those fonts do not happen to be installed on your user’s computer,
then a fallback font will be displayed. If you have not defined a fallback, then the
default HTML font will be used, which is often somewhat ugly. For this reason, it’s
common to see somewhat long stacks of fonts listed on projects.
One popular stack is this ‘system font’ stack. Source: CSS Tricks
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

The point of this somewhat ridiculous string of font-families is to try using the
default font of the system’s user interface. It will go through each of those fonts
until it finds one that is installed on the system, and then use that. Using a stack
like this often produces pleasing results, especially if you’re going for a somewhat
‘neutral’ font style.
Online Font Libraries
One popular and easy method to get fonts that are not installed on a user’s
computer is to use an online font library like Google Fonts, Font Library or the
premium, but non-free Adobe Fonts.
To use a font from one of these libraries, go to the website, select a font and then
copy a snippet from the website to import that font from their server into your

HTML and CSS Page 17


copy a snippet from the website to import that font from their server into your
website. You’ll be given either a <link> tag to put in your HTML like so….
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap"
rel="stylesheet">

… or an @import tag that can be dropped at the top of a CSS file.


@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');

Either method will import that font and make it available for you to use in your
CSS:
body {
font-family: 'Roboto', sans-serif;
}

Keep in mind that it’s important to add a fallback font. If you’re linking to an
external API, you have no guarantee that the URL won’t change, or that the
external API won’t go down at some point. Having a reasonable fallback means
that if something goes wrong, at least your site won’t look completely broken.
Downloaded Fonts
It is also possible to use a font that you have downloaded from the web. In your
CSS file, you import and define a custom font using the @font-face rule, and then
use as you would any other font-family. There are multiple types of font file
formats and you can read more in depth about them on fileinfo.com’s page on
Font File Formats. Please take care when choosing a font file format however,
because some are not universally supported by browsers. A list of browsers and
the font formats they support can be found on W3 Schools’ page on CSS Web
Fonts.
@font-face {
font-family: my-cool-font;
src: url(../fonts/the-font-file.woff);
}

h1 {
font-family: my-cool-font, sans-serif;
}

This method may be more reliable than relying on a third-party font API, but it is

HTML and CSS Page 18


This method may be more reliable than relying on a third-party font API, but it is
always wise to include a fallback.
Text Styles
You learned the basics of manipulating fonts in our Foundations lessons, but there
is quite a bit more that you can do with CSS when it comes to manipulating text
styles. These rules are all relatively simple and self-explanatory. You can refer to
the docs for any questions you might have.
font-style
Typically used to make a font italic. You learned about the HTML <em> tag, which
uses an italic font, but <em> also signifies that the text it wraps is significant or
should be emphasized in some way. A good rule of thumb to follow is that if you
just want text to be italic (or bold, underlined, highlighted, etc.), use a CSS
property. Otherwise, if text should have some sort of semantic emphasis, use the
correct HTML element.
For example, if you want all your header text to be italic you should use font-style
to accomplish this. If you want some text in the middle of a sentence to appear
italic in order to emphasize that text, it is appropriate to use an em element. The
MDN doc on the Emphasis Element puts stress on our point above.
We should use font-style: italic; if italics is required for styling purposes.
h1 {
font-style: italic;
}

We should use the em element if italics is required for emphasis.


<p>I <em>never</em> said he stole your money</p>
<p>I never said <em>he</em> stole your money</p>
<p>I never said he stole <em>your</em> money</p>

letter-spacing
Letter spacing does what you would expect…. it changes the space between letters
in a word. This can be useful for adjusting custom fonts that you feel have too
much or too little space. It can also be aesthetically pleasing in some cases, like
headers.
Obviously, use this sparingly and with care. Do not make your site hard to read!
line-height
Line height adjusts the space between lines in wrapped text. Adding a little line-
height can increase readability.
text-transform

HTML and CSS Page 19


text-transform
Text transform simply changes the case of the given text. You can use this, for
example, to force your heading tags to be all uppercase, or to capitalize every
word.
Usage is simple, and can be seen in the clear example on these MDN web docs.
text-shadow
As you might expect, text-shadow adds a shadow around the text in the selected
element. This one is best used sparingly, but can be used to great effect in
headings or other presentational text.
The examples on the MDN reference page for text-shadow show how to use it.
ellipsis
This one isn’t a single property, but it’s a useful trick to keep in your toolbox. With
the text-overflow property, you can truncate overflowing text with an ellipsis.
Making an overflow happen, however, requires the use of a couple other
properties because the default behavior of text simply printing outside its
container isn’t technically considered an overflow (that’s confusing, we know.
Sorry.)
The full snippet is:
.overflowing {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

You can see more detail and an example in this CSS Tricks Article. (Be ready to go
look that article up every time you want to use this.)
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What are the 2 ways to add fonts that are not installed on a user’s computer?
• What is the ‘system font stack’ and why would you want to use it?
• Which property would you use to increase or decrease the space between
letters in a word?
• Which property would you use to increase or decrease the space between
HTML and CSS Page 20
• Which property would you use to increase or decrease the space between
lines in a paragraph?

HTML and CSS Page 21


More CSS Properties
Thursday, July 7, 2022 2:23 AM

Introduction
By now, you probably have a strong grasp of the important foundational concepts
of CSS, but there is a lot more that you can do with CSS to make some truly
spectacular looking websites. It’s time to cover those useful little CSS features you
can use to add some shine to your projects.
There are a lot of CSS properties. A Recent CSS Tricks Article says there are
hundreds. Luckily, you don’t have to memorize them all: the amount of properties
you’re actually going to use on a daily basis is much smaller. This lesson is going to
cover most of the items you’ll end up using on a regular basis. The format of this
lesson is a little different since it’s essentially just a list of CSS properties. We’ll give
a little description of the property and then link you to some documentation
where you can see all the available options.
Learning Outcomes
• You’ll learn about a lot of useful CSS properties!
Background
You’ve likely already experimented with setting background colors on things, but
the background property can do quite a bit more. The background property is
actually a shorthand for 8 different background-related properties, all of which you
can read about in the linked docs. Beyond changing background-colors, you can
also specify background images, change the position and size of background
images, and change how background images repeat or tile if they are too small to
fill their container. It is also possible to have multiple background layers.
One thing to note is that it is possible to use these properties individually, and in
some cases it might be easier and more clear to do that than defaulting to the
shorthand. This is in contrast to some other shorthand properties where it is
almost always preferable to default to using the shorthand (flex, margin, padding
etc.)
There’s a lot of information in the docs on this shorthand and all the associated
properties. As we’ve mentioned before, you do NOT need to memorize the exact
order and syntax of each property. It’s enough to know that they exist and have a
general idea of what they do.
One more note, the Formal Syntax section here is crazy. Don’t let it deter you. The
basic syntax is somewhat hard to define because many of the properties that make
up the shorthand are optional, or can come in different places in the definition.
Read the MDN docs on background.
Borders
HTML and CSS Page 22
Borders
At this point, you’ve probably already encountered border and border-radius. The
border property is another shorthand, but it is much less complicated than the
background shorthand. For borders, basically you just need to define a size, style
and color.
border-radius is the property that is used to create rounded corners on things. As
you’ll see in the docs, it’s possible to get fancy and define different radii for each
corner of an element, but this is rarely useful. Store that information in the
category of “things I’ll look up if I ever need it”.
Read the MDN docs for border and border-radius.
box-shadow
As you might expect from the property name, box-shadow adds a shadow effect
around an element. This is useful to create a sense of depth on your page and to
add subtle separation between elements.
In usage it’s pretty simple, but keep in mind that it’s best used sparingly, and
subtly. Prefer lighter, barely visible shadows to darker or brighter colors.
Read the box-shadow docs.
Overflow
It is possible, using overflow, to define what happens to an element when its
content is too big to fit. The most common usage is likely to add scrollbars to an
element inside a webpage, for example a card style element with scrollable
content.
Check out the overflow docs
Opacity
Opacity is another easy one that can be very useful in some circumstances.
Check out opacity for a definition and some examples.
Additional Resources
Throughout this lesson we have linked primarily to the MDN docs for each
property… however there are many useful reference sites across the web that can
be useful and that may show up when searching these items.
• CSS Tricks has some really great content. Some of it feels less formal and
official than the MDN docs, but that means they can be easier to digest.
Sometimes their examples can be more useful. For example, check out their
pages on the background shorthand, or overflow.
• W3 Schools is another fine resource. We (the Odin authors) tend to prefer
MDN, but there is nothing wrong with W3.
Knowledge Check

HTML and CSS Page 23


This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Which property would you use to make an element transparent?
• Which property would you use to make a background image tile?
• Which property would you use to add scrollbars to an element?
• Which property would you use to add a shadow behind an element?
• Which property would you use to create rounded corners on an element?
• How would you use border-radius to make a circular element?

HTML and CSS Page 24


Advanced Selectors
Thursday, July 7, 2022 2:23 AM

Introduction
By now you should be comfortable with basic CSS selectors and have no trouble
grabbing things by their type, class or ID. But to be a real CSS surgeon, sometimes
you need more specialized tools. In this lesson we’ll look at advanced CSS selectors
and show you how to target elements in a more specific and finely grained way.
These selectors can be especially useful when you can’t (or don’t want to) change
your HTML markup.
There are a lot of advanced selectors, so going through every single one is outside
the scope of this lesson. However, we’ll go through some of the most useful and
common ones, as well as arm you with the concepts and vocabulary to learn more
on your own.
As always feel free to open up your code editor and run your own experiments
with these selectors - practice makes perfect!
Learning Outcomes
• Understand how to use parent and sibling selectors
• Recognize the difference between pseudo classes and pseudo elements
• Learn about some of the most useful and common pseudo elements and
pseudo classes
• Learn about the different ways to select an attribute or its parts

Parent and Sibling Combinators


Let’s have a look at some more ways we can access different elements without
referring to their classes. Here are three new selectors to do just that.
• > - the child combinator
• + - the adjacent sibling combinator
• ~ - the general sibling combinator
We’ll tackle some practical examples using this sample markup.
<main class="parent">
<div class="child group1">
<div class="grand-child group1"></div>
</div>
<div class="child group2">
<div class="grand-child group2"></div>
</div>
<div class="child group3">
<div class="grand-child group3"></div>
HTML and CSS Page 25
<div class="grand-child group3"></div>
</div>
</main>

By now, you should be pretty comfortable writing rules using the descendant
combinator you learned about in foundations. For instance, if we wanted to select
all the child and grand-child divs inside of main, we could write:
main div {
/* Our cool CSS */
}

But what if we wanted to be more specific and select only the child or grand-child
divs? That’s where the child combinator > comes in handy. Unlike the descendant
combinator, it will only select direct children.
/* This rule will only select divs with a class of child */
main > div {
/* Our cool CSS */
}

/* This rule will only select divs with a class of grand-child */


main > div > div {
/* More cool CSS */
}

Phrased another way, the child selector will select an element that is one level of
indentation down. In order to select an element that is adjacent to our target, or
on the same level of indentation, we can use the adjacent sibling combinator +.
/* This rule will only select the div with the class child group2 */
.group1 + div {
/* Our cool CSS */
}

/* This rule will only select the div with the class child group3 */
.group1 + div + div {
/* More cool CSS */
}

Finally, if we want to select all of an element’s siblings and not just the first one,
we can use the general sibling combinator ~.
/* This rule will select all of .group1's siblings - in this case the 2nd and 3rd .child

HTML and CSS Page 26


/* This rule will select all of .group1's siblings - in this case the 2nd and 3rd .child
divs */
.group1 ~ div {
/* Our cool CSS */
}

Just like the descendant combinator, these selectors don’t have any special
specificity rules - their specificity score will just be made up of their component
parts.
Pseudo-selectors
Before diving into pseudo-selectors, a quick note on the difference between
pseudo-elements and pseudo-classes. Pseudo-class selectors are prefixed with a
single colon and are a different way to target elements that already exist in HTML.
Pseudo-elements are prefixed with two colons and are used to target elements
that don’t normally exist in the markup. If that doesn’t make sense straight away,
don’t worry - we’ll explore some examples below.
Pseudo-classes
Pseudo-classes offer us different ways to target elements in our HTML. There are
quite a lot of them, and they come in a couple of different flavors. Some are based
on their position or structure within the HTML. Others are based on the state of a
particular element, or how the user is currently interacting with it. There are too
many to cover in detail here but we’ll have a look at some of the most useful ones.
Pseudo-classes share the same specificity as regular classes (0, 0, 1, 0). Just like
regular classes, most can be chained together.
Note: The (0,0,1,0) above is the notation for calculating specificity. To find out
more about how it works, glance over the “Calculating CSS Specificity Value”
section from this article on CSS Specificity.
As always don’t forget to check the docs to see a complete picture of what’s
available.
Dynamic and User Action Pseudo-classes
These types of useful pseudo-classes can make your page feel much more dynamic
and interactive.
:focus applies to an element that is currently selected by the user either through
selecting it with their cursor or using their keyboard.
:hover will affect anything under the user’s mouse pointer. It can be used to give
extra oomph to buttons and links to highlight that they’re interactable, or to
trigger a drop-down menu.
:active applies to elements that are currently being clicked, and is especially useful
for giving your user feedback that their action had an effect. This is a great one to
HTML and CSS Page 27
for giving your user feedback that their action had an effect. This is a great one to
give your buttons and other interactive elements more ‘tactile’ feedback.
Have you ever wondered why links are blue but turn purple when clicked in
unstyled HTML? It’s because browsers implement that styling by default. To
implement your own custom styling for links, take advantage of the :link
and :visited pseudo-classes. A simplified version of default browser styling might
look something like this:
/* This rule will apply to all links */
a{
text-decoration: underline;
}

/* This will apply to unvisited links */


a:link {
color: blue;
}

/* And you guessed it, this applies to all links the user has clicked on */
a:visited {
color: purple;
}

Structural Pseudo-classes
Structural pseudo-classes are a powerful way to select elements based on their
position within the DOM.
:root is a special class that represents the very top level of your document - the
one element that has no parents. Generally when working with the web, this is
equivalent to the html element, but there are a few subtle differences.
:root is generally the place where you will place your ‘global’ CSS rules that you
want available everywhere - such as your custom properties and CSS variables, or
rules such as box-sizing: border-box;.
:first-child and :last-child will match elements that are the first or last sibling.
Similarly, :empty will match elements that have no children at all, and :only-child
will match elements that don’t have any siblings.
For a more dynamic approach we can use :nth-child. This is a flexible pseudo-class
with a few different uses.
.myList:nth-child(5) {/* Selects the 5th element with class myList */}

.myList:nth-child(3n) { /* Selects every 3rd element with class myList */}

HTML and CSS Page 28


.myList:nth-child(3n + 3) { /* Selects every 3rd element with class myList,
beginning with the 3rd */}

.myList:nth-child(even) {/* Selects every even element with class myList */}

Pseudo-elements
While pseudo-classes give us an alternative way to interact with our HTML
elements based on their state or structure, pseudo-elements are more abstract.
They allow us to affect parts of our HTML that aren’t elements at all. These special
elements share the same specificity as regular elements (0, 0, 0, 1). There are a
number of useful pseudo-elements that can be utilized in any number of creative
ways.
::marker allows you to customize the styling of your <li> elements’ bullets or
numbers.
::first-letter and ::first-line allow you to (you guessed it!) give special styling to the
first letter or line of some text.
::selection allows you to change the highlighting when a user selects text on the
page.
::before and ::after allow us to add extra elements onto the page with CSS, instead
of HTML. Using it to decorate text in various ways is one common use case.
<style>
.emojify::before {
content: ' ';
}

.emojify::after {
content: ' ';
}
</style>

<body>
<div> Let's <span class="emojify">emojify</span>this span!</div>
</body>

Using these pseudo-elements this way would give us this result:


Let’s emojify this span!
There are lots more! Have a quick browse through the pseudo-element docs to see
a complete list of what’s possible.
HTML and CSS Page 29
a complete list of what’s possible.
Attribute Selectors
The last tool we’re going to add to the box is attribute selectors. Recall that an
attribute is simply anything in the opening tag of an HTML element - such as
src='picture.jpg' or href="www.theodinproject.com".
Since we write our own values for attributes, we need a slightly more flexible
system to be able to target specific values.
Attribute selectors have the same specificity as classes and pseudo-classes (0, 0, 1,
0).
Let’s look at some examples for basic usage.
• [attribute] - This general selector will select anything where the given
attribute exists. Its value doesn’t matter.
• selector[attribute] - Optionally we can combine our attribute selectors with
other types of selectors, such as class or element selectors.
• [attribute="value"] - To get really specific, we can use = to match a specific
attribute with a specific value.
[src] {
/* This will target any element that has a src attribute. */
}

img[src] {
/* This will only target img elements that have a src attribute. */
}

img[src="puppy.jpg"] {
/* This will target img elements with a src attribute that is exactly "puppy.jpg" */
}

Sometimes we need to be more general in how we access these attributes. For


example, perhaps we’re only interested in img elements where the src attribute’s
value ends in .jpg. For cases like this we have some attribute selectors that allow us
to match a part of the attribute’s value. If you’ve ever come across regular
expressions before, these attributes use a similar syntax.
• [attribute^="value"] - ^= Will match strings from the start.
• [attribute$="value"] - $= Will match strings from the end.
• [attribute*="value"] - *= The wildcard selector will match anywhere inside the
string.
[class^='aus'] {
/* Classes are attributes too!
This will target any class that begins with 'aus':

HTML and CSS Page 30


This will target any class that begins with 'aus':
class='austria'
class='australia'
*/
}

[src$='.jpg'] {
/* This will target any src attribute that ends in '.jpg':
src='puppy.jpg'
src='kitten.jpg'
*/
}

[for*='ill'] {
/* This will target any for attribute that has 'ill' anywhere inside it:
for="bill"
for="jill"
for="silly"
for="ill"
*/
}

To see what other things you can achieve with attribute selectors, such as
searching case insensitivity, or sub-strings separated by hyphens, have a browse
through the MDN docs.
Assignment
1. Complete CSS Diner. You should be familiar with most of the content in the
first couple of exercises, but practice and review never hurt! Don’t forget to
read the examples and explanations on the right.
2. Read Shay Howe’s article on Complex Selectors. This covers most of the
content of this lesson in a bit more detail.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
• Kevin Powell has a variety of videos on several of these topics if you’d like a
deeper dive.
• The CSS Tricks Almanac has a great reference for all pseudo-elements and
selectors. It includes examples, extra resources and browser support charts.
• W3 Schools also has a solid, more concise reference list. Includes an
interactive selector tool if you’d like to play around with some hands on
examples.
HTML and CSS Page 31
examples.
• The Free Code Camp Selector Cheat Sheet has a solid summary of some of the
most common selectors.
• A nice concise article on the differences between pseudo-classes and pseudo-
elements. Also provides a solid summary of the different kinds of selectors.
• Smashing Magazine on Taming Advanced CSS Selectors
• CSS Tricks on Attribute Selectors will help if you need a deeper look at
attributes.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is the difference between the child combinator and the descendant
combinator?
• How does the syntax of pseudo-classes and pseudo-elements differ?
• Do pseudo-classes exist somewhere in HTML? Do pseudo-elements?
• Name two ways you could select every second child of an element, starting
with the first.
• What is the difference between div:first-child and div:last-child? What will
each select?
• What selector would you use to style a button a user is currently hovering
over? How about one that is currently being clicked on?
• How could you select all input elements with a type of text?
• How could you select all classes that begin with thunder?

HTML and CSS Page 32


Positioning
Thursday, July 7, 2022 2:23 AM

Positioning
By now you have had quite a bit of practice moving elements around the screen using things
like margin, padding, and flexbox. These techniques have all relied on CSS’s default
“positioning-mode”. This default positioning-mode is intuitive, and you’ll continue using it for
almost all of your layout needs. However, there are other methods at your disposal that can be
very useful in some situations.
Learning Outcomes
• You’ll learn how to use absolute positioning.
• You’ll learn how to use fixed positioning.
• You’ll learn how to use sticky positioning.
• You’ll know the difference between each property and how to combine them.

Static and Relative Positioning


The default positioning mode that you’ve gotten used to is position: static. The
difference between static and relative is fairly simple. Static is the default position of every
element, and properties top, right, bottom, and left do not affect the position of the
element. Relative on the other hand is pretty much the same as static, but properties top,
ri....(etc.) displace the element relative to its normal position in the flow of the
document.
Absolute Positioning
position: absolute allows you to position something at an exact point on the screen
without disturbing the other elements around it. More specifically, using absolute positioning
on an element will remove that element from the normal document flow while being
positioned relative to an ancestor element. To put it in simple terms: elements that are
removed from the normal flow of the document don’t affect other elements and are also not
affected by other elements. Using absolute positioning allows you to position elements
anywhere on the screen using top, right, bottom, and left properties. This property is
really useful when you want to position something at an exact point on the screen, without
disturbing any of the other elements. A couple of good use cases for absolute positioning are:
• modals
• image with a caption on it
• icons on top of other elements
In the following example, we are using absolute positioning to display text over an image.
Disclaimer: absolute positioning has very specific use cases and if possible, using flexbox or grid
should be prioritized. Absolute positioning shouldn’t be used to do entire page layouts.
Fixed Positioning
Fixed elements are also removed from the normal flow of the document and are positioned
relative to the viewport. You basically use top, right, bottom, and left properties to
position it, and it will stay there as the user scrolls. This is especially useful for things like
navigation bars and floating chat buttons. We have one of those at the very bottom right corner
of the screen!

HTML and CSS Page 33


of the screen!
Sticky Positioning
Sticky elements will act like normal elements until you scroll past them, then they start
behaving like fixed elements. They are also not taken out of the normal flow of the document.
It might sound confusing, but checking out the behavior of this example might clear things up
for you. It’s useful for things like section-headings. Remember being able to still see what
category you’re looking at while scrolling through a shop? This is how it’s done!
Assignment
1. This video is fast-paced but provides a good visual representation of different positioning
behaviors. Go ahead and watch it.
2.

3. This MDN article covers all of the conceptual details about positioning.
4. This CSS Tricks page should give you a different insight on the topic. You should read it as
well.
5. Finally, this article discusses the difference between fixed and sticky positioning, it’s a
great read to understand the difference better.

Knowledge Check
This section contains questions for you to check your understanding of this lesson. If you’re
having trouble answering the questions below on your own, review the material above to find
the answer.
• What is the difference between static and relative positioning?
• What is absolute positioning useful for?
• What is the difference between fixed and sticky positioning?

Additional Resources
This section contains helpful links to related content. It isn’t required, so consider it
supplemental.
• It looks like this lesson doesn’t have any additional resources yet. Help us expand this
section by contributing to our curriculum.

HTML and CSS Page 34


CSS Functions
Thursday, July 7, 2022 2:23 AM

Introduction
You may have noticed that some property values you’ve worked with in CSS have a
slightly different syntax. When the value is a word followed by a pair of
parentheses () containing information between them - as in background-color:
rgb(0, 0, 0) - you’re using CSS functions.
In this lesson, we’ll cover the basics of what a function is and some common ways
they’re used in CSS.
Learning outcomes
• Recognize the basic parts of a CSS function
• Learn about the calc(), min(), max(), and clamp() functions and how to use
each one
What is a function and how are they used in CSS?
As in other programming languages, functions are reusable pieces of code which
perform specific tasks. Functions are passed “arguments” between parentheses,
each of which is used by the function in a specific way. Some common examples
are:
color: rgb(0, 42, 255);
background: linear-gradient(90deg, blue, red);

Here, the value of color is the function rgb(), which accepts arguments in the form
of numbers. It processes those numbers to calculate the rgb color corresponding
to the three values given. Similarly, the background property has a value of linear-
gradient(90deg, blue, red). linear-gradient generates a gradient image using the
parameters it’s been given. It needs at least two color arguments: colors to
transition between. Additionally, you can set the angle of direction of the gradient
line (like we’ve done in the example), add more color values, etc.
Unlike other programming languages you’ll use in TOP, CSS does not allow us to
create our own functions. Instead, the language comes bundled with a list of
premade functions that will help you solve the most common styling problems.
Besides defining colors, there are several CSS functions that are useful when
designing a website’s layout and sizing. These become important when thinking
about responsive design.
Let’s go over a few of these functions: calc(), min(), max(), and clamp().
calc()
HTML and CSS Page 35
calc()
The most powerful use cases for calc include:
• Mixing units
• The ability to nest calc( calc () - calc () )
Take a look at how calc() is being used here:
:root {
--header: 3rem;
--footer: 40px;
--main: calc(100vh - calc(var(--header) + var(--footer)));
}

• --header, --footer, and --main are all examples of CSS variables. You will be
learning about these in the next lesson.
Setting main to equal the outcome of: 100vh - (3rem + 40px). To put it another
way: main = 100vh - (header + footer). calc() is handling the math for us even
though we are mixing vh, rem and px units. Combined with CSS variables, calc() can
save us from the headache of repeating CSS rules.
You should be able to grasp how calc() is used in the above CodePen embed. We
encourage you to play around with different units and sizes of the elements to see
what results you get before moving on.
Note: The above is just an example of how calc() can affect a layout, but keep in
mind that calc() is likely not the best way to go about it. We will talk more about
layouts in future lessons.
min()
min() does an excellent job of helping us create responsive websites. Take a look at
this example:
#iconHolder {
width: min(150px, 100%);
height: min(150px, 100%);
box-sizing: border-box;
border: 6px solid blue;
}

Focus on this line width: min(150px, 100%); we can make several observations: If
there are 150px available to the image, it will take up all 150px. If there are not
150px available, the image will switch to 100% of the parent’s width. In the first
case min() selects 150px, since 150px is the smaller (the minimum) between 150px
and 100% of the parent’s width; in the second, it chooses 100%. min() behaves as a
boundary for the maximum allowed value, which in this example is 150px.

HTML and CSS Page 36


boundary for the maximum allowed value, which in this example is 150px.
You are able to do basic math inside a min ( ) => for example: width: min(80ch,
100vw - 2rem);
max()
Max works the same way as min, only in reverse. It will select the largest possible
value from within the parentheses. You can think of max() as ensuring a minimum
allowed value for a property.
Consider the following property of a given element:
width: max(100px, 4em, 50%);

From this list of given sizes, max() will select the largest one. As long as 4em or 50%
result in lengths longer than 100px, max() will select (the bigger) one of them. If
they are smaller than 100px (maybe as a cause of user’s font size preferences, or
their browser’s window size or zoom level), then 100px will win out as the largest.
You can think of 100px in this example as a guard value: width here won’t ever be
set to less than 100px.
The max function is most useful when the viewing window is either exceptionally
small, or the user increases the content size by using the browser’s zoom feature.
You may not find a lot of use for max at first, but it is good tool to be aware of for
projects where accessibility is important.
clamp()
clamp() is a great way to make elements fluid and responsive. clamp() takes 3
values:
h1 {
font-size: clamp(320px, 80vw, 60rem);
}

1. the smallest value (320px)


2. the ideal value (80vw)
3. the largest value (60rem)
The clamp() CSS function uses these values to set the smallest value, ideal value
and largest value. In the above example, this would mean the smallest acceptable
font-size would be 320px and the largest would be 60rem. The ideal font-size
would be 80vw.
Assignment
1. Take a look at the complete list of all CSS functions and how they are used so
you have an idea of what is possible.
2. Read this great article for a more in-depth look min, max, and clamp in action,
with animated examples.

HTML and CSS Page 37


with animated examples.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• This article contains some specific use cases for all four functions, including
color palette generation, background size responsiveness, and accessibility
settings.

Knowledge Check
• What are the four CSS math functions we covered above?
• How do we use CSS math functions in our CSS?
• How can CSS functions help make websites and applications more responsive?

HTML and CSS Page 38


Custom Properties
Thursday, July 7, 2022 2:23 AM

Introduction
Custom properties (also known as CSS variables) can be a really useful and
powerful tool when writing our CSS files. In short, they allow us to reference a CSS
value however many times we want throughout a file. By using custom properties,
instead of having to update every single instance of a specific value (“This shade of
red is too light, let’s change the shade on all seven of these selectors”), we only
need to update a single instance: the custom property itself. Not only that, but
custom properties can help us keep colors consistent throughout a project,
something that will be really helpful as projects get larger.
We can even redefine custom properties under different contexts, which is
incredibly useful for creating themes, such as the dark and light themes you see on
many websites these days.
Learning Outcomes
• You’ll learn how to declare a custom property
• You’ll learn how to access a custom property in a rule declaration
Using Custom Properties
The syntax for declaring and accessing a custom property is really simple and not
too different from how we write normal rule declarations:
.error-modal {
--color-error-text: red;
--modal-border: 1px solid black;
--modal-font-size: calc(2rem + 5vw);

color: var(--color-error-text);
border: var(--modal-border);
font-size: var(--modal-font-size);
}

That’s it! First, we declare our custom property with a double hyphen followed by
a case-sensitive, hyphen-separated property name (color-error-text wouldn’t be
the same as Color-Error-Text). The use of single hyphens to separate words is very
important here because spaces are not valid (--color error text would not work).
Then we can store any valid CSS value in our newly declared custom property,
whether it be a simple color value, shorthand values, or even a more complex
function, just to give you a few examples.
HTML and CSS Page 39
function, just to give you a few examples.
When we want to access a custom property, we use the var() function as the value
of a CSS property, and then place our custom property inside of the parenthesis
(including the double hyphen at the beginning).
Fallback Values
The var() function actually accepts two parameters. The first parameter we’ve
already gone over, which is the custom property we want to assign. The second
parameter is an optional fallback value. When a fallback value is provided in
addition to a custom property, the fallback value will be used if the custom
property is invalid or hasn’t been declared yet. We can even pass in another
custom property as a fallback, which can have its own fallback value as well!
.fallback {
--color-text: white;

background-color: var(--undeclared-property, black);


color: var(--undeclared-again, var(--color-text, yellow));
}

In the above example, our background-color property would have a value of black
and our color property would have a value of white. If the --color-text custom
property was invalid or didn’t exist, the fallback to our fallback would take over and
the color property would have a value of yellow.
Scope
In the first example above, you may have noticed that we declared and then
accessed our custom properties within the same declaration block. That’s because
the scope of a custom property is determined by the selector. This scope includes
the selector the custom property was declared for as well as any descendants of
that selector. If you’re familiar with how scope works in JavaScript, this sort of
behavior should feel a little similar.
In the example below, only the element with the cool-paragraph class would get
styled with a red background since it’s a descendant of the element where our
custom property is declared.
<div class='cool-div'>
<p class='cool-paragraph'>Check out my cool, red background!</p>
</div>

<p class='boring-paragraph'>I'm not in scope so I'm not cool.</p>


.cool-div {
--main-bg: red;
}
HTML and CSS Page 40
}

.cool-paragraph {
background-color: var(--main-bg);
}

.boring-paragraph {
background-color: var(--main-bg);
}

The :root Selector


While there may be times where you will want to limit the scope of a custom
property, you may want to be able to use other custom properties on many,
unrelated selectors. One workaround would be declaring the same custom
property on a bunch of selectors, but that defeats one of the purposes of using
custom properties in the first place (the ease of changing multiple instances of a
value at once).
A better solution is declaring those custom properties on the :root selector, which
is essentially the same thing as the html selector except it has a higher specificity.
<p class='cool-paragraph'>Lorem ipsum dolor sit amet.</p>

<p class='exciting-paragraph'>Lorem ipsum dolor sit amet.</p>


:root {
--main-color: red;
}

.cool-paragraph {
color: var(--main-color);
}

.exciting-paragraph {
background-color: var(--main-color);
}

By declaring our custom property on the :root selector in the example above, we
can access it on any other valid selector within our CSS file, since any other
selector would be considered a descendant of the :root selector.
Creating Themes with Custom Properties
Beyond allowing us to access custom properties more globally, the :root selector
gives us one way to add themes to our pages:

HTML and CSS Page 41


First we added a class attribute on our html element so that our page has a default
theme. Next in our CSS we created two scopes for our custom properties on
the :root selector, one for when our html (or root) element has a class of dark and
another for when it has a class of light. Our other selectors then use the values of
any custom properties depending on which class is currently present on our root
element.
Media Queries
Giving users the ability to toggle a theme themselves is great, but there’s another
option for setting a theme that you may have come across on certain sites or
applications: using the user’s theme setting from their operating system or user
agent (like a browser). This can be accomplished with the prefers-color-scheme
media query, which simply checks whether a user has selected a theme preference
on their OS/user agent. As you view the example below, try changing the theme
settings on your OS/user agent to see how the example updates in real time!
We first added custom properties on the :root element outside of the media
query. This gives us a default theme in case a user doesn’t have a preference set
on their OS or user agent, or if a browser doesn’t support the media query. In this
case, we’re using our “light” theme colors as the default. Then we added a prefers-
color-scheme media query for when a user has a dark theme set in their
preferences.
Using the prefers-color-scheme media query can be pretty helpful for users since it
doesn’t require them to manually change the theme to their preferred one. That
said, you need to be aware of a few things when it comes to using this media
query:
1. Only dark and light are valid values for the media query, so you can’t use it to
implement any themes beyond these two basic ones.
2. The light value for the media query is actually for when a user has a light
theme specified or when they have no preference set.
3. It doesn’t allow users to change the theme themselves, which can still be
important in cases where a user might want to use the theme opposite of
their OS/user agent preferred one for whatever reason.

Assignment
1. Read through MDN’s Using CSS custom properties page starting at the
“Inheritance of custom properties” section.
2. Open the inspector on this page to inspect the styles and see how Odin uses
some custom properties.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental for if you need to dive deeper into something.
HTML and CSS Page 42
supplemental for if you need to dive deeper into something.
Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• How would you declare a custom property with a name of text-color?
• How would you access a custom property with a name of background-color?
• Where would you declare a custom property to have its scope be global and
accessible by all other selectors?
• Where would you declare a custom property so that a user’s theme setting
from their OS or browser was taken into account?

HTML and CSS Page 43


Browser Capability
Thursday, July 7, 2022 2:24 AM

Introduction
As you continue your web development journey, it is important to keep in mind
that the end users of your work might be using a variety of browsers: Chrome,
Internet Explorer, Firefox, and Safari to name a few. At the same time, the number
of users using mobile operating systems is growing rapidly, therefore you should
also consider the mobile versions of different browsers.
Learning Outcomes
By the end of this lesson, you should:
• Understand browser compatibility and its history.
• Know how new CSS features make their way into browsers.
• Know how to check for compatibility.

Browser History
The history of modern browsing began back in December of 1990 with the release
of WorldWideWeb browser. It was written by Tim Berners-Lee while working for
the European nuclear research agency known as CERN. It was later renamed to
Nexus, to avoid confusion with the World Wide Web.
Nexus was the first of its kind, and allowed users to view basic style sheets, read
newsgroups, and even had spellcheck! It might not seem like a lot today, but at
that time it was truly groundbreaking.
The release of Nexus was just the beginning though, as in the next decade people
witnessed the first releases of browsers such as Mosaic Browser, which quickly
gained popularity and quickly became the most popular browser on the globe.
From there, the growth of the World Wide Web exploded with the releases of
Opera and Netscape Navigator browsers.
In 1995 the world got introduced to the first version of Internet Explorer, which
became the dominant player in the market. At some point, Internet Explorer was
used by more than 90% of all users. To counter this dominance, Netscape launched
what would become Mozilla Foundation which develops and maintains Firefox.
Soon after that, in 2003, Apple launched Safari, and in 2008, Google launched
Chrome.
You’re most likely familiar with most, if not all these names. There is a lot of
competition among the browsers still to this day, even though Chrome (and
Chromium) is the dominant player in the market.
What is Browser Compatibility

HTML and CSS Page 44


What is Browser Compatibility
Today, it is impossible to imagine the Web without the use of browsers. We have
witnessed a shift from standalone applications to HTML5 and Progressive Web
Apps that allow applications to fully function within a browser. For example,
Microsoft Word and Excel for the longest time could only be executed via a
standalone application. Now, you can utilize those applications through any
browser without the need to install any files.
As companies compete for the market share, different browsers are using different
engines to display information on the web page. For example, Chrome and
Chromium utilize Blink, while Safari uses WebKit.
Because of these differences, your applications may behave differently in the
browser. Due to Chrome dominance, the vast majority of applications are designed
to work smoothly with Chromium, and providing as good of performance in other
browsers is secondary.
For your web development projects to have a broader reach, you must make sure
that you’re testing your web applications against the browsers which are most
likely to be used by the users. Chrome, Safari, Firefox, and other Chromium-based
browsers (Microsoft Edge, Brave, etc.) are more common among regular users. But
you may find you need to support less common ones (Like Internet Explorer) as
well depending on the user base or the company you work for. For Chromium
browsers, if it works in Chrome, it should work in other related browsers as well.
Browser Releases and New CSS Features
W3C World Wide Web Consortium is the authority behind developing web
standards to maximize accessibility and consistency of the web experience. W3C is
also the authority to develop new features in the CSS. This is a closely collaborative
approach with the Web as a community as well as the companies developing the
web browsers.
When the web browsers such as Nexus and Netscape were released, there was no
such organization as W3C to help create more compatibility. Your application could
look and function differently in each browser. Even worse, your application
could’ve been completely unusable. Web developers had to make specific
adjustments for each browser, and not every developer had enough resources to
make that work for everyone.
Today, as the standards around the web evolve and change, and web developers
begin implementing new features in their codebase, the browsers must provide
support for those new features. If the user experience is impacted by the lack of
support in the browsers, the users might find their way to the competitor.
When Is It Safe to Use New Features
As exciting as it is to implement new features, there is a risk of rushing. It would

HTML and CSS Page 45


As exciting as it is to implement new features, there is a risk of rushing. It would
not be a positive experience for your users to find that, for example, your
application used to work well in Firefox, but due to the changes in the codebase it
is now unusable in Firefox but works well in Safari. Thankfully, there is a tool that
can help you prevent this situation.
“Can I Use” is a great resource to help you validate if new features are supported
by the browsers. It provides statistics on which browsers and platforms are
supporting new technologies, and even which versions of the browsers support
specific features.
It is generally good advice to implement new features when they are supported by
the most common browsers. This way you’re less likely to encounter an issue that
a lot of users will face.
Mobile Browsers
Traditionally, the Web was desktop computer first. The application was successful
if it worked well on desktop browsers. But as smartphones became more popular,
each year more and more users are using mobile devices as their main Web-facing
device. In some areas of the world, mobile users are a vast majority.
Mobile devices mostly consist of smartphones and tablets. The most popular
mobile operating systems are Android and Apple’s iOS.
As you’re developing your applications, you must also consider whether your
application should be fully mobile compatible. There are a couple of specifics
about mobile browsers that you need to keep in mind.
1. On iOS and iPadOS, Safari is technically the only supported browser. Yes, you
can install Chrome or Firefox, and you can even set them as a default, but
they are not full browsers. They are still using the Safari rendering engine
(WebKit). Therefore, for your web application to work for the Apple users, you
have to assure support for WebKit and other technologies used in Safari.
Important to remember, that since mobile browsers are not a one to one
comparison to desktop, a project that works in desktop version of Safari might
still need more adjustments to work properly on mobile version of the
browser.
2. Another consideration for mobile browsers is the magnitude of different
screen sizes. It is virtually impossible to have every physical device available to
test, and thankfully browsers provide a way to emulate other devices. The
important piece to remember is that when, for example, you emulate an
iPhone in Chrome, all that you’re emulating is the screen size. Keep in mind
that any specific considerations of the operating system will not be
reproducible. Which means that just because everything functions well in
Chrome when emulating a device, it could behave differently on the actual
phone or tablet device.

HTML and CSS Page 46


phone or tablet device.

Assignment
• Review Can I Use. Are all technologies you have encountered so far supported
by popular browsers?
• Read this article about browsers on iOS.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• Read more about the history of web browsers.
• Take a look at this comprehensive primer on browsers and rendering engines.

Knowledge Check
• What is the most used browser currently?
• What was the original name of the first web browser?
• How are mobile browsers different on Apple mobile operating systems from
Android?

HTML and CSS Page 47


Frameworks and Preprocessors
Thursday, July 7, 2022 2:24 AM

Introduction
At this point, you have written quite a bit of vanilla HTML and CSS, and learned
many design techniques that you will continue to use as you grow as a developer.
Through your experiences, you have no doubt encountered a CSS framework or
two. You may have also learned about preprocessors (aka precompilers). Both of
these types of tools can make writing CSS more streamlined and less tedious.
You should be aware that, at this point in your learning, both frameworks and
preprocessors are options for you, but that neither of them is necessary.
An important reason to know about frameworks and preprocessors is that they are
commonly found in the workplace. In addition, many job requirements include
Bootstrap, SASS, and related technology. So it’s helpful for you to know what these
tools are, and where to look for them once you’ve determined you need to learn
them.
Learning Outcomes
By the end of this lesson, you should:
• Know what a CSS framework is.
• Know some of the available frameworks.
• Know what a preprocessor is.
• Know some of the available preprocessors.

Frameworks Overview
Frameworks like Bootstrap and Tailwind do a lot of the heavy lifting of packaging
up commonly used CSS code for you, even icons and interactions (like menu
dropdowns). They are designed to abstract away the process of coding intuitive,
reusable, and responsive elements. A CSS framework is ultimately just a bundle of
CSS that you can use and access, using the classes defined by the framework. For
example, many frameworks provide a class called .btn that will add all the needed
styles to your buttons, without your having to write any CSS. In general, all you
have to do to use a framework is understand how it expects you to lay out your
site, and which classes it uses to designate its particular batch of styles.
You should be aware that there are quite a few frameworks available to choose
from. Two other frameworks to know about are Bulma and Foundation. There are
many more out there.
Disadvantages of Frameworks

HTML and CSS Page 48


Disadvantages of Frameworks
Frameworks are great for rapidly producing sites with interfaces that end users can
easily interact with. However, once you’ve taken a tour through some of the more
popular frameworks, you’ll start noticing an awful lot of similarities between a lot
of sites you encounter, due to similar use of frameworks. In addition to that issue,
too many new developers also jump into learning frameworks too early in their
education; the prospect of not having to practice writing vanilla CSS is very
tempting. As a result, many developers do not get enough CSS practice under their
belts to solidify the fundamentals of this very important language.
Additionally, the process of overriding a framework’s styling or debugging style
issues on your page becomes very difficult if you haven’t really mastered CSS
fundamentals. It is imperative to understand what a framework is doing “under the
hood” so that you are equipped to handle these issues later (and trust us, you will
have to).
Ultimately, frameworks can help you get up and running quickly - but they can
constrain you in the long run. And once you’ve started a project using a framework
it can be difficult to remove it. So whether or not you use frameworks for projects
in the future is up to you! (And maybe up to your employer as well….)
Preprocessors Overview
Preprocessors (aka precompilers) are languages that help you write CSS more
easily. They reduce code repetition and provide all sorts of time-saving and code-
saving features. A few examples: preprocessors allow you to write loops, join
multiple stylesheets, and nest classes.
CSS preprocessors are extensions to vanilla CSS that provide some extra
functionality such as nesting, mixins, and variables. When you run the processor, it
takes your code and turns it into vanilla CSS that you can import into your project.
Preprocessors do have some unique and helpful tools, but many of their most
helpful features have been implemented in vanilla CSS, so it might not be worth
the overhead of learning one unless you think you really need these features.
Some of the standard preprocessors in use are SASS, LESS and Stylus.
Assignment
1. Read this brief overview of frameworks.
2. Read this article, which considers the pros and cons of using a framework vs.
CSS grid.
3. Skim this article, which gives an overview of SASS, LESS and Stylus.
4. Read this brief article, which gives some reasons for using a preprocessor.
5. For balance, read this list of the disadvantages of using a preprocessor.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
HTML and CSS Page 49
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• Bootstrap documentation
• Tailwind documentation
• SASS documentation

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What are some advantages of using a CSS framework?
• What are some disadvantages of using a CSS framework?
• What are some advantages of using a CSS preprocessor?
• What are some disadvantages of using a CSS preprocessor?

HTML and CSS Page 50


Forms
Thursday, July 7, 2022 2:25 AM

HTML and CSS Page 51


Form Basics
Thursday, July 7, 2022 2:25 AM

Introduction
Forms are one of the most critical parts of your site. They are your user’s gateway
into your backend – the user provides data in a form, and you do stuff with it.
You need to specify the proper types of inputs for each possible data item since
there are often multiple ways to collect a piece of data, but only one way is easiest
for your user.
In this lesson, we will explore the basics of HTML forms and some of the different
types of inputs available to you.
Learning Outcomes
By the end of this lesson, you should be able to:
• Create forms with HTML
• Have a basic idea of how to style forms

The Form Element


The form element is a container element like the div element we learned earlier in
the curriculum. The form element wraps all of the inputs a user will interact with
on a form.
The form element accepts two essential attributes; the first is the action attribute
which takes a URL value that tells the form where it should send its data to be
processed. Later in the curriculum, we will learn to hook backend systems up to
frontend forms using this attribute. For now, it’s only essential to know what the
action attribute is used for.
The second is the method attribute which tells the browser which HTTP request
method it should use to submit the form. The GET and POST request methods are
the two you will find yourself using the most.
We use GET when we want to retrieve something from a server. For example,
Google uses a GET request when you search as it gets the search results.
POST is used when we want to change something on the server, for example, when
a user makes an account or makes a payment on a website.
The markup for creating a form element looks like this:
<form action="example.com/path" method="post">

</form>

HTML and CSS Page 52


Form Controls
To start collecting user data, we need to use form control elements. These are all
the elements users will interact with on the form, such as text boxes, dropdowns,
checkboxes and buttons. In the following few sections, we will explore some of the
form controls you will use most commonly.
The Input Element
The input element is the most versatile of all the form control elements. It accepts
a type attribute which tells the browser what type of data it should expect and how
it should render the input element.
A text input looks like this:
<form action="example.com/path" method="post">
<input type="text">
</form>

Text inputs accept any text input. For example, you would use it to collect things
like users’ first and last names.
Labels
An input on its own isn’t very useful since the user will not know what kind of data
they are supposed to provide. Instead, we can give our inputs a label to inform
users what type of data they are expected to enter.
To create a label, we use the <label> element. The text we want displayed in the
label will go between its opening and closing tags:
<form action="example.com/path" method="post">
<label for="firstName">First Name:</label>
<input type="text" id="firstName">
</form>

Labels accept a for attribute, which associates it with a particular input. The input
we want to associate with a label needs an id attribute with the same value as the
label’s for attribute.
When a label is associated with an input and is clicked, it will focus the cursor on
that input, ready for the user to input some data. This helps make our forms more
accessible to users who rely on assistive technologies.
Placeholder Attribute
To guide users on what to enter in form elements, we can include placeholder text
in input fields.

HTML and CSS Page 53


in input fields.
This is done by adding a placeholder attribute to an input. The value will be the
placeholder text we want to display in the input:
<label for="first_name">First Name:</label>
<input type="text" id="first_name" placeholder="Bob...">

Use placeholder text to demonstrate how text should be entered and formatted.
The Name Attribute
We need to use labels so that users understand what the data entered into an
input field will represent. Just like that, we also need to let the backend, where we
send our data, know what each piece of data represents.
We do this by adding a name attribute to our inputs:
<label for="first_name">First Name:</label>
<input type="text" id="first_name" name="first_name">

The name attribute serves as a reference to the data inputted into a form control
after submitting it. You can think of it as a variable name for the input. Form input
should always have a name attribute; otherwise, it will be ignored when the form
is submitted.
To get a better understanding of what this looks like we can submit a form to
httpbin. This service will send back a response which will let us view what data was
submitted. Fill in the form below and click submit:
The output we care about from the response is the “form” object. It should look
something like this:
"form": {
"age": "33",
"first_name": "John",
"last_name": "Doe"
},

Try changing the name attributes of some of the input fields in the form and then
submitting again to see how form data in the response changes.
Using Form Controls Outside of Forms
It’s worth mentioning that you can use any of the form controls HTML provides
outside of the <form> element, even when you don’t have a backend server where
you can send data.
For example you might want to have an input that gets some data from a user and
display that somewhere else on the page with JavaScript:
HTML and CSS Page 54
display that somewhere else on the page with JavaScript:
We will need to manipulate data from form controls like this quite a bit when we
get to the projects in the Fullstack JavaScript course.
Email Input
Email inputs are specialized text inputs just for email addresses. They are different
from text inputs in that they will display a different keyboard which will include the
@ symbol on mobile devices to make entering email addresses easier.
They also validate that the user has entered a correctly formatted email address,
but there will be more on validations later.
To create an email input, we use an input element with type attribute of “email”:
<label for="user_email">Email Address:</label>
<input type="email" id="user_email" name="email"
placeholder="you@example.com">

Password Input
Password inputs are another specialized text input. They differ from regular text
inputs in that they mask the inputted data with asterisks(*) to prevent anyone
from seeing what has been entered.
A password input can be created using an input element with a type of
“password”:
<label for="user_password">Password:</label>
<input type="password" id="user_password" name="password">

Number Input
The number input only accepts number values and ignores any other characters
the user tries to enter.
We create a number input using the input element with a type attribute of
“number”:
<label for="amount">Amount:</label>
<input type="number" id="amount" name="amount">

Date Input
To collect dates from a user, we can use a date input. This input is unique because
it provides a better user experience for choosing dates by rendering a simple date
picker calendar.
To create a date input, we use the input element with a type attribute of “date”:
<label for="dob">Date of Birth:</label>
HTML and CSS Page 55
<label for="dob">Date of Birth:</label>
<input type="date" id="dob" name="dob">

Text Area
The text area element provides an input box that can accept text that spans
multiple lines like user comments and reviews. It can also be resized by clicking and
dragging the bottom right corner to make it bigger or smaller.
To create a text area, we use the <textarea> element:
<textarea></textarea>

Unlike input elements, Textarea elements do have a closing tag. This allows you to
wrap some initial content you want the text area to display:
<textarea>Some initial content</textarea>

Text area elements accept a couple of unique attributes that other form controls
do not. These are the rows and cols attributes. They allow you to control the initial
height (rows) and width (cols) of the text area:
<textarea rows="20" cols="60"></textarea>

Selection Elements
Sometimes you will want users to select a value from a predefined list. This is
where select elements will be useful.
Select Dropdown
The select element renders a dropdown list where users can select an option.
Syntactically, select elements have similar markup to unordered lists. The select
element wraps option elements which are the options that can be selected.
To create a select dropdown, we use the <select> element. Any options we want to
display within the select element are defined using <option> elements:
<select name="Car">
<option value="mercedes">Mercedes</option>
<option value="tesla">Tesla</option>
<option value="volvo">Volvo</option>
<option value="bmw">BMW</option>
<option value="mini">Mini</option>
<option value="ford">Ford</option>
</select>

HTML and CSS Page 56


All the option elements need to have a value attribute. This value will be sent to
the server when the form is submitted.
We can set one of the options to be the default selected element when the
browser first renders the form by giving one of the options the selected attribute:
<select name="Car">
<option value="mercedes">Mercedes</option>
<option value="tesla">Tesla</option>
<option value="volvo" selected>Volvo</option>
<option value="bmw">BMW</option>
<option value="mini">Mini</option>
<option value="ford">Ford</option>
</select>

We may also split the list of options into groups using the <optgroup> element.
The optgroup element takes a label attribute which the browser uses as the label
for each group:
<select name="fashion">
<optgroup label="Clothing">
<option value="t_shirt">T-Shirts</option>
<option value="sweater">Sweaters</option>
<option value="coats">Coats</option>
</optgroup>
<optgroup label="Foot Wear">
<option value="sneakers">Sneakers</option>
<option value="boots">Boots</option>
<option value="sandals">Sandals</option>
</optgroup>
</select>

Radio Buttons
Select dropdowns are great for saving space on the page when we have an
extensive list of options we want users to choose from. However, when we have a
smaller list of 5 or fewer options to choose from, it is often a better user
experience to have them displayed on the page instead of hidden behind a
dropdown.
In this case, we can use radio buttons. Radio buttons allow us to create multiple
options that the user can choose one of. To create radio buttons, we use the ever
adaptable input element again with a type attribute of “radio”:
<h1>Ticket Type</h1>
HTML and CSS Page 57
<h1>Ticket Type</h1>
<div>
<input type="radio" id="child" name="ticket_type" value="child">
<label for="child">Child</label>
</div>

<div>
<input type="radio" id="adult" name="ticket_type" value="adult">
<label for="adult">Adult</label>
</div>

<div>
<input type="radio" id="senior" name="ticket_type" value="senior">
<label for="senior">Senior</label>
</div>

When we select one of the radio buttons and then select another, it will deselect
the first one. Radio buttons know to do this because they have the same name
attribute. This is how the browser knows these elements are part of the same
group of options.
We can set the default selected radio button by adding the checked attribute to it:
<h1>Ticket Type</h1>
<div>
<input type="radio" id="child" name="ticket_type" value="child">
<label for="child">Child</label>
</div>

<div>
<input type="radio" id="adult" name="ticket_type" value="adult" checked>
<label for="adult">Adult</label>
</div>

<div>
<input type="radio" id="senior" name="ticket_type" value="senior">
<label for="senior">Senior</label>
</div>

Checkboxes
Checkboxes are similar to radio buttons in that they allow users to choose from a
set of predefined options. But unlike radio buttons, they allow multiple options to
be selected at once.

HTML and CSS Page 58


be selected at once.
To create a checkbox, we use the input element with a type attribute of
“checkbox”:
<h1>Pizza Toppings</h1>

<div>
<input type="checkbox" id="sausage" name="topping" value="sausage">
<label for="sausage">Sausage</label>
</div>

<div>
<input type="checkbox" id="onions" name="topping" value="onions">
<label for="onions">Onions</label>
</div>

<div>
<input type="checkbox" id="pepperoni" name="topping" value="pepperoni">
<label for="pepperoni">Pepperoni</label>
</div>

<div>
<input type="checkbox" id="mushrooms" name="topping" value="mushrooms">
<label for="mushrooms">Mushrooms</label>
</div>

We can also have a single checkbox when we want users to toggle if they want
something to be true or false. Like signing up to a newsletter when they create an
account for example:
<div>
<input type="checkbox" id="newsletter" name="news_letter">
<label for="newsletter">Send me the news letter</label>
</div>

We can set checkboxes to be checked by default on page load by giving them a


checked attribute:
<div>
<input type="checkbox" id="newsletter" name="news_letter" checked>
<label for="newsletter">Send me the news letter</label>
</div>

HTML and CSS Page 59


Buttons
The button element creates clickable buttons that the user can interact with to
submit forms and trigger other actions.
To create a button, we use the <button> element. The content or text we want to
have displayed inside the button will go within the opening and closing tags:
<button>Click Me</button>

The button element also accepts a type attribute that tells the browser which kind
of button it is dealing with. There are three types of buttons available to us.
Submit Buttons
Once a user is finished filling in a form, they will need a way to submit it. There is a
specialized button for this; the submit button. When a submit button is clicked, it
will submit the form it is contained within. The type attribute has a value of submit
by default, i.e. if the type is not specified or the value provided is invalid.
To create a submit button, we use the button element with a type attribute of
“submit”:
<button type="submit">Submit</button>

Reset Button
A reset button clears all the data the user has entered into the form and sets all
the inputs in the form back to what they were initially.
To create a reset button, we use the button element with a type attribute of
“reset”:
<button type="reset">Reset</button>

Generic Button
The third and final button type is simply a generic button that can be used for
anything. It’s commonly used with JS for creating interactive UI’s.
To create a generic button, we use the button element with a type attribute of
“button”:
<button type="button">Click to Toggle</button>

Note: It is important to remember that a button within a form with the type value
of submit (which happens to be the default value) will always try to make a new
request and submit data back to the server. Hence, for buttons that are used
within a form for different purposes other than submitting the data, the type

HTML and CSS Page 60


within a form for different purposes other than submitting the data, the type
attribute should always be specified to avoid unwanted effects of submitting a
form.
Organizing Form Elements
Using the correct inputs for the data we want users to enter goes a long way
towards making our forms user friendly. However, in larger forms, users can easily
get overwhelmed and discouraged if there are many inputs to fill in.
Luckily, HTML provides a couple of elements that make it easy to organize forms
into sections that are visually distinct and manageable to digest.
Fieldset Element
The fieldset element is a container element that allows us to group related form
inputs into one logical unit.
To create a fieldset, we use the <fieldset> element. Whatever form inputs we want
to group together go within the opening and closing fieldset tags:
<fieldset>
<label for="first_name">First Name</label>
<input type="text" id="first_name" name="first_name">

<label for="last_name">Last Name</label>


<input type="text" id="last_name" name="last_name">
</fieldset>

Legend
The legend element is used to give field sets a heading or caption so the user can
see what a grouping of inputs is for.
To create a legend, we use the <legend> element with the text we want to display
within its opening and closing tags. A legend should always come right after an
opening fieldset tag:
<fieldset>
<legend>Contact Details</legend>

<label for="name">Name:</label>
<input type="text" id="name" name="name">

<label for="phone_number">Phone Number:</label>


<input type="tel" id="phone_number" name="phone_number">

<label for="email">Email:</label>
<input type="email" id="email" name="email">

HTML and CSS Page 61


<input type="email" id="email" name="email">
</fieldset>

<fieldset>
<legend>Delivery Details</legend>

<label for="street_address">Street Address:</label>


<input type="text" id="street_address" name="street_address">

<label for="city">City:</label>
<input type="text" id="city" name="city">

<label for="zip_code">Zip Code:</label>


<input type="text" id="zip_code" name="zip_code">
</fieldset>

A common use-case for these elements is using a fieldset to group radio buttons
and using a legend to communicate to the user what each of the options is
ultimately for:
<fieldset>
<legend>What would you like to drink?</legend>

<div>
<input type="radio" name="drink" id="coffee" value="coffee">
<label for="coffee">Coffee</label>
</div>

<div>
<input type="radio" name="drink" id="tea" value="tea">
<label for="tea">Tea</label>
</div>

<div>
<input type="radio" name="drink" id="soda" value="soda">
<label for="soda">Soda</label>
</div>

</fieldset>

A Note on Styling Forms


We will provide resources that go deep into styling forms in the assignment section
HTML and CSS Page 62
We will provide resources that go deep into styling forms in the assignment section
that comes next. However, before we get to the assignment, we should talk about
some of the challenges with styling HTML forms and how we can get around them:
Default Browser Styles
Each browser has its own default styles for form controls, making your forms
visually different for users depending on what browser they are using.
To have a consistent design among all browsers, we have to override these default
styles and style them ourselves.
Tricky and downright impossible to style form controls
Text-based form controls like text, email, password and text areas are reasonably
straightforward to style. They operate like any other HTML element, and most CSS
properties can be used on them.
Things get more tricky when creating custom styles for radio buttons and
checkboxes. But there are many guides out there you can use to achieve your
desired design. There have also been new CSS properties made available in recent
times to make styling radio buttons and checkboxes much easier.
Certain aspects of other elements are downright impossible to style, for example,
calendar or date pickers. If we want custom styles for these, we will have to build
custom form controls with JavaScript or use one of the many JavaScript libraries
that provide us with ready-made solutions.
Assignment
Form Basics
1. Read and follow along to MDN’s Introductory Guides to Forms
2. Read and follow along to MDN’s The Different Form Controls Guides
Styling Forms
1. Read and follow along to MDN’s Form Styling Guides
2. Read and follow along to the internetingishard guide to forms

Additional Resources
• Web.dev’s Form Course

Knowledge Check
• Explain what the form element is for and what two attributes it should always
include.
• Explain what form controls are at a high level.
• What is the name attribute for?
• What are the three most common form controls you can use for allowing
users to select predefined options?
• What are the three types of buttons in HTML?
• What are the two most challenging aspects of styling forms?

HTML and CSS Page 63


• What are the two most challenging aspects of styling forms?

HTML and CSS Page 64


Form Validation
Thursday, July 7, 2022 2:25 AM

Introduction
Validations allow us to set specific constraints or rules that determine what data
users can enter into an input. When a user enters data that breaks the rules, a
message will appear, providing feedback on what was wrong with the entered data
and how to fix it.
Validations are a vital ingredient in well-designed forms. They help protect our
backend systems from receiving incorrect data, and they help make the experience
of interacting with our form as dead-stupid-simple as possible for our users.
This lesson will explore some of the built-in validations you can use with HTML
forms. We will also dive into styling validations with CSS.
Learning Outcomes
By the end of this lesson, you should be able to:
• Explain what form validations are
• Know how to use a few of the basic built-in HTML validations
• Know how to build custom validations

Required Validation
We will often want to ensure specific fields have been filled in before submitting
the form, for example, the email and password in a login form.
To make a field required, we simply add the required attribute to it:
To ensure a good user experience and to meet accessibility guidelines, we should
always indicate which fields are required. This will often be done by adding an
asterisk(*) to the required field label like we have done in the example.
Text Length Validations
Sometimes we will want users to enter a minimum or a maximum amount of text
into a field. Real-world examples of using these validations would be the old 140
character limit that Twitter used to have in its status field or having minimum and
maximum length constraints on a username field.
Minimum Length Validation
To add the minimum length validation, we give the form control a minlength
attribute with an integer value that represents the minimum amount of characters
we want to allow in the form control:

HTML and CSS Page 65


Try entering less than three characters into the text area and clicking the tweet
button to see the validation in action.
Maximum Length Validation
To add a maximum length validation, we give the form control a maxlength
attribute with an integer value which represents the maximum amount of
characters we want to allow in the form control:
With the maximum length validation, the browser will prevent users from entering
more characters than the max length attribute value. Try this for yourself in the
example above.
Combining Validations
HTML allows us to apply as many validations as we wish to a form control. For
example, we can give our tweet textarea both minlength and maxlength
validations:
This gives us much more scope to control what users input.
Number Range Validations
Just like we often need to control the length of text-based form controls, there will
be many situations where we will want to control the range of values users can
enter into number based form controls.
We can do this with the min and max attributes, which allows us to set the lower
and upper bounds of the value entered into the form control. The min and max
attributes only work with number-based form controls such as the number, dates
and time inputs. You can view the complete list of supported elements on MDN’s
documentation.
Some real-world use cases for using these validations would be limiting the
quantity on a product order form or choosing the number of passengers on a flight
booking form.
Min Validation
To add a minimum value validation, we give the form control a min attribute with
an integer value which represents the minimum number we want the form control
to accept:
Try submitting the form with a quantity of 0 to see the validation in action.
Max Validation
To add a maximum value validation, we give the form control a max attribute with
an integer value which represents the maximum number we want the form control
to accept:
Try submitting the form with seven passengers to see the validation in action.
Pattern Validations

HTML and CSS Page 66


Pattern Validations
To ensure we get the correct information from users, we will often want to ensure
data matches a particular pattern. Real-world applications would be checking a
credit card number or a zipcode is in the correct format.
To add a pattern validation, we give the form control a pattern attribute with a
regular expression as the value. In our example we are using the pattern validation
to ensure a US zip code is in the correct format. 5 numbers followed by an optional
dash and 4 more numbers:
Entering an incorrect zip code and submitting the form will display the following
validation error in the browser “Please match the requested format”. This isn’t
very useful since it doesn’t communicate how to fix the issue.
We can add a more descriptive validation message by giving our input a title
attribute:
When we submit the form with an incorrect zip code, we will be greeted with a
more helpful message telling us exactly what went wrong and how to resolve it.
It is also good practice to use a placeholder attribute to show users an example of
the expected pattern they need to enter:
The pattern attribute can only be used on <input> elements. Some input elements
already validate data that matches a certain pattern. For example the email input
field which will make sure a valid email is entered and the url input element which
will check to ensure the url starts with http or https:
Styling Validations
We can target form controls that have passed or failed validations using the :valid
and :invalid pseudo-classes.
To see this in action, we will be using our email and website example that we
looked at previously:
First of all, we target any valid inputs and give them a green border. Our email and
URL inputs initially have a green border since they are not required fields and are
valid.
When a field is invalid, we give it a red border instead. Try entering an invalid email
address and URL to see how this looks.
Conclusion
The built-in validations will take you far with ensuring your users enter the correct
data. They are quick and easy to add. However, they have their limitations.
Sometimes you will need to include validations that the built-in validations won’t
be able to do. For example, validating that a password input and password
confirmation input have the same value or validating that a username has not
already been taken. We are also limited with what we can do with styling the
HTML and CSS Page 67
already been taken. We are also limited with what we can do with styling the
validation messages and the content within them.
In this case, we will need to get creative and make custom validations using
JavaScript and CSS. We’ll dive into how to achieve validation via JavaScript in a
future lesson.
It’s also worth noting client-side validations are not a silver bullet for ensuring
users enter the correct data. To ensure the integrity of any user data coming into
our systems, we should also have server-side validations in place. We will cover
this side of validations later in the curriculum.
Assignment
1. Read and follow along to MDN’s Client-Side Form Validation Guide
Skip the section on “Validating forms using JavaScript”. This will be covered in a
future lesson.
1. Go through SitePoint’s Complete Guide to HTML Forms and Constraint Validation
Guide. You can skip the section on “JavaScript and the Constraint Validation API”.
2. Read CSS Tricks brilliant Form Validation UX in HTML and CSS Guide

Additional Resources
• Check out html5pattern for a list of commonly used pattern regular
expressions you may find helpful.
• Look through this Twitter thread of the do and don’ts for form validation UX.
• 10 Guidelines for form validation design
• Regular expressions clearly explained goes over several real world examples of
regular expression patterns and walks through what they’re doing step by
step. This resource can be useful if you don’t just want to copy + paste
popular patterns, and instead want to know what a pattern is actually doing.
• One last resource on regular expressions that can be helpful is MDN’s regular
expression syntax cheatsheet. This cheatsheet does a great job explaining the
syntax of regular expressions in more detail.
Knowledge Check
• What does the required validation do?
• What validations can you use for checking text length?
• How can you validate the minimum and maximum of numeric inputs?
• What can you use the pattern validation for?
• What pseudo css selectors are available for styling valid and invalid inputs?

HTML and CSS Page 68


Project: Sign-up Form
Thursday, July 7, 2022 2:25 AM

Introduction
This project is intended to give you a chance to flex some of the new items you’ve
been absorbing over the past few lessons. This time it’s a sign-up form for an
imaginary service.
Assignment
Step 1: Set up and planning
1. Set up your HTML and CSS files with some simple dummy content, just to
make sure you have everything linked correctly.
2. Set up your git repository (refer to past projects if you need a refresher).
3. Download a full-resolution copy of the design file, and get a general idea for
how you’re going to need to lay things out in your HTML document.
Step 2: Gather Assets
1. The design has a large background-image, so go find and download an image
you want to use for that section. The one in the design can be found on
unsplash.com, but feel free to select your own. Be sure to credit the creator
of your image!
2. For the image-sidebar, use any logo.
Step 3: Some Tips!
1. How you attack this project is mostly up to you, but it is wise to begin by
scaffolding out the structure of the page, and then take the various sections
one by one.
2. The area behind the “ODIN” logo is a div that has a dark, but semi-
transparent background color. This enhances the readability of the text
against the busy background image.
3. The color we’ve chosen for the ‘Create Account’ button is similar to tones
found in the background image. Specifically, it is #596D48.
4. The inputs, by default have a very light border (#E5E7EB), but we’ve
included 2 variations. For starters, the password inputs should be given an
error class.
5. The other variation is the selected input, which should have a blue border
and subtle box-shadow. This can be done with the :focus pseudo-class
you’ve learned about in an earlier lesson.
6. Do not worry about making your project look nice on mobile, but DO resize
your browser a little bit to make sure that it’s not completely broken at
different desktop resolutions.
7. Checking that the password fields match each other requires javascript. Try
to implement this if you feel confident, otherwise just validate each field
separately.

HTML and CSS Page 69


Introduction
Thursday, July 7, 2022 2:19 AM

Make your websites dynamic and interactive with JavaScript! You'll create features
and stand-alone applications. This module includes projects where you will learn
how to manipulate the DOM, use object-oriented programming principles, and build
single page applications

Introduction
1 How this course will work
2 A quick review

Organizing your JavaScript Code


1 Introduction
2 Objects and Object Constructors
3 Project: Library
4 Factory Functions and the Module Pattern
5 Project: Tic Tac Toe
6 Classes
7 ES6 Modules
8 Webpack
9 Project: Restaurant Page
10 OOP Principles
11 Project: Todo List

JavaScript in Real World


1 Linting
2 Dynamic User Interface Interactions
3 Form Validation with JavaScript
4 What is ES6?

Asynchronous JavaScript and APIs


1 JSON
2 Asynchronous Code
3 Working with APIs
4 Async and Await
5 Project: Weather App

Testing JavaScript

Javascript Page 70
Testing JavaScript
1 Testing Basics
2 Project: Testing Practice
3 More Testing
4 Project: Battleship

Intermediate Git
1 A deeper look at Git

Video Course
Course: Namase JavaScript

Author: Akshay Saini


Things to focus on:
1 Hoisting
2 Functions
3 undefined vs not defined
4 scope and lexical environment
5 let and const in js
6 block scope and shadowing
7 closures
8 setTimeout + Closures
9 first class functions
10 callback functions
12 asynchronous javascript and event loop from scratch
13 Higher order functions
14 map, filter and reduce

Exercises:

Javascript Page 71
Exercises:
139 exercises grouped into 31 JavaScript Concepts

Javascript Page 72
How this course will work
Thursday, July 7, 2022 2:19 AM

Introduction
JavaScript is the future of the web. More and more of the logic is making its way to
the client side in order to facilitate lightning-fast user experiences. JavaScript is
even moving to the server side with Node.js. That’s why in this course we’ll be
diving deep into it to make sure you come out with a good understanding of how it
works.
This section will cover a lot of ground and your brain may melt down a few times,
but don’t worry, that’s just a flesh wound. Patch ‘er up and keep going! When in
doubt, build something.
The Path
The last thing you’ll do is a final project which integrates everything you’ve learned
in all the courses of this curriculum. This is the kind of project that you’ll be telling
employers all about and a great chance to prove that you’re now, officially, a
serious web developer.
Format
There is a lot to cover, but this course has been broken up into bite-sized lessons
and their accompanying projects. These projects will give you a chance to apply
what you have learned and to show what you are capable of. After a few of them,
you’ll really start getting the hang of things.
In each lesson:
1. We will introduce the topic briefly and provide you with a list of things you
should pay attention to (“Points to Ponder”).
2. You will be asked to do readings, watch videos, do online courses or otherwise
consume content to initially learn the material.
3. Every few lessons you will be asked to build a larger project.
4. Finally, we will include supplemental resources and other potentially useful
tidbits at the end of each lesson.

Enough talk - get learning!

Javascript Page 73
A quick review
Thursday, July 7, 2022 1:40 PM

Introduction
This course assumes that you have a decent grasp on the fundamentals of
JavaScript.
Review
Running through “part 1” of MDN’s JavaScript basics course is a great idea for a
refresher on the syntax. If you just want a quick reference to skim, try LearnXinY.
It might also be a good idea to do a little practicing before moving on. If you want
something fresh to work on, now would be a fine time to do some coding exercises
from across the net. The following sites are all great places to look.
• Exercism
• CodeWars

jQuery?
Before you press on, a note about jQuery. We occasionally get questions about
why we don’t include jQuery in our curriculum. jQuery was very popular in the
past, but has fallen out of the limelight in recent years. One of the biggest reasons
it’s begun to fall out of favor is that you simply don’t need it anymore. When it
became popular, doing things like DOM manipulation and AJAX calls were difficult
in plain JavaScript, but that is no longer the case.
A quick web-search on the topic will be more useful than any explanations here,
and if you still want to learn it (many older codebases still use it, and you will see it
on many older Stack Overflow posts) we are confident that you can pick it up quite
easily by reading the documentation on their website.

Javascript Page 74
Organizing your JavaScript Code
Thursday, July 7, 2022 1:43 PM

This series digs in to the things you need to write larger and larger applications with
JavaScript. This is where it gets real!

Javascript Page 75
Introduction
Thursday, July 7, 2022 1:44 PM

One of the most daunting parts of JavaScript is learning how to organize your code.
The reason this subject can be so overwhelming is not because JavaScript is so
much more complex than other languages, but because it is incredibly forgiving!
Many languages force you into using specific patterns and data structures in your
code, but that is not true in JavaScript.
In the beginning, this is a great thing! For example, if you just want to make a
simple button on your webpage do something, you can set that up in a couple lines
of code. However, as your program becomes more complex, it can become hard to
maintain unless you take care to organize your code, and because JavaScript is
such a flexible language, how you do that is entirely up to you. For many coders,
making decisions about design patterns is crippling, so we’re here to help.
This lesson series is going to cover a few of the most common design patterns that
occur in modern JavaScript code. We will discuss some pros and cons of each
pattern and will give you a chance to practice using each pattern in a project.
The patterns we’ll be covering in this series are:
• Plain Old JavaScript Objects and Object Constructors
• Factory Functions and the Module Pattern
• Classes
• ES6 Modules
Going through these will give us a chance to learn about a few other important
concepts in JavaScript such as “closure”, “prototypes”, “IIFEs” and more! This
series covers the most important parts of JavaScript after simply learning the
basics of the language… are you ready?
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• The book You Don’t Know JS (YDKJS) is free on GitHub, and explains how
JavaScript works “under the hood”. If you ever wondered why JavaScript
works the way it does, this book is for you!

Javascript Page 76
Objects and Object Constructors
Thursday, July 7, 2022 1:45 PM

Introduction
There are multiple ways to define objects but in most cases, it is best to use the
object literal syntax as follows:
const myObject = {
property: 'Value!',
otherProperty: 77,
"obnoxious property": function() {
// do stuff!
}
}

There are also 2 ways to get information out of an object: dot notation and bracket
notation.
// dot notation
myObject.property // 'Value!'

// bracket notation
myObject["obnoxious property"] // [Function]

Which method you use will depend on context. Dot notation is cleaner and is
usually preferred, but there are plenty of circumstances when it is not possible to
use it. For example, myObject."obnoxious property" won’t work because that
property is a string with a space in it. Likewise, you cannot use variables in dot
notation:
const variable = 'property'

myObject.variable // this gives us 'undefined' because it's looking for a property


named 'variable' in our object

myObject[variable] // this is equivalent to myObject['property'] and returns


'Value!'

Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Write an object constructor and instantiate the object.

Javascript Page 77
• Write an object constructor and instantiate the object.
• Describe what a prototype is and how it can be used.
• Explain prototypal inheritance.
• Understand the basic do’s and don’t’s of prototypical inheritance.
• Explain what Object.create does.
• Explain what the this keyword is.

Objects as a Design Pattern


One of the simplest ways you can begin to organize your code is by simply
grouping things into objects. Take these examples from a ‘tic tac toe’ game:
// example one
const playerOneName = "tim"
const playerTwoName = "jenn"
const playerOneMarker = "X"
const playerTwoMarker = "O"

// example two
const playerOne = {
name: "tim",
marker: "X"
}

const playerTwo = {
name: "jenn",
marker: "O"
}

At first glance, the first doesn’t seem so bad.. and it actually takes fewer lines to
write than the example using objects, but the benefits of the second approach are
huge! Let me demonstrate:
function printName(player) {
console.log(player.name)
}

This is something that you just could NOT do with the example one setup. Instead,
every time you wanted to print a specific player’s name, you would have to
remember the correct variable name and then manually console.log it:
console.log(playerOneName)
console.log(playerTwoName)

Again, this isn’t that bad… but what if you don’t know which player’s name you
Javascript Page 78
Again, this isn’t that bad… but what if you don’t know which player’s name you
want to print?
function gameOver(winningPlayer){
console.log("Congratulations!")
console.log(winningPlayer.name + " is the winner!")
}

Or, what if we aren’t making a 2 player game, but something more complicated
such as an online shopping site with a large inventory? In that case, using objects
to keep track of an item’s name, price, description and other things is the only way
to go. Unfortunately, in that type of situation, manually typing out the contents of
our objects is not feasible either. We need a cleaner way to create our objects,
which brings us to…
Object Constructors
When you have a specific type of object that you need to duplicate like our player
or inventory items, a better way to create them is using an object constructor,
which is a function that looks like this:
function Player(name, marker) {
this.name = name
this.marker = marker
}

and which you use by calling the function with the keyword new.
const player = new Player('steve', 'X')
console.log(player.name) // 'steve'

Just like with objects created using the Object Literal method, you can add
functions to the object:
function Player(name, marker) {
this.name = name
this.marker = marker
this.sayName = function() {
console.log(name)
}
}

const player1 = new Player('steve', 'X')


const player2 = new Player('also steve', 'O')
player1.sayName() // logs 'steve'
player2.sayName() // logs 'also steve'
Javascript Page 79
player2.sayName() // logs 'also steve'

Exercise
Write a constructor for making “Book” objects. We will revisit this in the project at
the end of this lesson. Your book objects should have the book’s title, author, the
number of pages, and whether or not you have read the book.
Put a function into the constructor that can report the book info like so:
theHobbit.info() // "The Hobbit by J.R.R. Tolkien, 295 pages, not read yet"

Note: It is almost always best to return things rather than putting console.log()
directly into the function. In this case, return the info string and log it after the
function has been called:
console.log(theHobbit.info());

The Prototype
Before we go much further, there’s something important you need to understand
about JavaScript objects. All objects in JavaScript have a prototype. Stated simply,
the prototype is another object that the original object inherits from, which is to
say, the original object has access to all of its prototype’s methods and properties.
The concept of the prototype is an important one, so you’ve got some reading to
do, which you’ll find in the Assignment section below. Make sure you really get it
before moving on!
If you’ve understood the concept of the prototype, this next bit about constructors
will not be confusing at all!
function Student(name, grade) {
this.name = name
this.grade = grade
}

Student.prototype.sayName = function() {
console.log(this.name)
}
Student.prototype.goToProm = function() {
console.log("Eh.. go to prom?")
}

If you’re using constructors to make your objects it is best to define functions on


the prototype of that object. Doing so means that a single instance of each
Javascript Page 80
the prototype of that object. Doing so means that a single instance of each
function will be shared between all of the Student objects. If we declare the
function directly in the constructor, like we did when they were first introduced,
that function would be duplicated every time a new Student is created. In this
example, that wouldn’t really matter much, but in a project that is creating
thousands of objects, it really can make a difference.
Recommended Method for Prototypal Inheritance
So far you have seen several ways of making an object inherit the prototype from
another object. At this point in history, the recommended way of setting the
prototype of an object is Object.create (here is the documentation for that
method). Object.create very simply returns a new object with the specified
prototype and any additional properties you want to add. For our purposes, you
use it like so:
function Student() {
}

Student.prototype.sayName = function() {
console.log(this.name)
}

function EighthGrader(name) {
this.name = name
this.grade = 8
}

EighthGrader.prototype = Object.create(Student.prototype)

const carl = new EighthGrader("carl")


carl.sayName() // console.logs "carl"
carl.grade // 8

You can probably figure out what’s going on here. After creating the constructor
for EighthGrader, we set its prototype to a new object that has a copy of
Student.prototype.
A warning… this doesn’t work:
EighthGrader.prototype = Student.prototype

because it will literally set EighthGrader’s prototype to Student.prototype (i.e. not


a copy), which could cause problems if you want to edit something in the future.
Consider one more example:

Javascript Page 81
Consider one more example:

function Student() {
}

Student.prototype.sayName = function() {
console.log(this.name)
}

function EighthGrader(name) {
this.name = name
this.grade = 8
}

// don't do this!!!
EighthGrader.prototype = Student.prototype

function NinthGrader(name) {
this.name = name
this.grade = 9
}

// noooo! not again!


NinthGrader.prototype = Student.prototype

NinthGrader.prototype.sayName = function() {console.log("HAHAHAHAHAHA")}

const carl = new EighthGrader("carl")


carl.sayName() //uh oh! this logs "HAHAHAHAHAHA" because we edited the
sayName function!

If we had used Object.create in this example, then we could safely edit the
NinthGrader.prototype.sayName function without changing the function for
EighthGrader as well.

Assignment
1. Read up on the concept of the prototype from the articles below.
a. JavaScriptIsSexy’s article on the prototype is a straightforward
introduction and demonstration of the concept. It also covers
constructors again.. good time for a review! The important bits here,
once you’ve covered the basics, are ‘Prototype-based inheritance’ and

Javascript Page 82
once you’ve covered the basics, are ‘Prototype-based inheritance’ and
the ‘Prototype chain’.
b. To go a bit deeper into both the chain and inheritance, spend some time
with JavaScript.Info’s article on Prototypal Inheritance. As usual, doing
the exercises at the end will help cement this knowledge in your mind.
Don’t skip them! Important note: This article makes heavy use of
__proto__ which is not generally recommended. The concepts here are
what we’re looking for at the moment. We will soon learn another
method or two for setting the prototype.
2. You might have noticed us using the this keyword in object constructors and
prototype methods in the examples above.
a. Dmitri Pavlutin’s article on the this keyword is very comprehensive and
covers how this changes in various situations. You should have a solid
understanding of the concept after reading it. Pay special attention to the
pitfalls mentioned in each section.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• This article from Lydia Hallie and This video from Avelx explains the Prototype
concept with graphics and simple language. Try using these resources if you
want another perspective to understand the concept.

• This Video from mpj explains Object.create method with great details about it,
he walks through what it is, why Object.create exists in JavaScript, and how to
use Object.create. Also you can check This Video from techsith to understand
another point of view of extending objects from others by Object.create.

Javascript Page 83

• The Principles of Object-Oriented JavaScript book by Nicholas C. Zakas is really


great to understand OOP in javascript, which explains concepts simply and in-
depth, which explores JavaScript’s object-oriented nature, revealing the
language’s unique implementation of inheritance and other key
characteristics, it’s not free but it’s very valuable.
• This stack overflow question explains the difference between defining
methods via the prototype vs defining them in the constructor.
• A Beginner’s Guide to JavaScript’s Prototype and JavaScript Inheritance and
the Prototype Chain from Tyler Mcginnis has great examples to help you
understand Prototype and Prototype Chain better from the beginner’s
perspective.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Write an object constructor and instantiate the object.
• Describe what a prototype is and how it can be used.
• Explain prototypal inheritance.
• Understand the basic do’s and don’t’s of prototypical inheritance.
• Explain what Object.create does
• How does this behave in different situations?

Javascript Page 84
Project: Library
Thursday, July 7, 2022 1:54 PM

Assignment

1. If you haven’t already, set up your project with skeleton HTML/CSS and JS files.

2. All of your book objects are going to be stored in a simple array, so add a function
to the script (not the constructor) that can take user’s input and store the new
book objects into an array. Your code should look something like this:
let myLibrary = [];

function Book() {
// the constructor...
}

function addBookToLibrary() {
// do stuff here
}

3. Write a function that loops through the array and displays each book on the page.
You can display them in some sort of table, or each on their own “card”. It might
help for now to manually add a few books to your array so you can see the display.
4. Add a “NEW BOOK” button that brings up a form allowing users to input the details
for the new book: author, title, number of pages, whether it’s been read and
anything else you might want.
5. Add a button on each book’s display to remove the book from the library.
a. You will need to associate your DOM elements with the actual book objects in
some way. One easy solution is giving them a data-attribute that corresponds
to the index of the library array.
6. Add a button on each book’s display to change its read status.
a. To facilitate this you will want to create the function that toggles a book’s
read status on your Book prototype instance.

Javascript Page 85
Factory Functions and Module Patterns
Thursday, July 7, 2022 1:58 PM

What’s wrong with constructors?


Object constructors are one of about a million ways to start organizing your code.
They are fairly common in the wild and are a fundamental building block of the
JavaScript language.
However…
There are many people who argue against using constructors at all. Their
arguments boil down to the fact that if you aren’t careful, it can be easy to
introduce bugs into your code when using constructors. This article does a pretty
decent job of outlining the issues (spoiler alert: the author ends up recommending
factory functions).
One of the biggest issues with constructors is that while they look just like regular
functions, they do not behave like regular functions at all. If you try to use a
constructor function without the new keyword, your program will not work as
expected, but it won’t produce error messages that are easy to trace.
The main takeaway is that while constructors aren’t necessarily evil, they aren’t the
only way, and they may not be the best way either. Of course, this doesn’t mean
that time learning about them was wasted! They are a common pattern in real-
world code and many tutorials that you’ll come across on the net.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Describe common bugs you might run into using constructors.
• Write a factory method that returns an object.
• Explain how scope works in JavaScript (bonus points if you can point out what
ES6 changed!).
• Explain what Closure is and how it impacts private functions & variables.
• Describe how private functions & variables are useful.
• Use inheritance in objects using the factory pattern.
• Explain the module pattern.
• Describe IIFE. What does it stand for?
• Briefly explain namespacing and how it’s useful.

Factory function introduction


The factory function pattern is similar to constructors, but instead of using new to
create an object, factory functions simply set up and return the new object when
you call the function. Check out this example:
Javascript Page 86
you call the function. Check out this example:
const personFactory = (name, age) => {
const sayHello = () => console.log('hello!');
return { name, age, sayHello };
};

const jeff = personFactory('jeff', 27);

console.log(jeff.name); // 'jeff'

jeff.sayHello(); // calls the function and logs 'hello!'

For reference, here is the same thing created using the constructor pattern:
const Person = function(name, age) {
this.sayHello = () => console.log('hello!');
this.name = name;
this.age = age;
};

const jeff = new Person('jeff', 27);

Object Shorthand
A quick note about line 3 from the factory function example. In 2015, a handy new
shorthand for creating objects was added into JavaScript. Without the shorthand,
line 3 would have looked something like this:
return {name: name, age: age, sayHello: sayHello};

Put simply, if you are creating an object where you are referring to a variable that
has the exact same name as the object property you’re creating, you can condense
it like so:
return {name, age, sayHello};

With that knowledge in your pocket, check out this little hack:
const name = "Maynard";
const color = "red";
const number = 34;
const food = "rice";

// logging all of these variables might be a useful thing to do,


// but doing it like this can be somewhat confusing.
Javascript Page 87
// but doing it like this can be somewhat confusing.
console.log(name, color, number, food); // Maynard red 34 rice

// if you simply turn them into an object with brackets,


// the output is much easier to decipher:
console.log({name, color, number, food});
// { name: 'Maynard', color: 'red', number: 34, food: 'rice' }

Scope and Closure


From simply reading the above example, you are probably already in pretty good
shape to start using factory functions in your code. Before we get there though, it’s
time to do a somewhat deep dive into an incredibly important concept: closure.
However, before we’re able to make sense of closure, we need to make sure you
have a really good grasp on scope in JavaScript. Scope is the term that refers to
where things like variables and functions can be used in your code.
In the following example, do you know what will be logged on the last line?
let a = 17;

const func = x => {


let a = x;
};

func(99);

console.log(a); // ???????

Is it 17 or 99? Do you know why? Can you edit the code so that it prints the other
value?
The answer is 17, and the reason it’s not 99 is that on line 4, the outer variable a is
not redefined, rather a new a is created inside the scope of that function. In the
end, figuring out scope in most contexts is not all that complicated, but it is crucial
to understanding some of the more advanced concepts that are coming up soon,
so take your time to understand what’s going on in the following resources.
1. This video is simple and clear! Start here.
2.

Javascript Page 88
3. This article starts simple and reiterates what the video covered, but goes deeper
and is more specific about the appropriate terminology. At the end, he defines
closure and describes the module pattern, both of which we’ll talk about more
soon.
• The previous article is great, but there is one inaccurate statement:
All scopes in JavaScript are created with Function Scope only, they aren’t created
by for or while loops or expression statements like if or switch. New functions =
new scope - that’s the rule
That statement was true in 2013 when the article was written, but ES6 has
rendered it incorrect. Read this article to get the scoop!

Private Variables and Functions


Now that we’ve cemented your knowledge of scope in JavaScript, take a look at
this example:
const FactoryFunction = string => {
const capitalizeString = () => string.toUpperCase();
const printString = () => console.log(`----${capitalizeString()}----`);
return { printString };
};

const taco = FactoryFunction('taco');

printString(); // ERROR!!
capitalizeString(); // ERROR!!
taco.capitalizeString(); // ERROR!!
taco.printString(); // this prints "----TACO----"

Because of the concept of scope, neither of the functions created inside of


FactoryFunction can be accessed outside of the function itself, which is why lines 9,
10, and 11 fail. The only way to use either of those functions is to return them in
the object (see line 4), which is why we can call taco.printString() but not
taco.capitalizeString(). The big deal here is that even though we can’t access the

Javascript Page 89
taco.capitalizeString(). The big deal here is that even though we can’t access the
capitalizeString() function, printString() can. That is closure.
The concept of closure is the idea that functions retain their scope even if they are
passed around and called outside of that scope. In this case, printString has access
to everything inside of FactoryFunction, even if it gets called outside of that
function.
Here’s another example:
const counterCreator = () => {
let count = 0;
return () => {
console.log(count);
count++;
};
};

const counter = counterCreator();

counter(); // 0
counter(); // 1
counter(); // 2
counter(); // 3

In this example, counterCreator initializes a local variable (count) and then returns
a function. To use that function, we have to assign it to a variable (line 9). Then,
every time we run the function it logs count to the console and increments it. Keep
in mind, counter() is calling the return value of counterCreator. As above, the
function counter is a closure. It has access to the variable count and can both print
and increment it, but there is no other way for our program to access that variable.
In the context of factory functions, closures allow us to create private variables and
functions. Private functions are functions that are used in the workings of our
objects that are not intended to be used elsewhere in our program. In other
words, even though our objects might only do one or two things, we are free to
split our functions up as much as we want (allowing for a cleaner, easier way to
read code) and only export the functions that the rest of the program is going to
use. Using this terminology with our printString example from earlier,
capitalizeString is a private function and printString is public.
The concept of private functions is very useful and should be used as often as is
possible! For every bit of functionality that you need for your program, there are
likely to be several supporting functions that do NOT need to be used in your
program as a whole. Tucking these away and making them inaccessible makes your
code easier to refactor, easier to test, and easier to reason about for you and
Javascript Page 90
code easier to refactor, easier to test, and easier to reason about for you and
anyone else that wants to use your objects.
Back to Factory Functions
Now that we’ve got the theory out of the way, let’s return to factory functions.
Factories are simply plain old JavaScript functions that return objects for us to use
in our code. Using factories is a powerful way to organize and contain the code
you’re writing. For example, if we’re writing any sort of game, we’re probably
going to want objects to describe our players and encapsulate all of the things our
players can do (functions!).
const Player = (name, level) => {
let health = level * 2;
const getLevel = () => level;
const getName = () => name;
const die = () => {
// uh oh
};
const damage = x => {
health -= x;
if (health <= 0) {
die();
}
};
const attack = enemy => {
if (level < enemy.getLevel()) {
damage(1);
console.log(`${enemy.getName()} has damaged ${name}`);
}
if (level >= enemy.getLevel()) {
enemy.damage(1);
console.log(`${name} has damaged ${enemy.getName()}`);
}
};
return {attack, damage, getLevel, getName};
};

const jimmie = Player('jim', 10);


const badGuy = Player('jeff', 5);
jimmie.attack(badGuy);

Take a minute to look through this example and see if you can figure out what’s
going on.

Javascript Page 91
going on.
What would happen here if we tried to call jimmie.die()? What if we tried to
manipulate the health: jimmie.health -= 1000? Well, those are things that we have
NOT exposed publicly so we would get an error. This is a very good thing! Setting
up objects like this makes it easier for us to use them because we’ve actually put
some thought into how and when we are going to want to use the information. In
this case, we have jimmie’s health hiding as a private variable inside of the object
which means we need to export a function if we want to manipulate it. In the long
run, this will make our code much easier to reason about because all of the logic is
encapsulated in an appropriate place.
Inheritance with factories
In the constructors lesson, we looked fairly deeply into the concept of prototypes
and inheritance, or giving our objects access to the methods and properties of
another object. There are a few easy ways to accomplish this while using factories.
Check this one out:
const Person = (name) => {
const sayName = () => console.log(`my name is ${name}`);
return {sayName};
}

const Nerd = (name) => {


// simply create a person and pull out the sayName function with destructuring
assignment syntax!
const {sayName} = Person(name);
const doSomethingNerdy = () => console.log('nerd stuff');
return {sayName, doSomethingNerdy};
}

const jeff = Nerd('jeff');

jeff.sayName(); //my name is jeff


jeff.doSomethingNerdy(); // nerd stuff

This pattern is great because it allows you to pick and choose which functions you
want to include in your new object. If you want to go ahead and lump ALL of
another object in, you can certainly do that as well with Object.assign (read the
docs for that one here).
const Nerd = (name) => {
const prototype = Person(name);
const doSomethingNerdy = () => console.log('nerd stuff');
return Object.assign({}, prototype, {doSomethingNerdy});
Javascript Page 92
return Object.assign({}, prototype, {doSomethingNerdy});
}

• Before moving on have a look at this article. In the second half of the article,
the author goes into some things that we aren’t really talking too much about
here, but you’ll be rewarded if you spend some time figuring out what he’s
talking about. Good stuff!

The Module Pattern


Quick sidenote: ES6 introduced a new feature in JavaScript called ‘modules’. These
are essentially a syntax for importing and exporting code between different
JavaScript files. They’re very powerful and we WILL be covering them later. They
are not, however, what we’re talking about here.
Modules are actually very similar to factory functions. The main difference is how
they’re created.
Meet a module:
const calculator = (() => {
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
const mul = (a, b) => a * b;
const div = (a, b) => a / b;
return {
add,
sub,
mul,
div,
};
})();

calculator.add(3,5); // 8
calculator.sub(6,2); // 4
calculator.mul(14,5534); // 77476

The concepts are exactly the same as the factory function. However, instead of
creating a factory that we can use over and over again to create multiple objects,
the module pattern wraps the factory in an IIFE (Immediately Invoked Function
Expression).
• Read up about IIFE’s in this article. The concept is simple: write a function,
wrap it in parentheses, and then immediately call the function by adding () to
the end of it.
• An example of creating and using a module pattern: JavaScript Module
Javascript Page 93
• An example of creating and using a module pattern: JavaScript Module
Pattern Basics.
• Additional example of creating and using a module pattern: Module pattern in
JavaScript.
• For those who prefer video lessons, here is an excellent YouTube series on
modular JS that covers most of the content in this guide: Modular Javascript.

In our calculator example above, the function inside the IIFE is a simple factory
function, but we can just go ahead and assign the object to the variable calculator
since we aren’t going to need to be making lots of calculators, we only need one.
Just like the factory example, we can have as many private functions and variables
as we want, and they stay neatly organized, tucked away inside of our module,
only exposing the functions we actually want to use in our program.
A useful side-effect of encapsulating the inner workings of our programs into
objects is namespacing. Namespacing is a technique that is used to avoid naming
collisions in our programs. For example, it’s easy to imagine scenarios where you
could write multiple functions with the same name. In our calculator example,
what if we had a function that added things to our HTML display, and a function
that added numbers and operators to our stack as the users input them? It is
conceivable that we would want to call all three of these functions add which, of
course, would cause trouble in our program. If all of them were nicely
encapsulated inside of an object, then we would have no trouble: calculator.add(),
displayController.add(), operatorStack.add().
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• Learning JavaScript Design Patterns by Addy Osmani

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.

Javascript Page 94
material above to find the answer.
• Describe common bugs you might run into using constructors.
• Write a factory method that returns an object.
• Explain how scope works in JavaScript (bonus points if you can point out what
ES6 changed!).
• Explain what Closure is and how it impacts private functions & variables.
• Describe how private functions & variables are useful.
• Use inheritance in objects using the factory pattern.
• Explain the module pattern.
• Describe IIFE. What does it stand for?
• Briefly explain namespacing and how it’s useful.

Javascript Page 95
Project: TIC TAC TOE
Thursday, July 7, 2022 2:06 PM

Introduction
We’re making a Tic Tac Toe game you can play in your browser!
Assignment
1. Set up your project with HTML, CSS and Javascript files and get the Git repo all
set up.
2. You’re going to store the gameboard as an array inside of a Gameboard
object, so start there! Your players are also going to be stored in objects… and
you’re probably going to want an object to control the flow of the game itself.
a. Your main goal here is to have as little global code as possible. Try tucking
everything away inside of a module or factory. Rule of thumb: if you only
ever need ONE of something (gameBoard, displayController), use a
module. If you need multiples of something (players!), create them with
factories.
3. Set up your HTML and write a JavaScript function that will render the contents
of the gameboard array to the webpage (for now you can just manually fill in
the array with "X"s and "O"s)
4. Build the functions that allow players to add marks to a specific spot on the
board, and then tie it to the DOM, letting players click on the gameboard to
place their marker. Don’t forget the logic that keeps players from playing in
spots that are already taken!
a. Think carefully about where each bit of logic should reside. Each little
piece of functionality should be able to fit in the game, player or
gameboard objects.. but take care to put them in “logical” places.
Spending a little time brainstorming here can make your life much easier
later!
5. Build the logic that checks for when the game is over! Should check for 3-in-a-
row and a tie.
6. Clean up the interface to allow players to put in their names, include a button
to start/restart the game and add a display element that congratulates the
winning player!
7. Optional - If you’re feeling ambitious create an AI so that a player can play
against the computer!
a. Start by just getting the computer to make a random legal move.
b. Once you’ve gotten that, work on making the computer smart. It is
possible to create an unbeatable AI using the minimax algorithm (read
about it here, some googling will help you out with this one)

Javascript Page 96
about it here, some googling will help you out with this one)
c. If you get this running definitely come show it off in the chatroom. It’s
quite an accomplishment!

Javascript Page 97
Classes
Thursday, July 7, 2022 2:09 PM

Introduction
JavaScript does not have classes in the same sense as other Object Oriented
languages like Java or Ruby. ES6, however, did introduce a syntax for object
creation that uses the class keyword. It is basically a new syntax that does the
exact same thing as the object constructors and prototypes we learned about in
the constructor lesson.
There is a bit of controversy about using the class syntax, however. Opponents
argue that class is basically just syntactic sugar over the existing prototype-based
constructors and that it’s dangerous and/or misleading to obscure what’s really
going on with these objects. Despite the controversy, classes are beginning to crop
up in real code bases that you are almost certainly going to encounter such as
frameworks like React.
Since we’ve already gone fairly in-depth with Constructors, you don’t have too
much left to learn here beyond the new syntax. If you choose to use classes in your
code (that’s fine!) you can use them much the same way as object constructors.
Learning Outcomes
After this lesson and completing the assignments, you will be able to:
• Describe the pros and cons of using classes in JavaScript.
• Briefly discuss how JavaScript’s object creation differs from a language like
Java or Ruby.
• Explain the differences between using a class to define a constructor and
other prototype methods.
• Explain what “getters” & “setters” are.
• Understand what computed names and class fields are.
• Describe function binding.
• Be able to use inheritance with classes.
• Briefly talk about the conflict in JS with functional programming and classes.

Assignment
1. This article is probably just about all you need to start using class syntax
confidently. “Getters and Setters” are a useful feature!
2. The MDN docs are, as usual, a great resource for going a little deeper. Look
especially at the ‘extends’ and ‘Mixins’ sections. React (and other frameworks)
uses classes in this way. You create your components and make them extend
the core React component which gives you access to all their built-in
functionality.
3. This article provides some pros and cons for classes. There are many people
Javascript Page 98
3. This article provides some pros and cons for classes. There are many people
who think that class syntax is misleading for Javascript, and thus Factory
Functions (from the previous lesson) are inherently better. WE are not saying
that classes are bad! We just want you to be informed on the opinions of both
sides.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• This playlist from Stephen Mayeux, explains ES6 Classes and some of their
methods with easy to follow examples.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Describe the pros and cons of using classes in JavaScript.
• Briefly discuss how JavaScript’s object creation differs from a language like
Java or Ruby.
• Explain the differences between using a class to define a constructor and
other prototype methods.
• Explain what “getters” & “setters” are.
• Understand what computed names and class fields are.
• Describe function binding.
• Be able to use inheritance with classes.
• Briefly talk about the conflict in JS with functional programming and classes.

Javascript Page 99
ES6 Modules
Thursday, July 7, 2022 2:12 PM

Introduction
Separate from the module pattern that we discussed in an earlier lesson,
“modules” is a feature that arrived with ES6. Browser support for this feature is
quite slim at this point, but is slowly improving, and until all modern browsers
support it, we can make it work using an external module bundler. ES6 modules
are starting to appear in many code bases around the net and getting them up and
running will give us a chance to explore some new parts of the JavaScript
ecosystem, so it’s going to be a worthy excursion!
Don’t be fooled! We’re going to cover much more than just the new module
syntax in this lesson! Before we can really use these modules, we’re going to have
to learn about npm and webpack, which are both topics that will be very useful to
you even beyond this lesson. In the end, the modules themselves are simple to
implement, so we’re going to take this chance to learn about a few other things.
Learning Outcomes
After completing this lesson, you will be able to:
• Explain what npm is and where it was commonly used before being adopted
on the frontend.
• Describe what npm init does and what package.json is.
• Know how to install packages using npm.
• Describe what a JavaScript module bundler like webpack is.
• Explain what the concepts “entry” and “output” mean as relates to webpack.
• Briefly explain what a development dependency is.
• Explain what “transpiling code” means and how it relates to front-end
development.
• Briefly describe what a task runner is and how it’s used in front-end
development.
• Describe how to write an npm automation script.
• Explain one of the main benefits of writing code in modules.
• Explain “named” exports and “default” exports.

The History of JavaScript


Why do we even need or want this stuff? What do you gain from all of this added
complexity? These are good questions.. with good answers.
• Read this article for a bit of a history lesson. It’s long, but it puts what we’re
doing here in great perspective. This article is a bit older, and those who have
Javascript Page 100
doing here in great perspective. This article is a bit older, and those who have
coded along with the example have frequently run into issues, so we don’t
suggest that you code along (you’ll be following along with the official
Webpack documentation later). Nevertheless, this article is extremely
important conceptually and really clarifies the ‘WHY’ of the rest of this lesson.
npm
The node package manager is a command-line tool that gives you access to a
gigantic repository of plugins, libraries and tools. If you have done our
Fundamentals course, you will probably have encountered it when you installed
the Jest testing framework to do our exercises.
Read through the npm links below but don’t worry about running any of the
commands on your computer. This section is about growing your awareness of
npm. You will have an opportunity to use what you learn here in upcoming
projects.
1. Take a couple minutes to read the About npm page - a great introduction to
npm.
2. This tutorial teaches you how to install packages with npm.
3. This tutorial covers the package.json file, which you can use to manage your
project’s dependencies.
4. Read this article on development dependencies to learn what they are and
how to use them.
5. If you run into trouble at any point you can check out the official docs page for
more tutorials and documentation.

Yarn?
At some point, you will probably run into Yarn - a replacement for the default npm.
For the most part, it does the same things, though it does have a few more
features. Recent versions of npm have incorporated some of the best features of
Yarn, so using it won’t offer you any real advantages at this point in your career. It
is a fine project, however, and may be worth your consideration in the future.
Webpack
Webpack is simply a tool for bundling modules. There is a lot of talk across the net
about how difficult and complex it is to set up and use, but at the moment our
needs are few and the setup is simple enough. In fact, you can see an example of
getting it up and running on the front page of their website.
Webpack is a very powerful tool, and with that power comes a decent amount of
complexity - just look at the sample config file on this page . Don’t let it scare
you off! The basic configuration is not difficult and proficiency with webpack.
To get us started, we are going to refer to the official documentation.
1. Code along with all of the steps of this tutorial (“Basic Setup” through
Javascript Page 101
1. Code along with all of the steps of this tutorial (“Basic Setup” through
“Conclusion”).
Let’s discuss what’s going on there. After installing webpack using npm, we set up
a simple project that required an external library (lodash - check it out here if it’s
new to you) using a simple script tag. The site lists a few reasons why this is
probably not ideal and then steps through using webpack to accomplish the same
thing.
There are a couple of key concepts to understanding how webpack works - entry
and output. In this example, we rearranged the files into a src and dist folder.
Technically we could have called those folders anything, but those names are
typical. src is our source directory. In other words, src is where we write all of the
code that webpack is going to bundle up for us. When webpack runs, it goes
through all of our files looking for any import statements and then compiles all of
the code we need to run our site into a single file inside of the dist folder (short for
distribution). Our entry file, then is the main application file that links (either
directly or indirectly) to all of the other modules in our project. In this example, it is
/src/index.js. The output file is the compiled version - dist/main.js.
• Browse this document for more details. We’ll talk plugins and loaders in
another lesson.
ES6 Modules (finally!)
Now that we (sorta) understand what webpack is doing it’s time to discuss the
module syntax. There are only 2 components to it - import and export.
• Take a moment to look at the docs for import and export.
Of course, the import statement is the same thing that you used during the
webpack tutorial! These things are simple to use.
// a file called functionOne.js
const functionOne = () => console.log('FUNCTION ONE!');

export { functionOne };
// another JS file
import { functionOne } from './functionOne';

functionOne(); // this should work as expected!

There are many benefits to writing your code in modules. One of the most
compelling is code reuse. If, for instance, you have written some functions that
manipulate the DOM in a specific way, putting all of those into their own file as a
‘module’ means that you can copy that file and re-use it very easily!
There are also the same benefits as when using factory functions or the module
pattern (the module pattern and ES6 modules are not the same things; this naming
Javascript Page 102
pattern (the module pattern and ES6 modules are not the same things; this naming
convention is frustrating). With the introduction of ES6 Modules, the module
pattern (IIFEs) is not needed anymore, though you might still encounter them in
the wild. By using ES6 modules, you can keep different parts of your code cleanly
separated, which makes writing and maintaining your code much easier and less
error-prone. Keep in mind that you can definitely export constructors, classes and
factory functions from your modules.
To pull it all together, let’s write a simple module and then include it in our code.
We are going to continue from where the webpack tutorial left off. Before
beginning, your file directory should look something like this:
├── dist
│ ├── main.js
│ └── index.html
├── src
│ └── index.js
├── package-lock.json
├── package.json
└── webpack.config.js

In addition, you should be able to bundle and run webpack by simply typing npx
webpack in the terminal, (or npm run build if you’re using the example project
created on the previous section.) .
Add a new file to the src directory called myName.js with the following contents:
const myName = (name) => 'Hi! My name is ' + name;

export default myName;

Then, in src/index.js, import and use your new function:


// import your function
import myName from './myName';

function component() {
const element = document.createElement('div');

// use your function!


element.textContent = myName('Cody');
return element;
}

document.body.appendChild(component());
Javascript Page 103
document.body.appendChild(component());

Easy! Now, if you run npx webpack in your project directory, your page should
show our new function being used.
There are 2 different ways to use exports in your code: named exports and default
exports. Which option you use depends on what you’re exporting. As a general
rule if you want to export multiple functions use named exports with this pattern:
// a file called myModule.js
const functionOne = () => 'ONE';
const functionTwo = () => 'TWO';

export {
functionOne,
functionTwo
};

And to import them:


// main js file in /src folder
import {functionOne, functionTwo} from './myModule';

Using this pattern gives you the freedom to only import the functions you need in
the various files of your program. So it’s perfectly fine to only import functionOne
if that’s the only one you need.
The various import/export methods are best explained in the docs that we linked
earlier - import and export.
Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Explain what npm is and where it was commonly used before being adopted
on the frontend.
• Describe what npm init does and what package.json is.
• Know how to install packages using npm.
• Describe what a JavaScript module bundler like webpack is.
• Explain what the concepts “entry” and “output” mean as relates to webpack.
• Briefly explain what a development dependency is.
• Explain what “transpiling code” means and how it relates to frontend
development.
• Briefly describe what a task runner is and how it’s used in frontend

Javascript Page 104


• Briefly describe what a task runner is and how it’s used in frontend
development.
• Describe how to write an npm automation script.
• Explain one of the main benefits of writing code in modules.
• Explain “named exports” and “default exports”.

Javascript Page 105


Web Pack
Thursday, July 7, 2022 2:17 PM

Introduction
We’ve already introduced webpack in a previous lesson. It is the go-to tool across
the web for bundling and compiling JavaScript code. There are other options out
there, but at this time none of them are as popular or widely used as webpack.
In our last lesson, we covered the first half of what webpack can do for you:
bundling your modules. Another amazing feature is webpack’s ability to process
and manipulate your code during the compilation step. So, for example, if you
would like to use Sass to write your CSS, webpack can do that for you. Webpack
can manage your images and compress and optimize them for use on the web.
Webpack can minify and uglify your code. There are tons of things webpack can
do, but to access these functions we need to learn more about loaders and plugins.
Learning Outcomes
After completing this lesson, you will be able to:
• Use webpack by following its documentation.
• Load assets with webpack.
• Manage output with webpack.
1. Go through this tutorial to see examples of using webpack to manage your
website’s assets.
2. Read through this tutorial to learn how to let webpack automatically manage
your index.html and insert your bundle into the page for you!
3. Finally, the first part of this tutorial talks about source maps, a handy way to
track down which source file (index.js, a.js, b.js) an error is coming from when
you use webpack to bundle them together. This is essential to debugging
bundled code in your browser’s DevTools. If the error comes from b.js the
error will reference that file instead of the bundle. It also walks through an
example of the --watch feature you definitely should have taken note of
above.
4. You don’t need to do the rest of the webpack tutorials at this time, but take a
look at what’s offered on the sidebar of their guides page. There are several
sweet features that you might want to use in future projects such as code-
splitting, lazy-loading, and tree-shaking. Now that you have a handle on
webpack’s configuration system adding these features is as easy as using the
right plugins and loaders!

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
Javascript Page 106
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• How do you load CSS using webpack?
• How do you load images using webpack?
• How do you load fonts using webpack?
• How do you load data using webpack?
• How would you track errors in bundled source code?

Javascript Page 107


Project: Restaurant Page
Thursday, July 7, 2022 2:19 PM

Introduction
Let’s use what we’ve learned and take a chance to continue practicing DOM
manipulation by dynamically rendering a simple restaurant homepage! By the end,
we are going to be using JavaScript alone to generate the entire contents of the
website!
Note: DOM elements should be created using JavaScript but styling can be done in
a separate CSS file.

Assignment
1. Start the project the same way you began the webpack tutorial project.
a. run npm init in your project directory to generate a package.json file.
b. run npm install webpack webpack-cli --save-dev to install webpack to the
node_modules directory of your project.
• Quick tip: the node_modules folder can get really big. It is customary to add
a .gitignore file to your project so that you don’t have to sync the contents of
node_modules to github. The dependencies that are stored there can be
installed from your package.json by running npm install, so you don’t need to
sync them.
a. Create a src and dist directory with the following contents:
b. an index.js file in src
c. an index.html file in dist. Go ahead and link the main.js file in a script tag.
main.js is the file that will be generated by webpack.
d. create a webpack.config.js file that looks just like our file from the tutorial.
1. Set up an HTML skeleton inside of dist/index.html with single <div
id="content">.
2. Inside of src/index.js write a simple console.log or alert statement and then
run npx webpack. Load up dist/index.html in a browser to make sure
everything is working correctly.
• Quick tip #2: if you run npx webpack --watch you will not have to rerun
webpack every time you make a change.
1. Create a bare-bones homepage for a restaurant. Include an image,
headline, and some copy about how wonderful the restaurant is. It’s okay
to hard-code these into the HTML for now just to see how they look on
the page.
2. Now remove those elements from the HTML (so leave only the <html>,
<body>, and <div id="content"> tags) and instead create them by using
Javascript Page 108
<body>, and <div id="content"> tags) and instead create them by using
JavaScript only, e.g. by appending each new element to div#content once
the page is first loaded. Since we’re all set up to write our code in
multiple files, let’s write this initial page-load function inside of its own
module and then import and call it inside of index.js.
3. Next, set up your restaurant site to use tabbed browsing to access the
Contact and Menu pages. Look at the behavior of this student solution
for visual inspiration.
a. Put the contents of each ‘tab’ inside of its own module. Each module will
export a function that creates a div element, adds the appropriate
content and styles to that element and then appends it to the DOM.
b. Write the tab-switching logic inside of index.js. You should have event
listeners for each tab that wipes out the current contents and then runs
the correct ‘tab module’ to populate it again.
1. If you are using GitHub pages to host your completed page you need to
do a tiny bit more work to get it to show up. After running webpack the
full bundled version of your site is available in the dist folder, but GH
pages is looking for an index.html in the root directory of your project.
a. Simply follow the instructions on this gist. EZPZ!
b. Recall that the source branch for GitHub Pages is set in your
repository’s settings.

Javascript Page 109


OOP Principles
Thursday, July 7, 2022 2:21 PM

Introduction
By this point, you will have learned and had a chance to practice the most common
object-creation and organization patterns in JavaScript. But that is just the tip of
the iceberg. More important than learning the syntax for factory functions or
modules is figuring out how to use them effectively.
This whole series of lessons has been about the “Object Oriented Programming”
paradigm (OOP). The basics of creating objects and classes are relatively
straightforward. But it is not straightforward to decide what to put in each object,
or when to make a new object, or when to let an object ‘inherit’ from another one.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain the “Single Responsibility Principle”.
• Briefly explain the additional SOLID principles.
• Explain what “tightly coupled” objects are and why we want to avoid them.
Luckily there are several concepts and principles that can guide us into making
good decisions when it comes to our objects. This lesson is an introduction to the
most important of those concepts. Keep in mind that there is not usually a very
clear answer to your application design questions. Some patterns and ideas are
obviously better than others, but there is often some trade-off when deciding
where to put a specific function. In other words.. these principles are not rules-
they’re helpful guidelines.
As you read these resources, it might help to go back to some projects you’ve
already done and think about how what you’ve written measures up to the
examples you see. And of course, as you move on, keep these things in mind when
crafting new projects.
Single Responsibility
As you craft your objects, one of the most important things to remember is the
Single Responsibility Principle which states that a class (or object or module.. you
get the point) should only have one responsibility. This doesn’t mean that an object
can only do one thing, but it does mean that everything an object does should be
part of one responsibility.
Here’s a really common example. Most of our code has functions to update and
write things to the DOM in addition to our application logic. It’s a really good idea
to separate your DOM stuff from the application logic.
Javascript Page 110
to separate your DOM stuff from the application logic.
So instead of this:
function isGameOver() {

// game over logic goes here!

if (gameOver){
const gameOverDiv = document.createElement('div');
gameOverDiv.classList.add('game-over');
gameOverDiv.textContent = `${this.winner} won the game!`;
document.body.appendChild(gameOverDiv);
}
}

You should extract all the DOM manipulation into its own module and use it like so:
function isGameOver() {

// game over logic goes here!

if (gameOver){
DOMStuff.gameOver(this.winner);
}
}

In fact - the function isGameOver shouldn’t be calling the DOM function anyway.
That should go elsewhere (directly in the game-loop).
Another way to think about the Single Responsibility Principle is that a given
method/class/component should have a single reason to change. Otherwise, if an
object is trying to have multiple responsibilities, changing one aspect might affect
another.
The Single Responsibility Principle is the first of a commonly found set of 5 design
principles called the SOLID principles. You will read more about these principles in
the assignment articles below.
Loosely Coupled Objects
Obviously, all of our objects are intended to work together to form our final
application. You should take care, however, to make sure that your individual
objects can stand alone as much as possible. Tightly coupled objects are objects
that rely so heavily on each other that removing or changing one will mean that
you have to completely change another one - a real bummer.

Javascript Page 111


This one is related pretty strongly to ‘Single Responsibility’ but takes a different
angle. As an example, if we were writing a game and wanted to completely change
how the User Interface worked, we should be able to do that without completely
reworking the game logic. So we should be able to start off writing our game using
primarily console.log()s and then add in a bunch of DOM functions later without
touching the game logic.
Assignment
1. The following articles mention the acronym SOLID before going on to talk
about Single Responsibility. Single Responsibility is definitely the most
relevant of the 5. Feel free to dig into the rest of the SOLID principles if you
like.. but pay special attention to Single Responsibility.
a. Read SOLID JavaScript: The Single Responsibility Principle. NOTE: This
article does make use of JQuery, one of the earliest and most popular
JavaScript libraries prior to the ES6 standard. While The Odin Project
does not teach JQuery and you are not expected to understand the
example, be sure to focus less on the code itself and more on the SOLID
concepts being expressed.
b. 5 Principles that will make you a SOLID JavaScript Developer hits the
same topic, and also covers the rest of ‘SOLID’ concisely.
c. And read S.O.L.I.D. The first 5 principles of Object Oriented Design with
JavaScript for good measure.
2. How to Write Highly Scalable and Maintainable JavaScript: Coupling explains
loosely coupled objects pretty well.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• The best book we’ve ever read on the subject of loose coupling is Practical Object-
Oriented Design In Ruby. Unfortunately, it is not free… and not JavaScript. We feel
confident in recommending it anyway. If you don’t know Ruby, it is a clear enough
language that you don’t really need to learn it to follow the examples and the
content of the book is sincerely fantastic. Alternatively, 99 Bottles of OOP is
written in both JavaScript and Ruby. It is written by the same author and may be a
better option if you are brand new to OOP (it is not free either).
• A nice summary of OOP’s most common principles using JavaScript

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Explain the “Single Responsibility Principle”.

Javascript Page 112


• Explain the “Single Responsibility Principle”.
• Briefly explain the additional SOLID principles.
• Explain what “tightly coupled” objects are and why we want to avoid them.

Javascript Page 113


Project: To do List
Thursday, July 7, 2022 2:24 PM

Introduction
At this point you’ve already had a fair amount of practice using the various
techniques we’ve shown you. But we’ve been throwing a lot of information your
way, so before we move on we’re going to take a minute to slow down and work
on one more great portfolio project.
The Todo List
Todo lists are a staple in beginning webdev tutorials because they can be very
simple. There is, however, a lot of room for improvement and many features that
can be added.
Before diving into the code, take a minute to think about how you are going to
want to organize your project.
Assignment
1. Your ‘todos’ are going to be objects that you’ll want to dynamically create,
which means either using factories or constructors/classes to generate them.
2. Brainstorm what kind of properties your todo-items are going to have. At a
minimum they should have a title, description, dueDate and priority. You
might also want to include notes or even a checklist.
3. Your todo list should have projects or separate lists of todos. When a user first
opens the app, there should be some sort of ‘default’ project to which all of
their todos are put. Users should be able to create new projects and choose
which project their todos go into.
4. You should separate your application logic (i.e. creating new todos, setting
todos as complete, changing todo priority etc.) from the DOM-related stuff, so
keep all of those things in separate modules.
5. The look of the User Interface is up to you, but it should be able to do the
following:
a. view all projects
b. view all todos in each project (probably just the title and duedate..
perhaps changing color for different priorities)
c. expand a single todo to see/edit its details
d. delete a todo
6. For inspiration, check out the following great todo apps. (look at screenshots,
watch their introduction videos etc.)
a. Todoist
b. Things
c. any.do
7. Since you are probably already using webpack, adding external libraries from
Javascript Page 114
7. Since you are probably already using webpack, adding external libraries from
npm is a cinch! You might want to consider using the following useful library
in your code:
a. date-fns gives you a bunch of handy functions for formatting and
manipulating dates and times.
8. We haven’t learned any techniques for actually storing our data anywhere, so
when the user refreshes the page, all of their todos will disappear! You should
add some persistence to this todo app using the Web Storage API.
a. localStorage (docs here) allows you to save data on the user’s computer.
The downside here is that the data is ONLY accessible on the computer
that it was created on. Even so, it’s pretty handy! Set up a function that
saves the projects (and todos) to localStorage every time a new project
(or todo) is created, and another function that looks for that data in
localStorage when your app is first loaded. Additionally, here are a couple
of quick tips to help you not get tripped up:
• Make sure your app doesn’t crash if the data you may want retrieve
from localStorage isn’t there!
• localStorage uses JSON to send and store data, and when you
retrieve the data, it will also be in JSON format. You will learn more
about this language in a later lesson, but it doesn’t hurt to get your
feet wet now. Keep in mind you cannot store functions in JSON, so
you’ll have to figure out how to add methods back to your object
properties once you fetch them. Good luck!

Javascript Page 115


JavaScript in Real World
Thursday, July 7, 2022 2:29 PM

Let's look at a few more practical applications of JavaScript and learn about a few
useful tools that are widely used in the industry.

Javascript Page 116


Linting
Thursday, July 7, 2022 2:29 PM

Style Guides
Code style is important! Having a consistent set of style rules for things such as
indentation or preferred quote style makes your code more maintainable and
easier to read. There are several popular JavaScript style guides on the net that set
standards for these types of things, and a little time spent reading them will make
you a better developer.
1. The Airbnb Style Guide is one of the most popular. It is also very well
formatted and easy to read.
2. Google also has their own style guide for JavaScript.
3. The JavaScript Standard Style. Used by companies like NPM and GitHub,
among others.

Learning Outcomes
• Set up a linter and prettier to make your code better.

Linting
The style guides we mentioned above are full of really helpful advice for
formatting, organizing and composing your code. But there are a lot of rules - it
can be difficult to internalize them all. Linters are tools that will scan your code
with a set of style rules and will report any errors to you that they find. In some
cases, they can even auto-fix the errors! The following articles explain in more
detail the benefits of using a linter while you code.
1. This article gets right to the point… start here!
2. This article goes a little further by discussing exactly how linters do what they
do.
There are multiple options for linting your JavaScript, but the most popular (and
most common in the industry) is eslint. Getting it installed and the initial set-up is
fairly simple.
1. The official ‘Getting Started’ page is a good place to start. It covers installation
and basic setup. The basic way to use this tool is to simply run the eslint
command in your terminal with a specific file.
2. Far more useful are linting plugins for your favorite text editor. Most editor
plugins allow you to automatically lint your code as you are writing it, and will
show the errors right in the editor, which makes resolving them much simpler.
We can’t cover every editor installation but some of the more popular are:

Javascript Page 117


We can’t cover every editor installation but some of the more popular are:
a. Visual Studio Code - The Plugin and a tutorial.
b. Sublime Text - The Plugin and a tutorial.
c. Atom - The Plugin and a tutorial.
d. Vim - Use the ALE plugin. If you use Vim you already know what you’re
getting into. ALE is a great plugin, but the setup and configuration can be
a little tricky.

Prettier
Prettier is awesome. It is similar to a linter, but serves a slightly different function.
Prettier will take your JS code and then automatically format it according to a set
of rules. Unlike a linter, it’s not looking for style errors, but specifically targeting
the layout of your code and making intelligent decisions about things like spaces,
indentation levels and line-breaks.
1. This quick talk from Prettier’s creator is a great introduction.
2.

3. Give it a test drive here. Go ahead and copy/paste some of your old JavaScript
code into that editor and see what happens.
4. Setup is simple. The homepage links to tutorials for most popular editors.
Using prettier makes coding faster and easier! You don’t have to worry about
nailing things like indentation, or remembering every semi-colon because prettier
will take care of those details for you.
Knowledge check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is linting?
• Which problems can linting prevent?
• Why should you use Prettier?

Javascript Page 118


Dynamic User Interface Interactions
Thursday, July 7, 2022 2:32 PM

Introduction
JavaScript is a very powerful language. It is capable of creating complex web
applications that work everywhere. But it is just as often used on a smaller scale.
JavaScript is the glue that holds even less flashy websites together- it makes drop-
downs drop down and image sliders slide.
Fortunately, at this point, you already have all the tools you need to make these
items without resorting to using a bloated framework like bootstrap. (Nothing
against bootstrap… you just do not need it! Good for you!)
We aren’t presenting any new content in this lesson - just giving you the chance to
practice some of the techniques that you’re going to be using on a daily basis as a
JavaScript programmer.
Animations are typically handled by CSS which is a little out of the scope of this
lesson, but interactive stuff like this is no fun without a little motion! If you want to
take a break and learn more about making stuff move go watch this video.

Learning Outcomes
• Practice everyday techniques used by JavaScript programmers.

Drop-down Menus
You know what we’re talking about here. Picture a nav-bar or a button and when
you click it the menu slides down nicely. As mentioned previously, you already
know everything you need to create this element. Here are some things to keep in
mind:
1. You can allow the menu to show up either on click or on hover.
2. You should hard-code the menu items into your HTML but hide/reveal them

Javascript Page 119


2. You should hard-code the menu items into your HTML but hide/reveal them
using JavaScript. You can do this either by adding a class (visible or something)
or by manually setting the style in JS.
3. Make sure the code is reusable! You should be able to create multiple drop-
downs on a page without repeating the JavaScript code.
4. If you bundle your code into a module you can publish it to npm and then
install and use it anytime you like! Nothing like publishing your own modules
to make you feel like a pro .

Mobile menus
Mobile versions of your sites are almost definitely going to need their own menu
implementation. Depending on how you decided to implement your drop-down,
you could reuse it here, but there are tons of more inventive options out there.
1. Browse the web for some inspiration, pick something and try to implement it!

Image slider
Again, there’s not much instruction needed here - just practice.
Create a simple image carousel. It should contain arrows on each side to advance
the image forward or backward. It should automatically move forward every 5
seconds. It should contain the little navigation circles at the bottom that indicate
which slide you are on (and they should be click-able to advance to that particular
slide).
Don’t spend too much time worrying about getting your images to display at the
correct size – it’s more important to get the slider sliding.
1. This one is a little more involved than the last two, so think about how you
would set up the different elements within the site.
2. Set up a very wide div which will contain the individual “slides” of each image.
By appropriately positioning that div inside a container div (which acts like a
picture frame), you can choose which slide is visible at any given time.
3. Once you have the slider positioned properly, build functions for “next” and
“previous” which will advance to the next or previous slide accordingly. Make
the transitions smooth using simple effects.
4. Set up arrow buttons which activate those functions and play with cycling
through the images.
5. Add in some navigation dots at the bottom of the slides. Make a horizontal
series of empty circles with CSS immediately below the slideshow. Each circle
represents a slide, so whenever a new slide is activated, its corresponding
circle gets filled in so you can tell where in the show you are. Make each circle
link to that particular slide, so you can click on the circle and it will jump to
that slide.
6. Add a timeout which advances the slides every 5 seconds.
Javascript Page 120
6. Add a timeout which advances the slides every 5 seconds.
7. Play around with your slideshow!

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What are some different types of navigation menus?
• What are the alternatives to hamburger menus?
• What are the downsides of hamburger menus?

Javascript Page 121


Form Validation with JavaScript
Thursday, July 7, 2022 2:35 PM

Introduction
Forms are a crucial part of most websites. Almost every major site has sign-up
forms, contact forms, search forms and more! Luckily HTML5 and JavaScript have
some handy built-in methods.
In this lesson, we’ll cover the Constraint Validation API: a way to validate forms on
the frontend with JavaScript.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Understand the importance of validation in HTML forms.
• Understand Constraint Validation API for more control over form validation.
• Add validation using only JavaScript.

Assignment
1. This tutorial on Form Validation covers how we can use JavaScript to validate
forms, including the constraint validation API.
2. It’ll also prove beneficial to go through the Constraint Validation docs.
3. For Reference, this document covers the JavaScript validation API in a more
concise format. These functions were explained in the previous article. Typically,
with HTML forms, the inputs are validated upon form submission, but you can use
these functions to check validity whenever you like (such as when a user clicks or
tabs out of a specific input field).

Practice
Project
Build a browser form which collects Email, Country, Zip Code, Password and
Password Confirmation fields. It should use live inline validation to inform the user
whether a field is properly filled in or not. That means highlighting a field red and
providing a helpful error message until it has been filled in properly.
The form doesn’t need to actually submit, but you should give an error message if
the button is pushed with any active errors or unfilled required fields. For the sake
of this lesson, make sure all of the validation occurs in the JavaScript file. If all is
well and the form is “submitted”, give the user a high five.
1. Set up a blank HTML document
2. Think about how you would set up the different form elements and their
accompanying validators. What objects and functions will you need? A few
minutes of thought can save you from wasting an hour of coding. The best

Javascript Page 122


minutes of thought can save you from wasting an hour of coding. The best
thing you can do is whiteboard the entire solution before even touching the
computer.
3. Write the simple form elements.
4. Add the JavaScript code that checks validation as the user progresses through
the form. When a user leaves a form field, it should automatically validate
that field.
5. Test out all possible cases.
6. Don’t forget to style validations with CSS by using the :valid and :invalid
psuedo-classes!

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Understand the importance of validating HTML forms before submitting them
to a server.
• Describe the two types of client-side form validation, built-in form validation
and validation using JavaScript.
• Understand JavaScript Constraint Validation API provides more control and
customization of form validation.
• Use JavaScript to write custom error messages and add custom styling to the
errors.
• Understand forms can also be validated without using Constraint Validation
API, which is useful in certain cases.

Javascript Page 123


What is ES6?
Thursday, July 7, 2022 2:37 PM

Introduction
We’ve been throwing around the term ES6 since our very first lessons, but we
haven’t taken the time to properly explain what it means or to investigate the
implications of it in our code.
Put simply, ES6 is a version of JavaScript that was officially released in the summer
of 2015. It included many new features that make writing JavaScript much easier
and cleaner. If you have been following our lessons you have already been learning
these new features because, well, ES6 is just JavaScript.
You have probably also come across articles talking about features in ES7 or ES8 or
ES2015 or ES2017 etc. Part of the confusion here is that right after the release of
ES6, the committee that makes these decisions changed the naming scheme from
‘version numbers’ (ES5, ES6, ES7 etc.) to ‘release years’ (ES2015, ES2016, ES2017
etc.)
• This article provides a nice clean explanation and timeline of the various
ECMAScript releases.
• This document outlines all the new features that showed up in ES6. As we’ve
mentioned you’ve already been using many of these, though there are a few
we haven’t specifically covered yet.
The problem with JavaScript constantly updating and adding features is that it
sometimes takes web-browsers a while to catch up and implement new features
once they’ve been released. At the current time all modern browsers (Chrome,
Firefox, Safari and Edge) support all of ES6, and most of ES7, but older browsers
(various versions of Internet Explorer for instance) do not. This means,
unfortunately, that if you write code that uses these new features it will not run in
browsers that do not support it.
For most of us, this has not been an issue because you are almost definitely using a
new browser that automatically updates itself when a new version is released. But
in the real world, if you’re selling products to customers you can’t control which
browsers people will use to connect to your site.
Fortunately there is solution to this problem. Babel is a tool that takes your
modern JavaScript code and transpiles it to code that older browsers can
understand. It can be used from the command line with a simple command, and
can also easily be added to your webpack configuration. With the babel-loader.
In all honesty, this is not something that you are going to need to worry about on
every project you’re starting. All the ES6 features are present in the large majority
of browsers used worldwide. But JavaScript is constantly changing, and as new
Javascript Page 124
of browsers used worldwide. But JavaScript is constantly changing, and as new
features are announced and released, you can use Babel to try them out, often
before they’re available in any browser!
• Follow the instructions here to install the babel-loader and use it with
webpack. If you’ve already got webpack up and running in a project, adding
babel is a cinch!
• Read this this article to better understand presets and plugins in Babel. It will
also show you how to target specific browser versions you want to support.

Javascript Page 125


Asynchronous JavaScript and APIs
Thursday, July 7, 2022 2:38 PM

This section explores asynchronous JavaScript and event loops, and how it's useful in
fetching data from web servers using APIs.

Javascript Page 126


JSON
Thursday, July 7, 2022 2:39 PM

Introduction
JSON (JavaScript Object Notation) is a standardized format for structuring data. It is
heavily based on the syntax for JavaScript objects. You will often encounter JSON
formatted data when working with external servers or APIs - it is essentially the
universal format for transmitting data on the web.
Fortunately, there isn’t much to learn here. We’re only including a lesson on it
because some formatting rules can cause confusion if you aren’t aware of them.
Spend 10-15 minutes going through the following resources and you’ll be good to
go.

Assignment
1. This MDN tutorial is probably all you need…
2. Read about the 2 JavaScript methods that you’ll most often be using when
dealing with JSON - JSON.parse() and JSON.stringify().
3. Mis-formatted JSON is a common cause of errors. This webpage lets you paste
in JSON code and will search it for formatting errors.

Javascript Page 127


Asynchronous Code
Thursday, July 7, 2022 2:39 PM

Introduction
Since JavaScript is the language of the web, there are some functions that by
necessity are going to take a decent amount of time to complete, such as fetching
data from a server to display on your site. For this reason, JavaScript includes
support for asynchronous functions, or to put it another way, functions that can
happen in the background while the rest of your code executes.
Learning Outcomes
By the end of this lesson, you should be able to:
• Explain what a callback is
• Explain what a promise is
• Explain the circumstances under which promises are better than callbacks
• Explain what the .then() function does

Callbacks
In the recent past, the way that these were most commonly handled were with
callbacks, and even now they are still used quite a lot in certain circumstances.
A callback function is a function passed into another function as an argument,
which is then invoked inside the outer function to complete some kind of routine
or action. MDN
Callbacks are simply functions that get passed into other functions. For example:
myDiv.addEventListener("click", function(){
// do something!
})

Here, the function addEventListener() takes a callback (the “do something”


function) and then calls it when myDiv gets clicked.
You will likely recognize this pattern as something that happens all the time in
JavaScript code. Unfortunately, though they are useful in situations like the above
example, using callbacks can get out of hand, especially when you need to chain
several of them together in a specific order. The rest of this lesson discusses
patterns and functions that will help keep you out of Callback hell.
Take a moment to skim through this article before moving on. Or, if you prefer a
Javascript Page 128
Take a moment to skim through this article before moving on. Or, if you prefer a
video watch this.

Promises
There are multiple ways that you can handle asynchronous code in JavaScript, and
they all have their use cases. Promises are one such mechanism, and they’re one
you will see somewhat often when using other libraries or frameworks. Knowing
what they are and how to use them is quite useful.
Essentially, a promise is an object that might produce a value at some point in the
future. Here’s an example:
Lets say getData() is a function that fetches some data from a server and returns it
as an object that we can use in our code:
const getData = function() {
// go fetch data from some API...
// clean it up a bit and return it as an object:
return data
}

The issue with this example is that it takes some time to fetch the data, but unless
we tell our code that, it assumes that everything in the function happens
essentially instantly. So, if we try to do this:
const myData = getData()
const pieceOfData = myData['whatever']

We’re going to run into trouble because when we try to extract pieceOfData out of
the returned data, the function getData() will most likely still be fetching, so
myData will not be the expected data, but will be undefined. Sad.
We need some way to solve this problem, and tell our code to wait until the data is
done fetching to continue. Promises solve this issue. We’ll leave learning the
specific syntax for the articles you’re about to read, but essentially Promises allow

Javascript Page 129


specific syntax for the articles you’re about to read, but essentially Promises allow
you to do this:
const myData = getData() // if this is refactored to return a Promise...

myData.then(function(data){ // .then() tells it to wait until the promise is resolved


const pieceOfData = data['whatever'] // and THEN run the function inside
})

Of course, there are many more occasions where one would want to use Promises
beyond fetching data, so learning these things now will be very useful to you.

Assignment
1. Read this article. It’s a good starting place and it’s short and to the point.
2. Watch this video. It’s a good place to get a feel for how one might actually use
promises in the wild. Feel free to watch the other videos in the series, but
they aren’t strictly needed at this point. The video also mentions the ES5/ES6
issue, don’t worry about that at this point either. All major browsers support
Promises and we will teach you how to support older browsers in a later
lesson.
3.

4. Watch this video to understand how asynchronous code works in JavaScript.


5.

6. Read Chapter 2: Callbacks and Chapter 3: Promises from You Don't Know JS. In
Chapter 2, the author explains the problems with callbacks and why callback

Javascript Page 130


Chapter 2, the author explains the problems with callbacks and why callback
hell will be your worst enemy (hint: it’s the inversion of control and non-linear
nature of callbacks). In Chapter 3, you go deep into the how and why of
promises. This chapter is not the easiest read, but you’ll be a promise
professional if you take the time to properly digest it. It’s worth the effort.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
1. This is another useful article about Callback functions in JavaScript.
2. The MDN Documentation for Promises. It might not be the best resource for
learning all about them, but once you’ve read a more friendly article or
tutorial, this will probably be the place you return to for a refresher.
3. This video and this one too are both nice introductions to Promises if you
need more repetition.
4.

5.

6. This tutorial is another good introduction.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is a callback?

Javascript Page 131


• What is a callback?
• What is a promise?
• When should you use promises over callbacks?
• What does the .then() function do?

Javascript Page 132


Working with APIs
Thursday, July 7, 2022 2:44 PM

Introduction
One of the most powerful things a web developer can do is fetching data from a
server and displaying it creatively on their site. In many cases, the server solely
exists for that specific site. The server could contain blog posts, user data, high
scores for a game or anything else. In other cases, the server is an open service
that serves data to anyone that wants to use it (i.e. weather data or stock prices).
In either case, the methods of accessing and then using that data are essentially
the same.
Learning Outcomes
By the end of this lesson, you should be able to:
• Explain what an API is
• Explain broadly how access to an API works
• Explain how to fetch and extract data from an API
• Explain why your API request might be blocked by the browser, and how to fix
this
APIs
Servers that are created for serving data for external use (in websites or apps) are
often referred to as APIs or ‘Application Programming Interfaces’.

There are multiple ways of requesting data from an API, but all of them basically do
the same thing. For the most part, APIs are accessed through URLs, and the
specifics of how to query these URLs change based on the specific service you are
using. For example, the OpenWeatherMap API has several types of data that you
can request. To get the current weather in a specific location, you can pass in the
name of a city (optionally, you can also add a state code or a country code) as a
URL query string parameter, like so:
api.openweathermap.org/data/2.5/weather?q=London

Javascript Page 133


api.openweathermap.org/data/2.5/weather?q=London

The specifics for using any API are usually documented on the service’s website.
Check here for the OpenWeatherMap API documentation. If you haven’t already,
go ahead and paste the weather URL above, with the city of your choice, into your
browser…(we’ll wait).
You’ll probably get an error like this:
{"code":401, "message": "Invalid API key. Please see
http://openweathermap.org/faq#error401 for more info."}

This brings us to another point about APIs. In most cases, you will have to create an
account and request an “API key” from the API service before attempting to fetch
data from their endpoints. Once obtained, an API key will usually have to be
included with every data request, such as another URL query string parameter:
http://api.openweathermap.org/data/2.5/weather?q=London&APPID=
1111111111

As you can imagine, an API key is random and unique to you. As such, services like
OpenWeatherMap can correlate your API key to your requests of their data,
including how much and how often you are requesting it.
On one hand, issuing API keys allows an API service to better track abuse of their
systems and data. On the other hand, it can also be a way for those services to
mitigate and recuperate operating costs. OpenWeatherMap, for example, provides
not only a free tier but a variety of paid tiers that can cost upwards of 2000
USD/month! After all, running servers costs money, and APIs are no exception.
While a single request to an API might cost a fraction of a penny, imagine using
that API to create an amazing weather app that gets used all over the world….you
could easily have thousands of people accessing that data every minute! The cost
to handle that traffic could quickly balloon up to significant sums for the API
service.
As such, you’ll find that most API services, if not all, provide paid tiers that come
with the ability to make more frequent requests, or provide access to more
information unavailable in lower tiers. For example, OpenWeatherMap’s free plan
only allows your app to make 60 requests per minute, for a monthly total of 1
million requests, while the “Enterprise” tier allows up to 200,000 requests per
minute! The free tier also comes with basic forecasting data, but it does not
include data for a 30-day forecast (details here if you’re interested). So, if your app
becomes successful and needs additional features, you’ll probably need to pay for
a better account.
Because your API key is your key to these services and data, securing them is an

Javascript Page 134


Because your API key is your key to these services and data, securing them is an
important habit, especially if you are using a paid tier. There are plenty of bots that
crawl GitHub repositories solely for hardcoded/unsecured API keys, allowing bad
agents to then access and utilize the services and data you’ve paid for. In fact, the
more eagle-eyed readers may have noticed a problem with the demonstration
above: The API key is right there in the URL request. It would not take much for an
internet traffic sniffer to pick up on the API key, least of all someone looking over
your shoulder!
At this point in the curriculum, though, this point is largely moot. After all, we’re
leveraging free access to APIs, and the majority of our apps are only going to be
used by us and the people that view our portfolios. Just make a note of the severe
limitations of using API keys as demonstrated above for now. The basics of
securing and obfuscating API keys from GitHub and from your requests will be
covered later in the curriculum.
Back to OpenWeatherMap. Go ahead and create an account to obtain an API key
from their free tier. Once the key has been activated, which can take up to 2 hours,
try making a new request with the city of your choice AND the API key passed in as
query string parameters, like the example above. You’ll hopefully see a proper
response, something like:
{"coord":{"lon":-77.73,"lat":38.77},"weather":[{"id":800,"main":"Clear","description
":"clear
sky","icon":"01d"}],"base":"stations","main":{"temp":75.74,"pressure":1017,"humi
dity":57,"temp_min":71.6,"temp_max":78.8},"visibility":16093,"wind":{"speed":3.8
7,"deg":291},"clouds":{"all":1},"dt":1504188900,"sys":{"type":1,"id":2886,"message
":0.0053,"country":"US","sunrise":1504175992,"sunset":1504222878},"id":477566
0,"name":"New Baltimore","cod":200}

Congratulations on making your first API request!


Fetching Data
So how do we actually get the data from an API into our code?
A couple of years ago the main way to access API data in your code was using an
XMLHttpRequest. This function still works in all browsers, but unfortunately, it is
not particularly nice to use. The syntax looks something like this:
// Just getting XHR is a mess!
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}

Javascript Page 135


}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e) {}
}
}

// Open, send.
request.open('GET', 'https://url.com/some/url', true);
request.send(null);

Ouch. That was painful.


Developers, feeling the pain of having to write that stuff out, began writing 3rd
party libraries to take care of this and make it much easier to use. Some of the
more popular libraries are axios and superagent, both of which have their
strengths and weaknesses.
More recently, however, web browsers have begun to implement a new native
function for making HTTP requests, and that’s the one we’re going to use and stick
with for now. Meet fetch:
// URL (required), options (optional)
fetch('https://url.com/some/url')
.then(function(response) {
// Successful response :)
})
.catch(function(err) {
// Error :(
});

In case you’ve forgotten, scroll back up and look at how you would use XHR to do
the same thing. While you’re admiring how nice and clean that code is, notice
the .then() and .catch() functions there. Do you remember what those are?
(PROMISES!)
Let’s change up our API for this example. We’re going to walk through an example
using fetch with the giphy API to display a random gif on a webpage. The API
requires you to sign up and get a free API key, so go ahead and do that here.
Giphy has several methods for searching and finding gifs which you can read about
in their documentation. Today we’re just going to use the ‘translate’ endpoint
because it’s the simplest one for our purposes. You can find the appropriate URL in

Javascript Page 136


because it’s the simplest one for our purposes. You can find the appropriate URL in
their documentation by scrolling down here. What it tells us is that the correct URL
is api.giphy.com/v1/gifs/translate and that it requires 2 parameters, your api_key
and a search term. If you put it all together correctly (with YOUR API key) you
should get something like this:
'https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats'
// of course we're searching for cats

Go ahead and try that URL (with YOUR API key) in a browser. If everything goes
well you should get a relatively long string of data and no errors.
CORS
A side note before we start putting this into our code. For security reasons, by
default, browsers restrict HTTP requests to outside sources (which is exactly what
we’re trying to do here). There’s a very small amount of setup that we need to do
to make fetching work. Learning about this is outside our scope right now, but if
you want to learn a bit about it this Wikipedia article and this Javascript.info article
are good starting points.
Whether or not you took the detour to learn all about Cross Origin Resource
Sharing (CORS) the fix is simple. With fetch, you are able to easily supply a
JavaScript object for options. It comes right after the URL as a second parameter to
the fetch function:
fetch('url.url.com/api', {
mode: 'cors'
});

Simply adding the {mode: 'cors'} after the URL, as shown above, will solve our
problems for now. In the future, however, you may want to look further into the
implications of this restriction.
Let’s Do This
For now, we’re going to keep all of this in a single HTML file. So go ahead and
create one with a single blank image tag and an empty script tag in the body.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<img src="#">

Javascript Page 137


<img src="#">
<script>
</script>
</body>
</html>

In the script tag, let’s start by selecting the image and assigning it to a variable so
that we can change the URL once we’ve received it from the Giphy API.
<script>
const img = document.querySelector('img');
</script>

Adding fetch with our URL from above is also relatively easy:
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats',
{mode: 'cors'})
.then(function(response) {
console.log(response.json());
});
</script>

You should now be able to open the HTML file in your browser, and while you
won’t see anything on the page, you should have something logged in the console.
The trickiest part of this whole process is deciphering how to get to the data you
desire from the server’s response. In this case, inspecting the browser’s console
will reveal that what’s being returned is another Promise… to get the data we need
another .then() function.
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats',
{mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
console.log(response);
});
</script>

Javascript Page 138


Now we have a JavaScript object and if you inspect it closely enough you’ll find that
the data we need (an image URL) is nested rather deeply inside the object:

To get to the data we need to drill down through the layers of the object until we
find what we want!
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats',
{mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
console.log(response.data.images.original.url);
});
</script>

Running the file should now log the URL of the image. All that’s left to do is set the
source of the image that’s on the page to the URL we’ve just accessed:
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats',
{mode: 'cors'})
.then(function(response) {

Javascript Page 139


.then(function(response) {
return response.json();
})
.then(function(response) {
img.src = response.data.images.original.url;
});
</script>

If all goes well, you should see a new image on the page every time you refresh!
If you’ve gotten lost along the way, check out this jsbin project. Besides the
glorious styling, this is what your version should look like.
While we are pushing this API key to the frontend, this isn’t something you should
do with any key that is not free, anything on the client is public knowledge.
Handling keys that are unsafe to push to the frontend will be taught in later
sections if you haven’t been exposed in the Ruby course.
Assignment
1. Read the fetch documentation here. It’s not all that complicated to use, but
we’ve only really scratched the surface at this point.
2. Check out this list and this list of free, open APIs and let your imagination go
wild.
3. Expand on our little project here by adding a button that fetches a new image
without refreshing the page.
4. Add a search box so users can search for specific gifs. You should also
investigate adding a .catch() to the end of the promise chain in case Giphy
doesn’t find any gifs with the searched keyword. Add a default image, or an
error message if the search fails.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is an API?
• How is access to an API restricted?
• How do you fetch and extract data from an API?
• Why might your API request be blocked by the browser, and how might you
fix this?

Javascript Page 140


Async and Await
Thursday, July 7, 2022 2:49 PM

Introduction
Asynchronous code can become difficult to follow when it has a lot of things going
on. async and await are two keywords that can help make asynchronous read
more like synchronous code. This can help code look cleaner while keeping the
benefits of asynchronous code.
For example, the two code blocks below do the exact same thing. They both get
information from a server, process it, and return a promise.
function getPersonsInfo(name) {
return server.getPeople().then(people => {
return people.find(person => { return person.name === name });
});
}
async function getPersonsInfo(name) {
const people = await server.getPeople();
const person = people.find(person => { return person.name === name });
return person;
}

The second example looks much more like the kind of functions you are used to
writing. However, did you notice the async keyword before the function
declaration? How about the await keyword before server.getPeople()?
Learning Outcomes
By the end of this lesson, you should be able to:
• Explain how you declare an async function
• Explain what the async keyword does
• Explain what the await keyword does
• Explain what an async function returns
• Explain what happens when an error is thrown inside an async function
• Explain how you can handle errors inside an async function

The async keyword


The async keyword is what lets the JavaScript engine know that you are declaring
an asynchronous function. This is required to use await inside any function. When
a function is declared with async, it automatically returns a promise; returning in
an async function is the same as resolving a promise. Likewise, throwing an error
will reject the promise.

Javascript Page 141


will reject the promise.
An important thing to understand is async functions are just syntactical sugar for
promises.
The async keyword can also be used with any of the ways a function can be
created. Said differently: it is valid to use an async function anywhere you can use
a normal function. Below you will see some examples that may not be intuitive. If
you don’t understand them, come back and take a look when you are done with
the assignments.
const yourAsyncFunction = async () => {
// do something asynchronously and return a promise
return result;
}
anArray.forEach(async item => {
// do something asynchronously for each item in 'anArray'
// one could also use .map here to return an array of promises to use with
'Promise.all()'
});
server.getPeople().then(async people => {
people.forEach(person => {
// do something asynchronously for each person
});
});

The await keyword


await is pretty simple: it tells JavaScript to wait for an asynchronous action to finish
before continuing the function. It’s like a ‘pause until done’ keyword. The await
keyword is used to get a value from a function where you would normally
use .then(). Instead of calling .then() after the asynchronous function, you would
simply assign a variable to the result using await. Then you can use the result in
your code as you would in your synchronous code.
Error Handling
Handling errors in async functions is very easy. Promises have the .catch() method
for handling rejected promises, and since async functions just return a promise,
you can simply call the function, and append a .catch() method to the end.
asyncFunctionCall().catch(err => {
console.error(err)
});

But there is another way: the mighty try/catch block! If you want to handle the

Javascript Page 142


But there is another way: the mighty try/catch block! If you want to handle the
error directly inside the async function, you can use try/catch just like you would
inside synchronous code.
async function getPersonsInfo(name) {
try {
const people = await server.getPeople();
const person = people.find(person => { return person.name === name });
return person;
} catch (error) {
// Handle the error any way you'd like
}
}

Doing this can look messy, but it is a very easy way to handle errors without
appending .catch() after your function calls. How you handle the errors is up to
you, and which method you use should be determined by how your code was
written. You will get a feel for what needs to be done over time. The assignments
will also help you understand how to handle your errors.
Practice
Remember the Giphy API practice project? (If not, you should go back and
complete the API lesson). We are going to convert the promise based code into
async/await compatible code. Here’s a refresher of the code we are starting with:
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats',
{mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
img.src = response.data.images.original.url;
});
</script>

Since await does not work on the global scope, we will have to create an async
function that wraps our API call to Giphy.
<script>
const img = document.querySelector('img');

async function getCats() {

Javascript Page 143


async function getCats() {
fetch('https://api.giphy.com/v1/gifs/translate?
api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
img.src = response.data.images.original.url;
})
}
</script>

Now that we have a function that is asynchronous, we can then start refactoring
from using promises to using await:
<script>
const img = document.querySelector('img');

async function getCats() {


const response = await fetch('https://api.giphy.com/v1/gifs/translate?
api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
response.json().then(function(response) {
img.src = response.data.images.original.url;
});
}
</script>

Since response is still the same object we have passed to the .then() block at the
start, we still need to use the .json() method, which in turn returns a promise.
Because .json() returns a promise, we can use await to assign the response to a
variable.
<script>
const img = document.querySelector('img');

async function getCats() {


const response = await fetch('https://api.giphy.com/v1/gifs/translate?
api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
const catData = await response.json();
img.src = catData.data.images.original.url;
}
</script>

Javascript Page 144


To use this function, we just simply need to call it with getCats() in our code.
<script>
const img = document.querySelector('img');

async function getCats() {


const response = await fetch('https://api.giphy.com/v1/gifs/translate?
api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
const catData = await response.json();
img.src = catData.data.images.original.url;
}
getCats();
</script>

This code will behave exactly like the code from the last lesson; it just looks a bit
different after refactoring. async/await are very useful tools when it comes to
cleaning up asynchronous JavaScript code. It is important to remember
async/await are just promises written in a different way. Do the assignments
below, and dive deeper into the understanding of async/await.
Assignment
1. Read this article for a solid introduction to async/await. This article also has
some good examples of its use.
2. Read this article for a more in-depth look at async/await, including how to
handle errors.
3. Watch this video for a good overview on async/await and its purpose, along
with a special trick.
4.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
1. This video is an example of how you can change callbacks, to promises, to

Javascript Page 145


1. This video is an example of how you can change callbacks, to promises, to
async/await.
2.

3. This video gives a comprehensive view of Promises, async, and await.


4.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• How do you declare an async function?
• What does the async keyword do?
• What does the await keyword do?
• What is returned from an async function?
• What happens when an error is thrown inside an async function?
• How can you handle errors inside an async function?

Javascript Page 146


Project: Weather App
Thursday, July 7, 2022 2:51 PM

Introduction
Use everything we’ve been discussing to create a weather forecast site using the
weather API from the previous lesson. You should be able to search for a specific
location and toggle displaying the data in Fahrenheit or Celsius.
You should change the look of the page based on the data, maybe by changing the
color of the background or by adding images that describe the weather. (You could
even use the Giphy API to find appropriate weather-related gifs and display them).
Feel free to use promises or async/await in your code, though you should try to
become comfortable with both.
API Keys, Secrets, and Security
Not all APIs are free, and depending on how they’re set up, they can cost money
per use. This makes them a prime target for people looking to use the API without
paying by using your API key. They can also be rate-limited, and if someone has
access to your API key they can use up all of your uses. One way to prevent this
issue is to store your API keys on the server and never send them to the frontend
in the first place, this is often done using environment variables and it makes the
key available only on the server the code is deployed to.
When talking about API keys and security you’ll often hear “Never trust the client”
(client meaning the frontend). Often this means not to trust that data coming from
the client is valid, but it also means that you cannot trust anything we send to the
client. Because of this, when you leak an API key, Github will alert you that you
have committed an API key publicly. After following this project, and indeed
exposing the API key, you may notice that Github will send you this alert. This is
totally OK for this project as this API key is publicly available and there is no
consequence for exposing it. This is not to say ALL keys are this way. Later during
the backend courses you will learn ways to securely deal with these topics.
Assignment
1. Set up a blank HTML document with the appropriate links to your JavaScript
and CSS files.
2. Write the functions that hit the API. You’re going to want functions that can
take a location and return the weather data for that location. For now, just
console.log() the information.
3. Write the functions that process the JSON data you’re getting from the API
and return an object with only the data you require for your app.
4. Set up a simple form that will let users input their location and will fetch the
Javascript Page 147
4. Set up a simple form that will let users input their location and will fetch the
weather info (still just console.log() it).
5. Display the information on your webpage!
6. Add any styling you like!
7. Optional: add a ‘loading’ component that displays from the time the form is
submitted until the information comes back from the API.
8. Push that baby to github and share your solution below!

Javascript Page 148


Testing JavaScript
Thursday, July 7, 2022 2:55 PM

Test driven development is an important skill in today's dev world. This section digs
into the details of writing automated JavaScript tests.

Javascript Page 149


Testing Basics
Thursday, July 7, 2022 2:52 PM

Introduction
Test Driven Development, or TDD for short, is a big deal in the modern
development landscape. This is a concept that we introduced way back in our
Fundamentals section with our JavaScript Exercises. The main idea is simply that
you start working on your code by writing automated tests before writing the code
that is being tested. There are tons of benefits to working like this, all of which will
be discussed in the resources below.
There are many test-running systems available in JavaScript: Mocha, Jasmine, Tape
and Jest to name a few. Fortunately the syntax for each one is very similar. They all
have their own set of special features, but the basic syntax is almost identical, so in
the end it doesn’t matter which one you use. In fact, simply picking which library to
use for this curriculum has been quite tricky!
This lesson is going to center around Jest. The biggest reasons for this decision are
that one of the best resources we’ve found for explaining JavaScript testing uses it
and they have fantastic documentation. In the end, writing tests is less about the
syntax and more about the TDD philosophy. The most important issues are
knowing why we write tests and what we test rather than how.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain the basics of TDD.
• Get up and running with Jest.
• Write basic tests.

Assignment
1. Read this short article that outlines the basic process and the benefits of TDD.
2. Watch at least the first 3 videos of this video series about testing in JavaScript.
The first video focuses heavily on the WHY, while the next two go into more
depth about the process. Later videos in the series are definitely worthwhile,
but the first 3 are enough to get you up and running.
3.

Javascript Page 150


4. Read and follow the Getting Started tutorial on the main Jest website.
5. Read and follow the Using Matchers document on the main Jest website. This
one demonstrates some of the other useful functions you can use in your
tests.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What are the benefits of TDD?
• What are some common jest matchers?

Javascript Page 151


Project: Testing Practice
Thursday, July 7, 2022 2:56 PM

Introduction
Let’s practice! This testing thing really is not that difficult, but it is quite new. The
only way to get comfortable with it is to spend some time doing it.
Using ES6 import statements with Jest
By default, the current version of Jest will not recognize ES6 import statements. In
order for you to be able to use ES6 modules for this project you may do the
following:
1. Install the @babel/preset-env package
npm i -D @babel/preset-env
2. Create a .babelrc file in the project’s root with the following lines of code:
{ "presets": ["@babel/preset-env"] }
This will allow you to use import statements. Note that in the Jest docs similar
instructions are laid out here.
Assignment
Write tests for the following, and then make the tests pass!
3. A capitalize function that takes a string and returns it with the first character
capitalized.
4. A reverseString function that takes a string and returns it reversed.
5. A calculator object that contains functions for the basic operations: add, subtract,
divide, and multiply. Each of these functions should take two numbers and return
the correct calculation.
6. A caesarCipher function that takes a string and returns it with each character
“shifted”. Read more about how a Caesar cipher works on this website.
a. Don’t forget to test wrapping from z to a.
b. Don’t forget to test keeping the same case.
c. Don’t forget to test punctuation!
d. For this one, you may want to split the final function into a few smaller
functions. One concept of Testing is that you don’t need to explicitly test every
function you write… Just the public ones. So in this case you only need tests
for the final caesarCipher function. If it works as expected you can rest
assured that your smaller helper functions are doing what they’re supposed
to.
1. An analyzeArray function that takes an array of numbers and returns an
object with the following properties: average, min, max, and length.
const object = analyzeArray([1,8,3,4,2,6]);

Javascript Page 152


object == {
average: 4,
min: 1,
max: 8,
length: 6
};

Javascript Page 153


More Testing
Thursday, July 7, 2022 2:57 PM

Introduction
An important basic concept in testing is isolation. You should only test one method at a time,
and your tests for one function should not depend upon an external function behaving
correctly - especially if that function is being tested elsewhere. The main reason for this is that
when your tests fail, you want to be able to narrow down the cause of this failure as quickly as
possible. If you have a test that depends on several functions, it can be hard to tell exactly what
is going wrong.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain what tightly coupled code is
• Describe a pure function and how it relates to TDD
• Explain what mocking is

Pure Functions
There are many benefits to using TDD when you write your code. One of the biggest benefits is
less obvious at first - it helps you to write better code. If you look back at some of your early
projects you will probably notice how tightly coupled everything is. All of your functions include
references to functions in other parts of your code, and the whole thing is filled with DOM
methods or console.log().
Tightly coupled code is hard to test! Imagine trying to write tests for a function like this:
function guessingGame() {
const magicNumber = 22;
const guess = prompt('guess a number between 1 and 100!');
if (guess > magicNumber) {
alert('YOUR GUESS IS TOO BIG');
} else if (guess < magicNumber) {
alert('YOUR GUESS IS TOO SMALL');
} else if (guess == magicNumber) {
alert('YOU DID IT! ');
}
}

Making this testable requires us to split up all the different things that are happening. First, we
do not need to test the functions prompt and alert because they are built in to the browser.
They are external to our program and whoever wrote them has already tested them. What we
do need to test is the number logic, which is much easier if we untangle it from the other
functions:
function evaluateGuess(magicNumber, guess) {
if (guess > magicNumber) {
return 'YOUR GUESS IS TOO BIG';

Javascript Page 154


return 'YOUR GUESS IS TOO BIG';
} else if (guess < magicNumber) {
return 'YOUR GUESS IS TOO SMALL';
} else if (guess == magicNumber) {
return 'YOU DID IT! ';
}
}

function guessingGame() {
const magicNumber = 22;
const guess = prompt('guess a number between 1 and 100!');
const message = evaluateGuess(magicNumber, guess);
alert(message);
}

guessingGame();

In this example, the only thing we really need to test is the evaluateGuess function, which is
much easier to test because it has a clear input and output and doesn’t call any external
functions. This implementation is much nicer as well because it’s much easier to extend. If we
wanted to switch out the prompt and alerts for methods that manipulate the DOM we can
do that more simply now and if we want to make our game more advanced by letting the user
make multiple guesses, that is also easier.
If we had written this program with TDD it is very likely that it would have looked more like the
second example to begin with. Test driven development encourages better program
architecture because it encourages you to write Pure Functions.
• Read this quick article about the value of ‘Pure Functions’.

Mocking
There are two solutions to the ‘tightly coupled code’ problem. The first, and best option is to
simply remove those dependencies from your code as we did above, but that is simply not
always possible. The second option is mocking - writing “fake” versions of a function that
always behaves exactly how you want. For example, if you’re testing a function that gets
information from a DOM input, you really don’t want to have to set up a webpage and
dynamically insert something into the input just to run your tests. With a mock function, you
could just create a fake version of the input-grabbing function that always returns a specific
value and use THAT in your test.
Assignment
1. If you haven’t already, watch the ‘mocking’ videos from this series.
2.

Javascript Page 155


3. Too much mocking can be a bad thing. It is sometimes necessary, but if you have to set up
an elaborate system of mocks to test any bit of your code, that means your code is too
tightly coupled. These two articles (one and two) might be a little extreme, but they
contain several really good points about program architecture and testing.
4. Now that you have some practice and context for TDD, this section of the Jest docs will
probably make good sense to you.
5. Jest includes some really handy mocking functions. Read about them in the official docs.
6. Watch this amazing video that covers what to test in your codebase. The video is
specifically about testing the Ruby language, but that doesn’t matter at all. The concepts
here ring true in any language, and luckily Ruby is a clear enough language that you will be
able to follow along just fine.
7.

8. And finally, if you wish, you can add Jest to your webpack setup. Read about that process
here.

Knowledge Check
This section contains questions for you to check your understanding of this lesson. If you’re
having trouble answering the questions below on your own, review the material above to find
the answer.
• What is tightly coupled code?
• What are the two requirements for a function to be pure?
• What are side effects and why is it important to identify them when testing a function?
• What are two solutions to the tightly coupled code problem?
• What is mocking?
• When would you use a mock function?
• How should you test incoming query messages?

Javascript Page 156


• Why should you not test implementation?

• Should you test private methods?


• Why should you not test messages with no side effects?


Javascript Page 157


Project-Battleship
Thursday, July 7, 2022 3:01 PM

Introduction
It’s time to really flex your muscles. Test Driven Development can certainly feel
uncomfortable at first, but becomes more natural with practice. We’re going to
implement the classic game ‘Battleship’. If you’ve never played it, or need a
refresher you can read about it here and you can play an online version here.
Since we’re doing TDD, it’s important that you don’t get overwhelmed. Simply
take it one step at a time. Write a test, then make it pass.
We have not yet discussed testing the appearance of a webpage. Doing this
requires a separate set of tools, and it is outside the scope of this unit. For this
assignment do your best to isolate every bit of application functionality from
the actual DOM manipulation bits. You can use mocks to make sure that DOM
methods like appendChild are being called, but try your best to keep those
things outside of the app logic.
Assignment
1. Begin your app by creating the Ship factory function.
a. Your ‘ships’ will be objects that include their length, where they’ve
been hit and whether or not they’ve been sunk.
b. REMEMBER you only have to test your object’s public interface. Only
methods or properties that are used outside of your ‘ship’ object need
unit tests.
c. Ships should have a hit() function that takes a number and then marks
that position as ‘hit’.
d. isSunk() should be a function that calculates it based on their length
and whether all of their positions are ‘hit’.
2. Create Gameboard factory.
a. Note that we have not yet created any User Interface. We should
know our code is coming together by running the tests. You shouldn’t
be relying on console.logs or DOM methods to make sure your code is
doing what you expect it to.
b. Gameboards should be able to place ships at specific coordinates by
calling the ship factory function.
c. Gameboards should have a receiveAttack function that takes a pair of
coordinates, determines whether or not the attack hit a ship and then
sends the ‘hit’ function to the correct ship, or records the coordinates
of the missed shot.
d. Gameboards should keep track of missed attacks so they can display
Javascript Page 158
d. Gameboards should keep track of missed attacks so they can display
them properly.
e. Gameboards should be able to report whether or not all of their ships
have been sunk.
3. Create Player.
a. Players can take turns playing the game by attacking the enemy
Gameboard.
b. The game is played against the computer, so make ‘computer’ players
capable of making random plays. The AI does not have to be smart,
but it should know whether or not a given move is legal. (i.e. it
shouldn’t shoot the same coordinate twice).
4. Create the main game loop and a module for DOM interaction.
a. At this point it is appropriate to begin crafting your User Interface.
b. The game loop should set up a new game by creating Players and
Gameboards. For now just populate each Gameboard with
predetermined coordinates. You can implement a system for allowing
players to place their ships later.
c. We’ll leave the HTML implementation up to you for now, but you
should display both the player’s boards and render them using
information from the Gameboard class.
a. You need methods to render the gameboards and to take user
input for attacking. For attacks, let the user click on a coordinate
in the enemy Gameboard.
d. The game loop should step through the game turn by turn using only
methods from other objects. If at any point you are tempted to write
a new function inside the game loop, step back and figure out which
class or module that function should belong to.
e. Create conditions so that the game ends once one players ships have
all been sunk. This function is appropriate for the Game module.
5. Finish it up
a. There are several options available for letting users place their ships.
You can let them type coordinates for each ship, or investigate
implementing drag and drop.
b. You can polish the intelligence of the computer player by having it try
adjacent slots after getting a ‘hit’.
c. Optionally, create a 2 player option that lets users take turns by
passing the device back and forth. If you’re going to go this route,
make sure the game is playable on a mobile screen and implement a
‘pass device’ screen so that players don’t see each others boards!

Javascript Page 159


Javascript Page 160
Intermediate Git
Thursday, July 7, 2022 3:03 PM

You should be familiar with the basic Git workflow since you've been using it to save
your projects along the way (right?!). This section will start preparing you for the
more intermediate-level uses of Git that you'll find yourself doing.

Javascript Page 161


A deeper look at git
Thursday, July 7, 2022 3:03 PM

Introduction
Git is a crucial skill to have whether you’re just a hobbyist or you aim to become a professional
web developer. It’s the “save” button on steroids and allows for seamless collaboration. There
really aren’t all that many commands for you to learn, but sometimes the real difficulty of Git
comes from visualizing what’s happening.
In this lesson, we’ll help with the visualization by diving deeper than just the $ git add . and
$ git commit and $ git push commands you’ve mostly been using. We’ll cover topics
such as Remotes, Pointers, and Changing Git History. This will expand your understanding of
what’s actually going on under the hood with Git.
It is very important to take a look at all of this before progressing any further with the
curriculum. The project work is becoming more and more complex, so using a disciplined Git
workflow is no longer optional. Hopefully after going through this lesson you’ll be much more
comfortable changing your Git history and have a better understanding of Git as a whole.
Lesson Overview
This section contains a general overview of topics that you will learn in this lesson.
• History changing Git commands
• Different ways of changing history
• Using remotes to change history
• Dangers of history-changing operations
• Best practices of history-changing operations
• Pointers

Changing History
So let’s say you’re comfortable writing good commit messages and you’re working with
branches to have a good Git workflow going. But nobody is perfect, and as you’re writing some
beautiful code something goes wrong! Maybe you commit too early and are missing a file.
Maybe you mess up one of your commit messages and omit a vital detail.
Let’s look at some ways we can change recent and distant history to fit our needs. We’re going
to cover how to:
• Change our most recent commit
• Change multiple commit messages
• Reorder commits
• Squash commits together
• Split up commits
Getting Set Up
Before we get started with the lesson, let’s create a Git playground in which we can safely
follow along with the code and perform history changing operations. Go to GitHub, and as you
have in the past create a new repository. Call it whatever you’d like, and clone this repository to
your local system. Now, let’s cd into the repository we just cloned, and create some new files!

Javascript Page 162


your local system. Now, let’s cd into the repository we just cloned, and create some new files!
Once you’re in the repository follow along with the following commands. Look them up if
you’re confused about anything that’s happening.
$ touch test{1..4}.md
$ git add test1.md && git commit -m 'Create first file'
$ git add test2.md && git commit -m 'Create send file'
$ git add test3.md && git commit -m 'Create third file and create
fourth file'

Changing The Last Commit


So if we look at the last commit we made Uh-Oh!, if you type in git status and git log you
can see we forgot to add a file! Let’s add our missing file and run $ git commit --amend
$ git add test4.md
$ git commit --amend

What happened here is we first updated the staging area to include the missing file, and then
we replaced the last commit with our new one to include the missing file. If we wanted to, we
could have changed the message of the commit and it would have overwritten the message of
the past commit.
Remember to only amend commits that have not been pushed anywhere! The reason for this is
that git commit --amend does not simply edit the last commit, it replaces that commit with
an entirely new one. This means that you could potentially destroy a commit other developers
are basing their work on. When rewriting history always make sure that you’re doing so in a
safe manner, and that your coworkers are aware of what you’re doing.
Changing Multiple Commits
Now let’s say we have commits further back in our history that we want to modify. This is
where the beautiful command rebase comes into play! We’re going to get deeper into the
complexities of rebase later on in this lesson, but for now we’re going to start out with some
very basic usage.
rebase -i is a command which allows us to interactively stop after each commit we’re trying
to modify, and then make whatever changes we wish. We do have to tell this command which
is the last commit we want to edit. For example, git rebase -i HEAD~2 allows us to edit
the last two commits. Let’s see what this looks like in action, go ahead and type in:
$ git log
$ git rebase -i HEAD~2

You should notice that when rebasing, the commits are listed in opposite order compared to
how we see them when we use log. Take a minute to look through all of the options the
interactive tool offers you. Now let’s look at the commit messages at the top of the tool. If we
wanted to edit one of these commits, we would change the word pick to be edit for the
appropriate commit. If we wanted to remove a commit, we would simply remove it from the
list, and if we wanted to change their order, we would change their position in the list. Let’s see
what an edit looks like!
edit eacf39d Create send file
pick 92ad0af Create third file and create fourth file

Javascript Page 163


This would allow us to edit the typo in the Create send file commit to be Create
second file. Perform similar changes in your interactive rebase tool, but don’t copy and
paste the above code since it won’t work. Save and exit the editor, which will allow us to edit
the commit with the following instructions:
You can amend the commit now, with
git commit --amend
Once you're satisfied with your changes, run
git rebase --continue

So let’s edit our commit by typing git commit --amend, fixing the typo in the title, and then
finishing the rebase by typing git rebase --continue. That’s all there is to it! Have a look
at your handiwork by typing git log, and seeing the changed history. It seems simple, but this
is a very dangerous tool if misused, so be careful. Most importantly, remember that if you have
to rebase commits in a shared repository, make sure you’re doing so for a very good reason
that your coworkers are aware of.
Squashing Commits
Using squash for our commits is a very handy way of keeping our Git history tidy. It’s
important to know how to squash, because this process may be the standard on some
development teams. Squashing makes it easier for others to understand the history of your
project. What often happens when a feature is merged, is we end up with some visually
complex logs of all the changes a feature branch had on a main branch. These commits are
important while the feature is in development, but aren’t really necessary when looking
through the entire history of your main branch.
Let’s say we want to squash the second commit into the first commit on the list, which is
Create first file. First let’s rebase all the way back to our root commit by typing git
rebase -i --root. Now what we’ll do is pick that first commit, as the one which the
second commit is being squashed into:
pick e30ff48 Create first file
squash 92aa6f3 Create second file
pick 05e5413 Create third file and create fourth file

Rename the commit to Create first and second file, then finish the rebase. That’s it!
Run git log and see how the first two commits got squashed together.
Splitting Up a Commit
Before diving into Remotes, we’re going to have a look at a handy Git command called reset.
Let’s have a look at the commit Create third file and create fourth file. At the
moment we’re using blank files for convenience, but let’s say these files contained functionality
and the commit was describing too much at once. In that case what we could do is split it up
into two smaller commits by, once again, using the interactive rebase tool.
We open up the tool just like last time, change pick to edit for the commit we’re going to
split. Now, however, what we’re going to do is run git reset HEAD^, which resets the
commit to the one right before HEAD. This allows us to add the files individually, add, and
commit them individually. All together it would look something like this:
$ git reset HEAD^

Javascript Page 164


$ git reset HEAD^
$ git add test3.md && git commit -m 'Create third file'
$ git add test4.md && git commit -m 'Create fourth file'

Let’s start by looking a bit closer at what happened here. When you ran git reset, you reset
the current branch by pointing HEAD at the commit right before it. At the same time, git
reset also updated the index (the staging area) with the contents of wherever HEAD now
pointed. So our staging area was also reset to what it was at the prior commit - which is great -
because this allowed us to add and commit both files separately.
Now let’s say we want to move where HEAD points to but don’t want to touch the staging area.
If we want to leave the index alone, you can use git reset --soft. This would only perform
the first part of git reset where the HEAD is moved to point somewhere else.
The last part of reset we want to touch upon is git reset --hard. What this does is it
performs all the steps of git reset, moving the HEAD and updating the index, but it also
updates the working directory. This is important to note because it can be dangerous as it can
potentially destroy data. A hard reset overwrites the files in the working directory to make it
look exactly like the staging area of wherever HEAD ends up pointing to. Similarly to git
commit --amend, a hard reset is a destructive command which overwrites history. This
doesn’t mean you should completely avoid it if working with shared repositories on a team with
other developers. You should, however, make sure you know exactly why you’re using it, and
that your coworkers are also aware of how and why you’re using it.
Working With Remotes
Thus far you’ve been working with remote repositories each time you’ve pushed or pulled from
your own GitHub repository while working on the curriculum’s various projects. In this section
we’re going to cover some slightly more advanced topics, which you might not have yet
encountered or had to use.
git push --force
Let’s say you’re no longer working on a project all by yourself, but with someone else. You want
to push a branch you’ve made changes on to a remote repository. Normally Git will only let you
push your changes if you’ve already updated your local branch with the latest commits from
this remote.
If you haven’t updated your local branch, and you’re attempting to git push a commit which
would create a conflict on the remote repository, you’ll get an error message. This is actually a
great thing! This is a safety mechanism to prevent you from overwriting commits created by the
people you’re working with, which could be disastrous. You get the error because your history
is outdated.
You might perform a brief query and find the command git push --force. This command
overwrites the remote repository with your own local history. So what would happen if we used
this while working with others? Well let’s see what would happen when we’re working with
ourselves. Type the following commands into your terminal, and when the interactive rebase
tool pops up remove our commit for Create fourth file:
$ git push origin main
$ git rebase -i --root
$ git push --force
$ git log

Javascript Page 165


Huh, that’s interesting, we don’t see our fourth file on our local system. Let’s check our GitHub
repository, is our file test4.md there?
No! We just destroyed it, which in this scenario is the danger - you could potentially destroy the
work of those you’re collaborating with! git push --force is a very dangerous command,
and it should be used with caution when collaborating with others. Instead, you can fix your
outdated history error by updating your local history using fetch, merge, and then attempting
to push again.
Let’s consider a different scenario:
$ touch test4.md
$ git add test4.md && git commit -m "Create fifth file"
$ git push origin main
$ git log

We look at our commit message and realize oops, we made a mistake. We want to undo this
commit and are once again tempted to just force the push. But wait, remember, this is a very
dangerous command. If we’re ever considering using it, always check if it’s appropriate and if
we can use a safer command instead. If we’re collaborating with others and want to undo a
commit we just made, we can instead use git revert!
git revert HEAD
git push origin main

Remember when we were working with HEAD, aka the current commit we’re viewing, while
rebasing? What this would do is it would revert the changes to HEAD! Then we would push our
new commit to whichever branch we’re working on, which in this example is main even though
normally our work would most likely be on a feature-branch.
So now that we’ve learned about the various dangers of git push --force, you’re probably
wondering why it exists and when to use it. A very common scenario in which developers use
git push --force is updating pull requests. Collaborative work is covered more in depth in
a separate lesson, but the take-away from this section should be that the --force option
should be used only when you are certain that it is appropriate. There are also less common
scenarios, such as when sensitive information is accidentally uploaded to a repository and you
want to remove all occurrences of it.
It is worth giving special mention to git push --force-with-lease, a command which in
some companies is the default option. The reason for this is that it’s a fail-safe! It checks if the
branch you’re attempting to push to has been updated and sends you an error if it has. This
gives you an opportunity to, as mentioned before, fetch the work and update your local
repository.
Dangers and Best Practices
Let’s review the dangers we’ve addressed so far. I know, I know, it’s scary stuff - but we have to
be mindful or our coworkers might end up hating our guts! If you look back through this lesson
you’ll see a common thread. amend, rebase, reset, push --force are all especially
dangerous when you’re collaborating with others. These commands can destroy work your
coworkers have created. So keep that in mind. When attempting to rewrite history, always
check the dangers of the particular command you’re using and follow these best practices for
the commands we’ve covered:

Javascript Page 166


the commands we’ve covered:
1. If working on a team project, make sure rewriting history is safe to do and others know
you’re doing it.
2. Ideally, stick to using these commands only on branches that you’re working with by
yourself.
3. Using the -f flag to force something should scare you, and you better have a really good
reason for using it.
4. Don’t push after every single commit, changing published history should be avoided when
possible.
5. Regarding the specific commands we’ve covered:
a. For git amend never amend commits that have been pushed to remote
repositories.
b. For git rebase never rebase a repository that others may work off of.
c. For git reset never reset commits that have been pushed to remote repositories.
d. For git push --force only use it when appropriate, use it with caution, and
preferably default to using git push --force-with-lease.

Branches Are Pointers


While the focus of this lesson was more advanced tools for changing Git history, we’re going
into another advanced topic that might be hard for some to understand - Pointers.
So what is a branch? Based off of your exposure, you might be visualizing a branch as a group of
commits. This actually isn’t the case! A branch is actually a pointer to a single commit! Hearing
this, your first thought might be “Well if a branch is just a finger pointing at a single commit,
how does that single commit know about all the commits that came before it?” The answer to
this question is very simple: Each commit is also a pointer that points to the commit that came
before it! Wow. This might be a lot to take in, so let’s take a moment to absorb that fact.
Now that you’ve had a second to gather your thoughts and attempt to wrap your head around
this concept, it might help to go back and look at a concrete example of pointers we used in this
lesson. Let’s think back to our use of git rebase -i HEAD~3. If you can remember, this
command lets us edit the last 3 commits. Do you have any guesses on how Git knew which 3
commits to edit? That’s right, by using pointers! We start at HEAD, which is a special pointer for
keeping track of the branch you’re currently on. HEAD points to our most recent commit in the
current branch. That commit points to the commit made directly before it, which we can call
commit 2. Commit 2 does the exact same and points to the commit before it, which we can call
commit 3. That’s how git rebase -i HEAD~3 starts with a HEAD pointer, and then follows
subsequent pointers to find which three commits to edit.
You might be feeling overwhelmed at this point, so let’s recap what we’ve learned. A branch is
simply a pointer to a single commit. A commit is a snapshot, and it’s a pointer to the commit
directly behind it in history. That’s it!
Assignment
1. Read through GitHub’s documentation on merge conflicts
• It’s only a matter of time until you run into one (if you haven’t already)! While merge
conflicts might seem intimidating, they’re actually very simple. Take your time with
this resource and make sure you look at the two different ways the documentation
suggests resolving merge conflicts - on GitHub itself, and on your command line.
While you might not need this right now, keeping the source of this documentation
in the back of your mind will prove invaluable for when you eventually run into a

Javascript Page 167


in the back of your mind will prove invaluable for when you eventually run into a
merge conflict and aren’t sure where to find a simple solution.
2. Read think-like-a-git
• Take your time with this resource as well, it’s very well written and will be very
helpful in solidifying your understanding of Git.

Additional Resources
This section contains helpful links to related content. It isn’t required, so consider it
supplemental.
• Read this Git Cheat Sheet if you need a reference sheet.
• Watch this video about Rebase & Merge for an example of how to use both rebase and
merge.

• Read the chapter on Branches covered by git-scm if you want an even deeper dive into
Branches.
• Read the chapter on Rebasing covered by git-scm for an even deeper dive into Rebasing.
• Read the chapter on Reset covered by git-scm for a deeper dive into git reset.

Knowledge Check
This section contains questions for you to check your understanding of this lesson on your own.
If you’re having trouble answering a question, click it and review the material it links to.
• How can you amend your last commit?
• What are some different ways to rewrite history?
• What is a safe way to push history changes to a remote repository?
• What are the dangers of history-changing operations?
• What are best practices of history-changing operations?
• Explain what it means for branches to be pointers.

Javascript Page 168


Video Course (Mandatory)
Thursday, July 7, 2022 3:09 PM

Course: Namase JavaScript

Author: Akshay Saini


Things to focus on:
Hoisting
Functions
undefined vs not defined
scope and lexical environment
let and const in js
block scope and shadowing
closures
set Timeout + Closures
first class functions
callback functions
asynchronous JavaScript and event loop from scratch
Higher order functions
map, filter and reduce

Javascript Page 169


Exercises (Mandatory)
Thursday, July 7, 2022 3:10 PM

Exercises:
139 exercises grouped into 31 JavaScript Concepts

Javascript Page 170


Introduction to Nodejs
Thursday, July 7, 2022 3:15 PM

Overview
Take your JavaScript skills to the server-side! Learn how to fully craft your site's
backend using Express, the most popular back-end JavaScript framework! You will
also learn how to use a non-relational database, MongoDB

Introduction to Nodejs
1 Introduction
2 Getting started
3 Debugging Node
4 Project: Basic Informational Site

MongoDB
1 Introduction

Express and MongoDB


1 Introduction to Express
2 Express 101
3 Express 102: CRUD and MVC
4 Preparing for Deployment
5 Project: Mini Message Board
6 Express 103: Routes and Controllers
7 Express 104: View Templates
8 Project: Express 105: Forms and Deployment
9 Project: Inventory Application

Authentication
1 Authentication Basics
2 Security Configuration
3 Project: Members Only

APIs
1 API basics
2 API security
3 Project: Blog API

Nodejs Page 171


Testing Express
1 Testing Routes and Controllers
2 Testing Database Operations

Nodejs Page 172


Introduction
Thursday, July 7, 2022 3:17 PM

NodeJS (or just ‘Node’) has been steadily gaining popularity since its creation in
2009. The internet is flooded with courses and articles about it, installing it is a
prerequisite for pretty much any front-end development work, and of course the
amount of jobs that require knowledge of it are also on the rise.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Describe the purpose of a server.
• Describe the differences between static and dynamic sites.
• Explain why you might need a back-end for your project.
• Explain when you wouldn’t need a back-end for a project.
• Explain the event loop.
• Understand the origin of the Node.js runtime.
• Write a simple “hello world” application and run it in the console of your
machine.
• Understand what Node.js really is.

What is Node?
The Node.js website declares:
“As an asynchronous event driven JavaScript runtime, Node is designed to build
scalable network applications.”
This is a definition that requires a little unpacking.
The important bit to understand right up front is that Node is a “JavaScript
runtime”. When JavaScript was first created, it was designed to run in the browser.
This means that it was impossible to use JavaScript to write any kind of program
that was not a website. Node brings JavaScript out of browser-land. This allows
developers to use JavaScript to accomplish pretty much anything that other
popular server-side languages such as Ruby, PHP, C# and Python can do. So, at its
most basic level, Node simply allows you to run JavaScript code on a machine such
as your local computer or a server without having to go through a web browser.
To facilitate this, Node has some added functionality that is not found in browser-
based JavaScript, such as the ability to read and write local files, create http
connections and listen to network requests.
Event Driven
Back to the definition from Node’s website: Node is an asynchronous event driven
JavaScript runtime. In this context asynchronous means that when you write your

Nodejs Page 173


JavaScript runtime. In this context asynchronous means that when you write your
code you do not try to predict the exact sequence in which every line will run.
Instead you write your code as a collection of smaller functions that get called in
response to specific events such as a network request (event driven).
For example, let’s say you are writing a program and you need it to do the
following. It should read some text from a file, print that text to the console, query
a database for a list of users and filter the users based on their age.
Instead of telling your code to do those steps sequentially like so:
1. Read File
2. Print File Contents
3. Query Database
4. Filter Database Query results
You can break up the task like so:
1. Read File AND THEN Print File Contents
2. Query Database AND THEN Filter Database Query Results.
When you run this program Node will start at the top and begin reading the file
but since that is an action that takes some time it will immediately begin running
the second step (querying the database) while it’s waiting on the file to finish
reading.
While both of these processes are running, Node sits and waits on an event. In this
case, it is waiting on the completion of both processes, the reading of a file and the
database query. When either of these tasks are finished, Node will fire off an event
that will run the next function we’ve defined. So if the read-file process finishes
first, it will print the file contents. If the database query finishes first, it will start
the filtering process. As the programmer, we don’t know or care which order the
two processes are going to be completed. If this code was processed
synchronously (rather than asynchronously) we would have to wait for each step in
the program before moving on to the next one, which could cause things to slow
down considerably. If the file that we needed to read was really long then we
might have to wait a few seconds before the database query could begin.
This process is almost exactly like the way that you would use addEventListener in
front-end JavaScript to wait for a user action such as a mouse-click or keyboard
press. The main difference is that the events are going to be things such as
network requests and database queries. This functionality is facilitated through the
use of callbacks. Callbacks are incredibly important to Node, so take a minute to
read through this article to make sure you’re up to speed.
Let’s look at a quick real-world example:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});

Nodejs Page 174


res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Hello World!');
}).listen(8080);

This snippet is from the very first lesson in a tutorial that you’ll be following very
soon. Basically this code is creating a server and saying, “any time we get a
network request, run this callback function”. This function happens to respond
with the text ‘Hello World!’. So if you go to a browser and navigate to the correct
address and port, you would see that text on your screen.
A word of advice
While you may have learned Angular (or any other frontend framework) before,
either of your own volition or earlier in the path, it is not recommended to use it
for this course right away. There are many topics that you must learn before you
can combine these frameworks effectively. As you move forward through the Node
course, you will learn more about how to integrate Node APIs with frontend
frameworks. You should follow the course as it is written; deviating from the
directions can make it more difficult than it needs to be. Your time spent learning
those frameworks will not be wasted, don’t worry!
Assignment

1. This short module on “The Server Side” from MDN is a great source for the
background knowledge you need. Read through at least the first two articles
posted under the ‘Guides’ section: Introduction to the server side and Client-
Server Overview. The other two are interesting and worth reviewing, but less
relevant to our immediate concerns.
2. To gain a little more insight into the nature of Node, and to unpack the rest of
the above definition, read this article.
3. What is the Node Event Loop? Check out this long, but really fantastic video…
don’t skip it!
4.

5. Take a few minutes to go through the “Quick Start” section of the new official
Node.js website.
6. This short video is a great introduction as well!
Nodejs Page 175
6. This short video is a great introduction as well!
7.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• Read this article on 7 awesome things you can build with Node.js.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is Node?

Nodejs Page 176


Getting Started
Thursday, July 7, 2022 3:21 PM

Like we learned in the introduction lesson, Node.js is really just JavaScript. So a


basic understanding of JavaScript is necessary in order to understand Node. For
this reason, it is highly recommended that you take our prerequisite JavaScript
course before continuing with this course.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain some things that Node.js is commonly used for.
• Create and use modules in Node.js (both built-in and user created).
• Set up a basic webserver with Node.js using the HTTP module.
• Read, create, update, and delete files from Node.js.
• Use the URL module to parse a url address and split it into readable parts.
• Understand how to use NPM.
• Create, fire and listen for your own events.

Assignment
• Let’s dive in and start looking at Node server-side code! We will be hopping
around lessons in the NodeJS.dev docs which you should follow along.
• Get Started
○ Learn how to run Node.js scripts from the terminal in this lesson.
○ Learn quickly about .env files and how we use them here! This will
become very important in the future when working with databases
and other sensitive credentials!
• HTTP Module
○ Learn how to Build an HTTP server, and then how to make HTTP
requests with Node.
• File System
○ First, take a look at the fs module that we use heavily for working
with files in Node.
○ Then, let’s start writing files in Node.
○ Finally, we’ll learn how to read files.
• The URL Class
○ Check out this documentation on the URL class. Play with the code
samples to see how it works!
• NPM
○ Let’s get an introduction to NPM.
○ After that, it’s time to quickly get introduced to the package.json file.
○ And the differences between NPM global and local packages.
Nodejs Page 177
○ And the differences between NPM global and local packages.
• Events
○ Follow along the Event Emitter section.
○ Look into this section to see the events module.
• Optional Extra Credit!
• Although a bit outdated, the W3 Schools introduction to Node.js is super
useful! Go to the W3 Schools node tutorial and code along with the
following lessons (which should be listed on the sidebar of their site).
Specifically, work from the Node.js Intro through to Node.js Events. You
can look at the File Uploads and Email sections if you’re feeling
particularly ambitious! NOTE: The URL module is very outdated. Refer to
the earlier link if you run into issues in the Node.js URL Module from W3.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is a File System Module? How and why would you use it?
• What is the command for installing a package locally in with npm?
• What is the command for installing a package globally in with npm?
• What is the difference between a global and local package install with npm?

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• This crash course video from TraversyMedia is a great code-along for getting
into Node.js. It may seem repetitive after completing the assignment, but
practice is repetition!

• This crash course playlist of 12 episodes from Net Ninja is a great resource to
learn Node.js, There are 12 videos in playlist you can consider them all.

Nodejs Page 178


Nodejs Page 179
Debugging Node
Thursday, July 7, 2022 3:24 PM

Up until this point, you’ve likely only relied on the browser’s DevTools to debug
your code. When it comes to debugging Node and server side code, VS Code has
a handy built-in debugger that you can use to debug directly in your editor!
Additionally, you can also set Google Chrome up to debug Node and get the full
benefits of the Chrome DevTools. Ultimately, this lesson will familiarize you with
the Node debugger, which is a critical tool at this point in your learning, and will
likely be a key tool you use daily in your professional life.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Use the VS Code built-in Node debugger
• Use the Chrome DevTools to debug Node

Assignment
• Check out the official VS Code Node debugger documentation. Take note of
the Javascript Debug Terminal- this is an easy way to get the debugger
running!
• Read this article for a tutorial on how to debug Node with Chrome. NOTE:
You can ignore anything that refers to debugging remote apps- you’ll be
debugging local apps.
• Watch this video tutorial to see the process in action

Knowledge Check
This section contains questions for you to check your understanding of this
lesson. If you’re having trouble answering the questions below on your own,
review the material above to find the answer.
• What are two ways to debug Node in VS Code?

Nodejs Page 180


Project: Basic Informational Site
Thursday, July 7, 2022 3:25 PM

Introduction
You’ve come a long way, congratulations! At this point you should feel comfortable
with building new Express applications and using MongoDB to model and store
data. This project will require you to put all of that knowledge to the test. It’s not
going to be easy, but should be well within your capabilities and it will be a great
portfolio piece.
You’ll be building Facebook. As with our previous lessons, how much effort you
want to put into the styling and front-end is up to you. The important stuff is the
data and backend. You’ll put together the core features of the platform like users,
profiles, posts, “liking”, “friending”, and the news feed. You’ll also implement
signing in with the real Facebook using our old friend passportJS.
Some features of Facebook are things we haven’t been exposed to such as chat,
realtime updates of the newsfeed and notifications. You won’t be responsible for
those unless you’re feeling really confident in your skills at this point. (It’s not that
hard.. look here if you want to see what’s involved.)
Assignment
Build Facebook! You’ll build a large portion of the core Facebook user functionality
in this project. We won’t be worrying about some of the more flashy front-end
stuff unless you really want to, but you shouldn’t need it to get a nice user
experience.
This project will give you a chance to take a relatively high level set of
requirements and turn it into a functioning website. You’ll need to do some of your
own research and read the documentation for a few of the modules we’ll be using.
Keep the following requirements in mind. We’ll cover specific steps to get started
below this list.
1. Users must sign in to see anything except the sign in page.
2. Users should be able to sign in using their real facebook details. This is fairly
easily accomplished using PassportJS, and you should be able to use the
knowledge you already have to figure it out from the documentation.
3. Users can send friend requests to other users.
4. A user must accept the friend request to become friends.
5. Users can create posts. (begin with text only)
6. Users can like posts.
7. Users can comment on posts.
8. Posts should always display with the post content, author, comments and
Nodejs Page 181
8. Posts should always display with the post content, author, comments and
likes.
9. Treat the Posts index page like the real Facebook’s “Timeline” feature – show
all the recent posts from the current user and users she is friends with.
10. Users can create Profile with a photo (you can get this from the real facebook
when you sign in using passport)
11. The User Show page contains their profile information, profile photo and
posts.
12. The Users Index page lists all users and buttons for sending friend requests to
those who are not already friends or who don’t already have a pending
request.
13. Deploy your app to Heroku!
Extra Credit
1. Make posts also allow images (either just via a url, or by uploading one.)
2. Allow Users to upload and update their own profile photo.
3. Create a guest sign-in functionality that allows visitors to bypass the login
screen without creating an account or supplying credentials. This is especially
useful if you are planning on putting this project on your résumé - most
recruiters, hiring managers, etc. will not take the time to create an account.
This feature will give them an opportunity to look at your hard work without
going through a tedious sign-up process.
4. Make it pretty!
Getting Started
1. Think through the data architecture required to make this work. There are lots
of models and the relationship between them is more complicated than
anything you’ve done before. How are you going to model a user’s list of
friends and friend requests? Posts should be able to have likes and comments
associated with them, how are you going to model that? Take some time to
plan your approach before diving in.
2. Start your app however you like, using the express-generator or from scratch.
3. Work your way down the list above! Each step will involve a new challenge,
but you’ve got the tools.
4. You can populate data like users and posts with fake data using the Faker
module from npm. To accomplish this create a new JavaScript file named
seeds.js which imports your mongoose models and uses the faker module to
generate and save a bunch of new users.

Nodejs Page 182


MongoDb
Thursday, July 7, 2022 3:29 PM

In this section you'll learn about creating and querying a MongoDB database, as
well as the differences between relational databases and a NoSQL option like
MongoDB.

Nodejs Page 183


Introduction to MongoDb
Thursday, July 7, 2022 3:29 PM

Data persistence is integral to the vast majority of web applications. Local storage
has limitations and poses security risks, and SaaS options such as Firebase work
well, but ultimately being able to understand how to structure, build, and query
your own database are important skills for any full stack developer to have. For
example, consider Twitter. Where are your username and password stored? Or
perhaps where all of your Tweets might be fetched from? How does the
application determine what Tweets are shown to you every time you log on? These
operations are handled by a database. Databases are split into “relational” and
“non-relational” types of databases, and each handles data and scaling in different
manners. This article goes in depth with the difference between the two. This
lesson will teach you about MongoDB, a popular NoSQL database.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Set up a database on MongoDB Atlas
• Use the mongo shell
• Create, edit, and delete documents in a MongoDB database using the mongo
shell

Assignment
• Take the entire MongoDB University “Mongo Basics” course. This course will
teach you the basics of MongoDB and the mongo shell. You will need to make
an account.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is the difference between a relational database and a non-relational
database?

Nodejs Page 184


Express and Mongoose
Thursday, July 7, 2022 3:31 PM

Here we finally get to Express, the most popular back-end JavaScript framework,
and learn to build applications with MongoDB using Mongoose.

Nodejs Page 185


Introduction to Express
Thursday, July 7, 2022 3:31 PM

In the previous lessons, you got up and running with Node. You learned how to
serve up a multi-page website and read/write data from files on the server. You
probably found that while it wasn’t too difficult, the code was verbose and a little
complicated. However, you can easily see how complicated and hard to maintain
things would get if you decided to start adding more features. Express is a tiny and
simple framework that makes the things you did in the previous lessons even
quicker and simpler, and does so in a way that makes projects even more easily
extensible.
In this section, we are going to be following the express tutorial on MDN. We’ll go
one lesson at a time, occasionally supplementing with a little deeper explanation
or side projects to help you deepen your understanding of the material. There is a
ton of information there, so be sure to take your time and READ EVERYTHING. The
blue “notes” that are scattered throughout the tutorial often link to articles or
other tutorials that will definitely improve your understanding of the content.
Don’t be lazy!
Learning Outcomes
By the end of this lesson, you should be able to do the following:
Express web framework
• Describe Express and Node’s main benefits.
• Describe the relationship between Node and Express.
• Explain what a module is and how Express fits in.
• Import and create modules.
• Describe asynchronous APIs.
• Describe and create route handlers.
• Describe and use middleware.
• Describe error handling in Express.
• Describe what the main parts of an Express app might look like.
Setting up a Node development environment
• Describe Express development environment.
• Import Express into an application using NPM.
• Create and run applications using the Express application generator tool.
• Set up a development environment for Express on your computer.

Assignment
1. Read the introductory lesson on the MDN website. It is long but its main
purpose is to show you the various bits and pieces that you’ll be learning in
the rest of the tutorial. If you want you can code along a bit, but most of the

Nodejs Page 186


the rest of the tutorial. If you want you can code along a bit, but most of the
examples aren’t really intended for you to follow 100%. DO read the entire
thing! Some of it will be a review, but that’s OK! Follow the links that they give
and at least look at them. They are a vital part of this lesson and will often
direct you to the relevant portion of the official express docs (which are quite
good)! You’ll want to be somewhat familiar with them when it comes time to
do your own projects.
2. The second lesson in MDN’s Express tutorial walks you through setting up
Node and NPM. If you’ve come this far, you should already have both set up.
Still go through the Using NPM and Installing the Express Application
Generator sections of this lesson as you’ll learn more about installing and
getting started with Express.
3. Once you’re all set up, take a look at the simple Node site you created in our
first project. Rewrite it using express! You should be able to do this with just
one app.js file and a few app.get()s.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• The book Express in Action by Evan M. Hahn is an incredible resource for
Express beginners.
• This video crash course provides you with all the basic concepts.

• Web Dev Simplified’s Express JS crash course also packs a ton of great
information into a 35 minute video.

Nodejs Page 187


Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is Express?
• What is a module?
• Which are the four most used methods to define route handlers?
• How do we handle errors?
• How do you use the Express library with NPM in a project?

Nodejs Page 188


Express 101
Thursday, July 7, 2022 3:33 PM

In the last lesson, we set the stage by explaining quite a bit of the background
information you’ll need to really understand what’s going on as we start to dive
into Express. This lesson will actually start you on the project that you’ll be
completing as you follow the tutorial.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Use express-generator to generate a basic express site.
• Understand the basic parts of an express project.
• Understand what a Templating Language is and be able to list a couple of
popular ones.
• Understand what Middleware is.
• Understand req, res and next in the context of middleware.

Templating Engines
A templating engine is a tool that allows you to insert variables and simple logic
into your views. For instance, you could have a header that updates with the actual
user’s name once they’ve logged in, something that is not possible with plain
HTML. As the lesson mentions, there are several templating languages available for
JavaScript. The tutorial uses Pug (formerly known as Jade) which has a bit of a
learning curve because it looks and feels dramatically different from regular HTML.
If you’ve ever worked with Ruby on Rails you might be more comfortable with ejs,
which is very similar to erb.
It’s up to you which you choose! If you choose not to use Pug you will still be able
to follow the tutorial just fine. Most of the Odin staff prefer ejs to Pug simply
because we like working with HTML, but in the end, there is nothing wrong with
Pug if you like the look of it or want to learn something new.
Middleware
This step of the MDN tutorial mentions middleware, but does not clearly define it.
Middleware is a complicated word for a simple concept. A middleware is just a
plain JavaScript function that Express will call for you between the time it receives
a network request and the time it fires off a response (i.e. it’s a function that sits in
the middle). You will eventually be using several of these functions that will run in a
specific sequence for every request.
For example, you might have a logger (that prints details of the request to the
console), an authenticator (that checks to see if the user is logged in, or otherwise
has permission to access whatever they’re requesting) and a static-file server (if

Nodejs Page 189


has permission to access whatever they’re requesting) and a static-file server (if
the user is requesting a static file then it will send it to them). All of these functions
will be called in the order you specify every time there’s a request on the way to
your app.get("/") function.
It is possible and common to write your own middleware functions (you’ll be doing
that later) so let’s take a minute to demystify what they’re actually doing.
Middleware functions are just plain JavaScript functions with a specific function
signature (that is, it takes a specific set of arguments in a specific order). You’ve
actually already seen it!
The three middleware function arguments are: req, res, and next. Technically,
these are just variables, so you could call them anything, but convention (and the
express documentation) almost always give them these names.
A middleware function:
function(req, res, next) {
// do stuff!
}

When someone visits your site, their web-browser sends a request to your server.
Express takes that request and passes it through all of the middleware functions
that you have defined and used in your project. Each function is defined with these
parameters which might seem familiar to you from the plain Node tutorial that you
went through in the ‘Getting Started’ lesson. Technically, req and res are almost
the same here as they are in vanilla Node, but Express enhances them by adding a
few useful properties and methods to them.
req or request is an object that has data about the incoming request such as the
exact URL that was visited, any parameters in the URL, the body of the request
(useful if the user is submitting a form with some data in it) and many other things.
• You can see everything it includes in the express docs.
res or response is an object that represents the response that Express is going to
send back to the user. Typically, you use the information in the req to determine
what you’re going to do with the res by calling res.send() or another method on
the object.
• Check out the documentation for the response object here!
next is a function that you see a little less often, but is very important to the
functioning of your app. If you are writing or using some middleware that does not
send a response back to the user’s client then you must call the next function at
the end of your middleware function. The next function simply tells express to
move to the next middleware in the stack, but if you forget to call it then your app
will pause and nothing will happen!

Nodejs Page 190


An example middleware
As a quick example, if you wanted to create a simple logging middleware you could
write a function like this:
const myLogger = function(req, res, next) {
console.log("Request IP: " + req.ip);
console.log("Request Method: " + req.method);
console.log("Request date: " + new Date());

next(); // THIS IS IMPORTANT!


}

app.use(myLogger)

app.use is how you load your middleware function into Express so that it knows to
use it. If you stick this bit of code in any express application near the beginning of
your app.js (after the part where you define app = express()) then it will write all of
those details to your console every time you get a network request. When the
logging is complete we call the next() function so that our app can continue.
As a final detail, the order that middleware gets executed in your app matters!
Middleware functions will always run in the order that they are instantiated using
app.use().
Using Git
As you work through this tutorial, make sure to put the node_modules folder in
a .gitignore file.
Assignment
1. Read this intro article on MDN.
2. Begin the project by following this lesson. Be sure to read everything
carefully! There’s quite a bit of important information in this article. You only
have to do part 2 for now. We will continue where we leave off later.
3. For a little more detail on the nature of middleware read the official
documentation here.

Knowledge Checks
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is middleware?
• What is the req object?
• What is the res object?
• Why is next important?
Nodejs Page 191
• Why is next important?
• What does app.use do?

Nodejs Page 192


Express 102: CRUD and MVC
Thursday, July 7, 2022 3:36 PM

After setting up the skeleton for your project it’s time to set up the database. As
usual, there’s quite a bit of background information that you will find useful as you
progress.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain CRUD and how it correlates to HTTP methods in Express.
• Describe MVC and how it correlates to Express.
• Describe databases and ORMs as well as how to use them with Node/Express
apps.
• Design and create your own models using Mongoose.
• Declare object schema and models.
• Describe the main field types and basic validation.
• List a few ways to access model data.
• Test models by creating a number of instances (using a standalone script).

CRUD
CRUD is a concept that comes up a lot in web development, and it’s the type of
thing that might show up in interview questions so it’s worth taking a little time to
make sure you understand what it refers to. Thankfully, it’s a relatively simple
concept.
CRUD stands for: Create, Read, Update and Delete. These are the four basic
functions that you will be building into your database driven apps. Put simply, if
you are designing a CRUD interface that means that users can expect to be able to
do these 4 things to items in the database (providing they have the appropriate
permissions of course).
In your library example, this simply means that we are going to be building the
ability for users to create entries (add books, authors or genres to the database),
read entries (or, retrieve lists of books and other things from the database), update
entries (edit details of an entry), and delete entries (remove them from the
database).
Of course, this is simply a concept and not some sort of rule that must be followed.
You may not want to allow users to do all of these actions, or you may want to
limit which users can do what at any given time. For example, if you are creating a
social networking site, you might only allow users to read the profile information of
their friends or connections, and you might not want to allow people to delete
things at all.

Nodejs Page 193


things at all.
The CRUD operations roughly correlate to the HTTP methods that you can employ
in an express app. This definition can be somewhat flexible, but in general create
correlates to POST (or app.post() in an express app), read correlates to GET
(app.get()), update to PUT (app.put()) and delete to DELETE (app.delete())

MVC
MVC is another common concept in web development and also something that is
likely to come up in an interview question. MVC stands for Model, View, Controller
and refers to the architecture of your code. Basically, it is a way to organize your
application by separating all of the actions into 3 main components: Models, Views
and Controllers.
Models are the basic building blocks of your database. So for every entry in your
DB (books, authors, etc. in our Library Project), you’ll create a model that holds the
details of that entry. Models define the types of information that get used by your
views and controllers.
Views are, of course, the component that generates the UI for your application. In
our case, we’ve selected a templating engine that uses data supplied by a
controller to display the desired information.
Controllers are the components that decide what view to display and what
information is going to be put into it.
MVC Example
Without digging into the code prematurely, consider a very simple photo-
uploading site. Users can upload and then view photos that are all listed on an
index somewhere. In this case, we’ll have a model for our photos that would define
how our photos are stored in the database (DB). The model might specify that
photos should be objects that have a filename, a URL and a date-created field.
We’ll need two views, 1) the index, and 2) the display-photo view which will just
display a single photo.
Our controller then would be called by Express whenever we get an app.get()
request. It would then use the details of the request to determine which view is
shown, and which image is displayed depending on whether the user is requesting
the index or a specific photo’s page.
If this is a little confusing at this point, don’t worry about it too much. You will be
creating models, views, and controllers in the tutorial and it will all become much
clearer once you see them in use.
Which database should I choose?
One final note before diving back into the tutorial. Express does not care about

Nodejs Page 194


One final note before diving back into the tutorial. Express does not care about
which database you use. The lesson lists a few options but ultimately uses
MongoDB. In this case, the actual DB you use matters little. If you later decide that
you would rather use SQL or something else, you should be able to pick it up fairly
easily by reading the documentation. At this point, Mongo is probably the most
popular choice to use with Express so we recommend just sticking with that for
now.
Assignment
1. Continue where we left off with the MDN library tutorial (Part 3)!

Knowledge Checks
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What does CRUD stand for?
• What does the Model in “MVC” refer to?
• What does the View in “MVC” refer to?
• What does the Controller in “MVC” refer to?

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• For a deeper explanation of MVC you could read this article from
freeCodeCamp.
• This crash course video from Web Dev Simplified gives a run-down of how you
should expect to use MongoDB (Mongoose) in Node.js, as well as some
advanced things you can do with object schemas.

Nodejs Page 195


Preparing for Deployment
Thursday, July 7, 2022 3:38 PM

Introduction
We have one thing to attend to before progressing in our web development
journey. We are putting in all of this hard work to make great projects, so naturally
we want to show them off to the world, right? In future lessons, we will be
deploying our applications to a cloud platform, Heroku. Heroku will enable us to
run, build, and operate our web applications in the cloud!
Step 1: Create a Heroku Account
Go to the Heroku website and create an account using the same email address you
used for GitHub and Git.
Step 2: Heroku CLI
Activate your account from the email they sent you. Now, we’ll install the Heroku
command line so that we can interact with the Heroku service. We will use curl to
download a script and run it to install the Heroku CLI. This script may ask for your
sudo password, this is expected. Go ahead and type it in after running the
command below.
Run this command:
curl https://cli-assets.heroku.com/install.sh | sh

Then, type heroku version, which should return something similar to heroku/7.5.1
linux-x64 node-v10.5.0.
Step 3: Add your SSH Key to Heroku
Adding your SSH key lets Heroku know what machine the commands are coming
from, similar to how GitHub uses SSH keys.
In your terminal, type
heroku keys:add

Next, press y and then Enter. Now, type in the email address you used to create
your Heroku account and press Enter. Then, type in the password for your Heroku
account. Next, press y and Enter to allow Heroku to upload your public SSH key.
The terminal may read Invalid credentials provided. Just press any key and the
Heroku website will open in your browser. Log in with the information you created
your account with, and the terminal will reappear and accept your public SSH key.
Conclusion

Nodejs Page 196


At this point, we have the necessary setup to deploy our web applications to the
internet. You could say… we are prepared for deployment. The only thing left to do
is continue on with your web development journey by moving on to the next
lesson.

Nodejs Page 197


Project: Mini Message Board
Thursday, July 7, 2022 3:40 PM

Introduction
Let’s take a quick break from the main Express tutorial to practice what we’ve
already learned. At this point you should know enough to use Express to make
some fun interactive web apps! We’re going to create a super simple message
board.
Assignment

1. Use express-generator to set up a basic project using whichever templating


language you prefer. If you want, you can set it all up manually – it doesn’t really
take that much longer.
• Hint: here are links to some of the more popular templating language docs:
PUG, EJS, Handlebars

2. Initialize a Git repo in your project directory with


git init

Create a .gitignore file in your project directory that includes node_modules.


3. We are going to have 2 routes, the index ("/") and a new-message form ("/new").
The generator already created a router for our index, so find that file and open it
up. It can be found at routes/index.js. There is already a router.get() method for "/"
that should be rendering your index view, so lets add some messages to it.
4. Create an array at the top of your index router called messages and put a couple of
sample messages inside of it like this:
const messages = [
{
text: "Hi there!",
user: "Amando",
added: new Date()
},
{
text: "Hello World!",
user: "Charles",
added: new Date()
}
];

5. Next, in your index template (in the "views" folder) loop through the messages
array using whichever templating language you selected and for each one, display

Nodejs Page 198


array using whichever templating language you selected and for each one, display
the user, text and the date the message was added. Don’t forget to make your
messages available to your template by including it in the res.render ‘locals’ object
(e.g. res.render('index', { title: "Mini Messageboard", messages: messages })).
6. Next let’s set up the new message form. In the router add a router.get() for the
"/new" route and point it to a template named "form". In the views directory
create your form template. Add a heading, 2 inputs (one for the author’s name and
one for the message text) and a submit button. To have the form make a network
request you will need to define it with both a method and an action like so:
<form method="POST" action="/new">
put your inputs and buttons in here!
</form>

7. With your form set up like this, when you click on the submit button it should send
a POST request to the url specified by the action attribute, so go back to your index
router and add a router.post() for "/new".
8. In order to get and use the data from your form, you will need to access the
contents of your form inside router.post() as an object called req.body. The
individual fields inside the body object are named according to the name attribute
on your inputs (the value of <input name="messageText"> will show up as
req.body.messageText inside the router.post function).
9. In your router.post() take the contents of the form submission and push them into
the messages array as an object that looks something like this:
messages.push({text: messageText, user: messageUser, added: new Date()});

10. At the end of the router.post() function use res.redirect('/') to send users back to
the index page after submitting a new message.
11. At this point, you should be able to visit /new (it might be a good idea to add a link
to that route on your index page), fill out the form, submit it and then see it show
up on the index page!
12. Now you’re almost ready to deploy your application on Heroku, but before doing
that, you need to modify a few things just to make life easier for your deployment.
First, you need to specify the exact version of Node that you’re using in your
package.json file; if you don’t remember the version number, just find it using
node -v. Then, add it to your package.json file, so that it will look similar to this:
"engines": { "node": "10.x.y" },

13. Heroku usually requires a Procfile, which specifies all the commands that need to
run on startup. With node.js, this file isn’t obligatory since Heroku searches in the
package.json file for a start script which is already defined in your app, but it’s still
good practice to add it to your project. Create it in your root directory, and add
this single line to it:
web: node ./bin/www
Nodejs Page 199
web: node ./bin/www

14. You’re finally ready to deploy to Heroku! You can first try it on local, using
heroku local web

This will run your app locally using Heroku at http://localhost:5000/. Test it, and if
everything works fine, you can finally create it:
heroku create

Stage and commit the changes that you’ve made since starting this project, and
then push it to your Heroku repository with:
git push heroku main

Nodejs Page 200


Express 103: Routes and Controllers
Thursday, July 7, 2022 3:42 PM

The next step in the MDN express tutorial sets up all the routes and controllers
you’re going to need when creating the Library project. This project is
designed using the MVC (Model, View, Controller) architecture. In a previous
step you set up all the Models (or Database Objects) and in the next step you’ll
be setting up several different views.
If you remember from our earlier lessons, the controller is the code that sits
between the models and the views. It determines which view is going to be
shown, as well as which information is going to populate that view. In this
lesson, you will copy and paste quite a bit of repetitive code to get the
controllers and routes set up, but be sure to read everything in between them!
There is a lot of useful information therein.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Create simple routes.
• Create route-handler callback functions.
• Create a catalog route module.
• Describe approaches for structuring routes and controllers.
• Set up URL endpoints.

Assignment
1. Continue where we left off with part 4 of the Express tutorial

Knowledge Check
This section contains questions for you to check your understanding of this
lesson. If you’re having trouble answering the questions below on your own,
review the material above to find the answer.
• How do you define a route function in Express?
• Name four HTTP verbs a route might need to handle.
• What is a route parameter, and what syntax is used to define one in a
route handler?
• What is a route-handler callback function commonly called?

Nodejs Page 201


Express 104: View Templates
Thursday, July 7, 2022 3:43 PM

This lesson is fun! You’ll be setting up several views, and you’ll start to see your
Application come together. We’ll finally get to see our data showing up in the
browser! This is a long lesson that is broken up into several sub-lessons, so make
sure you click through to see them all.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Describe asynchronous functions.
• Manage asynchronous operations in controller functions.
• Manage flow control when using asynchronous operations.
• Create and extend templates.
• Write templates using Pug.
• Pass information to a template from your view.
• Implement read-only pages.
• Describe how routes works.
• Describe how views and models work in practice.
• Query database using models.
• Describe date handling using luxon.

Assignment
1. Let’s get back to the tutorial.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Why do we use the async module?
• Why are async methods needed and what do they avoid?
• How do we run multiple asynchronous operations in parallel?
• How do we run multiple asynchronous operations in series?
• When do we use async.waterfall() instead of async.series() ?
• How do we nest elements and define attributes in Pug?
• What is a base template and how do we extend it?
• Why do we use luxon instead of the regular date format?

Nodejs Page 202


Project: Express 105: Forms and Deployment
Thursday, July 7, 2022 3:44 PM

This lesson picks up where the last one left off and has you creating the rest of
your views. You’ll be focusing on the forms needed to create and update new
entries in your database. With the knowledge you pick up here, you’ll really be
ready to go create your own data-driven web applications. There is, of course,
more to learn, but finishing this one is a big step towards actually being able to do
your own projects.
It’s another long multi-part tutorial, with plenty of useful information scattered
throughout. Be sure to take your time and read everything!
This is the last lesson on the MDN tutorial. The last step, listed below takes you
through what you need to do to actually deploy your project so you can share it
and show it off, so be sure to link it up in the student solutions below!
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Describe form handling process.
• Describe validation and sanitization.
• Describe routes.
• Work with HTML forms in Express using Pug.
• Use forms to get data from users and update the database with this data.
• Validate and sanitize input using express-validator.
• Write forms to create, update, and delete records from the database.
• Add basic forms and form-handling code to Node websites.

Assignment
1. Let’s get back to the tutorial
2. Read about deploying your app in the last article in this tutorial.

Nodejs Page 203


Project: Inventory Application
Thursday, July 7, 2022 3:45 PM

Introduction
Alright! Let’s flex our skills a little! That tutorial was humongous, and you learned a
lot of things. The only way to make it stick is to practice! For this project you are
going to create an Inventory management app for an imaginary store. It’s up to
you what kind of business this is – you could be selling groceries, car parts, baby-
toys, musical-instruments, ponies or anything!
Your Inventory app should have categories and items, so when the user goes to the
home-page they can choose a category to view, and then get a list of every item in
that category. You should include all of the CRUD methods for both items and
categories, so anybody that’s visiting the site can Create, Read, Update or Delete
any Item or Category.
Assignment
1. Before you begin, take a moment to write down all of the models you’ll need and
the fields that should go in them. It might help to grab a pencil and some paper
and literally draw a diagram like you saw in the MDN tutorial on databases.
• Items should at least have: a name, description, category, price, number-in-
stock and URL, though you should feel free to add more fields if it seems
relevant to the type of business you’ve chosen.
• Categories should at least have a name, a description and a URL.
2. We’re going to follow the basic path that was demonstrated by the MDN tutorial
to set up and flesh out your app, so first choose a templating language and
generate the boilerplate skeleton with express-generator.
3. Create a new Mongo Collection using the web-interface as demonstrated in the
tutorial and then set up your database schemas and models.
4. In the Library tutorial you populated your database with some sample data that
was provided in a populatedb.js file. Actually understanding how that worked was
over your head at the time, but now that you’ve finished that tutorial you’ll be able
to understand how it works. Download the file here and edit it, or re-write it using
the specifics of your models and then run it to populate your database!
5. Set up the routes and controllers you’re going to need.
6. Create all of the ‘READ’ views (i.e. view category, and view item)
7. Create all the forms and build out the controllers you need for the rest of the
CRUD actions.
8. EXTRA CREDIT: For bonus points, try to figure out how to add and upload images
for each item. Use this middleware which was created by the Express team. The
documentation in the README there should be enough to get you going.
9. EXTRA CREDIT: We will learn about creating users with secure passwords in a later

Nodejs Page 204


9. EXTRA CREDIT: We will learn about creating users with secure passwords in a later
lesson, but for now we don’t want just anyone to be able to delete and edit items
in our inventory! Figure out how to protect destructive actions (like deleting and
updating) by making users enter a secret admin password to confirm the action.
10. Deploy it and show off what you’ve done!

Nodejs Page 205


Authentication
Thursday, July 7, 2022 3:47 PM

We learn how to create authentication strategies that allow us to securely sign


users into our applications.

Nodejs Page 206


Authentication Basics
Thursday, July 7, 2022 3:47 PM

Creating users and allowing them to log in and out of your web apps is a crucial
functionality that we are finally ready to learn! There is quite a bit of setup
involved here, but thankfully none of it is too tricky. You’ll be up and running in no
time! In this lesson, we’re going to be using passportJS, an excellent middleware to
handle our authentication and sessions for us.
We’re going to be building a very minimal express app that will allow users to sign
up, log in, and log out. For now, we’re just going to keep everything except the
views in one file to make for easier demonstration, but in a real-world project, it is
best practice to split our concerns and functionality into separate modules.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
PassportJS
• Understand the use order for the required middleware.
• Describe what Strategies are.
• Use the LocalStrategy to authenticate users.
• Explain the purpose of cookies in authentication.
• Refreshed on prior learning material (routes, templates, middleware).
• Use PassportJS to set up user authentication with Express.
Data Security/Safety
• Describe what bcrypt is and its use.
• Describe what a hash is and explain the importance of password hashing.
• Describe bcrypt’s compare function.

Set Up
We’re going to be using another Mongo database, so before we begin log in to
your mongo provider and create a new database and save its URL string
somewhere handy.
To begin, let’s set up a very minimal express app with a single MongoDB model for
our users. Create a new directory and use npm init to start the package.json file
then run the following to install all the dependencies we need:
npm install express express-session mongoose passport passport-local ejs

Next, let’s create our app.js:


IMPORTANT NOTE: For the moment we are saving our users with just a plain text
Nodejs Page 207
IMPORTANT NOTE: For the moment we are saving our users with just a plain text
password. This is a really bad idea for any real-world project. At the end of this
lesson, you will learn how to properly secure these passwords using bcrypt. Don’t
skip that part.
/////// app.js

const express = require("express");


const path = require("path");
const session = require("express-session");
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const mongoDb = "YOUR MONGO URL HERE";


mongoose.connect(mongoDb, { useUnifiedTopology: true, useNewUrlParser:
true });
const db = mongoose.connection;
db.on("error", console.error.bind(console, "mongo connection error"));

const User = mongoose.model(


"User",
new Schema({
username: { type: String, required: true },
password: { type: String, required: true }
})
);

const app = express();


app.set("views", __dirname);
app.set("view engine", "ejs");

app.use(session({ secret: "cats", resave: false, saveUninitialized: true }));


app.use(passport.initialize());
app.use(passport.session());
app.use(express.urlencoded({ extended: false }));

app.get("/", (req, res) => res.render("index"));

app.listen(3000, () => console.log("app listening on port 3000!"));

Most of this should look familiar to you by now, except for the new imported

Nodejs Page 208


Most of this should look familiar to you by now, except for the new imported
middleware for express-session and passport. We are not actually going to be
using express-session directly, it is a dependency that is used in the background by
passport.js. You can take a look at what it does here.
To keep things simple, our view engine is set up to just look in the main directory,
and it’s looking for a template called index.ejs so go ahead and create that:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>hello world!</h1>
</body>
</html>

Creating Users
The first thing we need is a sign up form so we can actually create users to
authenticate! In the Library Tutorial website, you learned about validating and
sanitizing inputs. This is a really good idea, but for the sake of brevity, we’re going
to leave that out here. Don’t forget to include sanitation and validation when you
get to the project.
Create a new template called sign-up-form, and a route for /sign-up that points to
it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Sign Up</h1>
<form action="" method="POST">
<label for="username">Username</label>
<input name="username" placeholder="username" type="text" />
<label for="password">Password</label>
<input name="password" type="password" />
<button>Sign Up</button>
</form>

Nodejs Page 209


</form>
</body>
</html>
//// app.js

app.get("/sign-up", (req, res) => res.render("sign-up-form"));

Next, create an app.post for the sign up form so that we can add users to our
database (remember our notes about sanitation, and using plain text to store
passwords…).
app.post("/sign-up", (req, res, next) => {
const user = new User({
username: req.body.username,
password: req.body.password
}).save(err => {
if (err) {
return next(err);
}
res.redirect("/");
});
});

Let’s reiterate: this is not a particularly safe way to create users in your database…
BUT you should now be able to visit /sign-up, and submit the form. If all goes well
it’ll redirect you to the index and you will be able to go see your newly created user
inside your database.
Authentication
Now that we have the ability to put users in our database, let’s allow them to log-
in to see a special message on our home page! We’re going to step through the
process one piece at a time, but first, take a minute to glance at the passportJS
website the documentation here has pretty much everything you need to get set
up. You’re going to want to refer back to this when you’re working on your project.
PassportJS uses what they call Strategies to authenticate users. They have over 500
of these strategies, but we’re going to focus on the most basic (and most
common), the username-and-password, or what they call the LocalStrategy
(documentation here). We have already installed and required the appropriate
modules so let’s set it up!
We need to add 3 functions to our app.js file, and then add an app.post for our
/log-in path. Add them somewhere before the line that initializes passport for us:

Nodejs Page 210


/log-in path. Add them somewhere before the line that initializes passport for us:
app.use(passport.initialize()).
Function one : setting up the LocalStrategy
passport.use(
new LocalStrategy((username, password, done) => {
User.findOne({ username: username }, (err, user) => {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: "Incorrect username" });
}
if (user.password !== password) {
return done(null, false, { message: "Incorrect password" });
}
return done(null, user);
});
})
);

This function is what will be called when we use the passport.authenticate()


function later. Basically, it takes a username and password, tries to find the user in
our DB, and then makes sure that the user’s password matches the given
password. If all of that works out (there’s a user in the DB, and the passwords
match) then it authenticates our user and moves on! We will not be calling this
function directly, so you won’t have to supply the done function. This function acts
a bit like a middleware and will be called for us when we ask passport to do the
authentication later.
Functions two and three: Sessions and serialization
To make sure our user is logged in, and to allow them to stay logged in as they
move around our app, passport will use some data to create a cookie which is
stored in the user’s browser. These next two functions define what bit of
information passport is looking for when it creates and then decodes the cookie.
The reason they require us to define these functions is so that we can make sure
that whatever bit of data it’s looking for actually exists in our Database! For our
purposes, the functions that are listed in the passport docs will work just fine.
passport.serializeUser(function(user, done) {
done(null, user.id);
});

passport.deserializeUser(function(id, done) {

Nodejs Page 211


passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});

Again, we aren’t going to be calling these functions on our own, they’re used in the
background by passport.
Log in form
To keep things nice and simple let’s go ahead and add the login form directly to
our index template. The form will look just like our sign-up form, but instead of
POSTing to /sign-up we’ll add an action to it so that it POSTs to /log-in instead. Add
the following to your index template:
<h1>please log in</h1>
<form action="/log-in" method="POST">
<label for="username">Username</label>
<input name="username" placeholder="username" type="text" />
<label for="password">Password</label>
<input name="password" type="password" />
<button>Log In</button>
</form>

… and now for the magical part! Add this route to your app.js file:
app.post(
"/log-in",
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/"
})
);

As you can see, all we have to do is call passport.authenticate(). This middleware


performs numerous functions behind the scenes. Among other things, it looks at
the request body for parameters named username and password then runs the
LocalStrategy function that we defined earlier to see if the username and password
are in the database. It then creates a session cookie that gets stored in the user’s
browser, and that we can access in all future requests to see whether or not that
user is logged in. It can also redirect you to different routes based on whether the
login is a success or a failure. If we had a separate login page we might want to go
back to that if the login failed, or we might want to take the user to their user

Nodejs Page 212


back to that if the login failed, or we might want to take the user to their user
dashboard if the login is successful. Since we’re keeping everything in the index we
want to go back to “/” no matter what.
If you fill out and submit the form now, everything should technically work, but you
won’t actually SEE anything different on the page… let’s fix that.
The passport middleware checks to see if there is a user logged in (by checking the
cookies that come in with the req object) and if there is, it adds that user to the
request object for us. So, all we need to do is check for req.user to change our view
depending on whether or not a user is logged in.
Edit your app.get("/") to send the user object to our view like so:
app.get("/", (req, res) => {
res.render("index", { user: req.user });
});

and then edit your view to make use of that object like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<% if (user) {%>
<h1>WELCOME BACK <%= user.username %></h1>
<a href="/log-out">LOG OUT</a>
<% } else { %>
<h1>please log in</h1>
<form action="/log-in" method="POST">
<label for="username">Username</label>
<input name="username" placeholder="username" type="text" />
<label for="password">Password</label>
<input name="password" type="password" />
<button>Log In</button>
</form>
<%}%>
</body>
</html>

So, this code checks to see if there is a user defined… if so it offers a welcome
message, and if NOT then it shows the login form. Neat!

Nodejs Page 213


message, and if NOT then it shows the login form. Neat!
As one last step… let’s make that log out link actually work for us. As you can see
it’s simply sending us to /log-out so all we need to do is add a route for that in our
app.js. Conveniently, the passport middleware adds a logout function to the req
object, so logging out is as easy as this:
app.get("/log-out", (req, res) => {
req.logout(function (err) {
if (err) {
return next(err);
}
res.redirect("/");
});
});

You should now be able to visit /sign-up to create a new user, then log-in using
that user’s username and password, and then log out by clicking the log out
button!
A quick tip
In express, you can set and access various local variables throughout your entire
app (even in views) with the locals object. We can use this knowledge to write
ourselves a custom middleware that will simplify how we access our current user
in our views.
Middleware functions are simply functions that take the req and res objects,
manipulate them, and pass them on through the rest of the app.
app.use(function(req, res, next) {
res.locals.currentUser = req.user;
next();
});

If you insert this code somewhere between where you instantiate the passport
middleware and before you render your views, you will have access to the
currentUser variable in all of your views, and you won’t have to manually pass it
into all of the controllers in which you need it.
Securing passwords with bcrypt
Now, let’s go back and learn how to securely store user passwords so that if
anything ever goes wrong, or if someone gains access to our database, our user
passwords will be safe. This is insanely important, even for the simplest apps, but
luckily it’s also really simple to set up.
First npm install bcryptjs. There is another module called bcrypt that does the

Nodejs Page 214


First npm install bcryptjs. There is another module called bcrypt that does the
same thing, but it is written in C++ and is sometimes a pain to get installed. The
C++ bcrypt is technically faster, so in the future it might be worth getting it
running, but for now, the modules work the same so we can just use bcryptjs.
Once it’s installed you need to require it at the top of your app.js and then we are
going to put it to use where we save our passwords to the DB, and where we
compare them inside the LocalStrategy.
Storing hashed passwords:
Password hashes are the result of passing the user’s password through a one-way
hash function, which maps variable sized inputs to fixed size pseudo-random
outputs.
Edit your app.post("/sign-up") to use the bcrypt.hash function which works like
this:
bcrypt.hash("somePassword", 10, (err, hashedPassword) => {
// if err, do something
// otherwise, store hashedPassword in DB
});

The second argument is the length of the “salt” to use in the hashing function;
salting a password means adding extra random characters to it, the password plus
the the extra random characters are then fed into the hashing function. Salting is
used to make a password hash output unique, even for users who use the same
password, and to protect against rainbow table and dictionary attacks.
Usually, the salt gets stored in the database in the clear next to the hashed value,
but in our case, there is no need to do so because the hashing algorithm that
bcryptjs uses includes the salt automatically with the hash.
The hash function is somewhat slow, so all of the DB storage stuff needs to go
inside the callback. Check to see if you’ve got this working by signing up a new user
with a simple password, then go look at your DB entries to see how it’s being
stored. If you’ve done it right, your password should have been transformed into a
really long random string.
It’s important to note that how hashing works is beyond the scope of this lesson.
To learn more about the subject consider reading This wikipedia article.
Comparing hashed passwords:
We will use the bcrypt.compare() function to validate the password input. The
function compares the plain-text password in the request object to the hashed
password.
Inside your LocalStrategy function we need to replace the user.password !==
password expression with the bcrypt.compare() function.
Nodejs Page 215
password expression with the bcrypt.compare() function.
bcrypt.compare(password, user.password, (err, res) => {
if (res) {
// passwords match! log user in
return done(null, user)
} else {
// passwords do not match!
return done(null, false, { message: "Incorrect password" })
}
})

You should now be able to log in using the new user you’ve created (the one with a
hashed password). Unfortunately, users that were saved BEFORE you added bcrypt
will no longer work, but that’s a small price to pay for security! (and a good reason
to include bcrypt from the start on your next project)
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• This article goes into great detail about the passport local strategy and brings the
magic that happens behind the scenes into the light. It provides a comprehensive
foundation for how session-based authentication works using browser cookies
along with backend sessions to manage users.
• If you like video content, watch this Youtube Playlist by the same author who
wrote the article above. You just need to watch the first 6 videos.

• This video gives a broad overview of some of the different methods to store
passwords in databases, and the risks of some of them.

Nodejs Page 216


Knowledge Checks
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• Which passportJS strategy did we use in this lesson?
• Why does passportJS create a cookie?
• What does the bcrypt.compare() function do?
• Why should we include bcrypt when we begin a project?

Nodejs Page 217


Security Configuration
Thursday, July 7, 2022 3:50 PM

This lesson is a small one, but it is incredibly important. Now that we are dealing
with Authentication, sessions, cookies and user passwords, it is crucial that we do
everything we can so that our authentication system or databases are not
compromised.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Access environment variables using the process object in node.
• Use dotenv to store and make environment variables available to your
application globally.
• Describe how environment variables are handled in version control.
• Have familiarity with nconf’s hierarchical configuration.

Keep it secret, keep it safe


Essentially, in addition to using encryption to secure user passwords we need to
make sure that important sensitive information such as our Express sessions
secret, our MongoDB url (especially if it includes your username and password!)
and any API keys that you might be using stay hidden. Details such as these should
never get committed to a git repo or otherwise published.
Hiding secrets is easily accomplished and there are a handful of ways to do it. One
of the most common is using an npm package called dotenv. Its usage is simple.
Simply create a file called .env in your project directory and fill it with variables that
represent things you need to keep secret using the syntax [key]=[value], for
example, SECRET_KEY="something hard to guess". Important note: you need to
add this file to your gitignore so that it does not get committed to git!
A more robust option is the package nconf. It can be used in place of or alongside
of dotenv. Basically, it allows you to define configuration files in multiple ways for
ultimate flexibility. For example, you could have a config.js file that kept all of your
secrets, but also add the ability to override one of those secrets with a command-
line argument.
Digging into this package can be useful when creating bigger projects where app
configuration needs to be a little more involved. This package makes it easy to
configure things such as separate production and development databases, logging
and debugging options, or anything else.
Assignment
1. The main important takeaway here is to KEEP YOUR SECRETS SECRET by never
accidentally publishing them.

Nodejs Page 218


accidentally publishing them.
2. Read through the documentation for dotenv and nconf. There are other ways
to go about hiding your secrets, but these two packages are popular and
widely used.
3. Go back to your earlier projects and SECURE THEM!

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• If you still want to know more about environment variables this article digs
deeper into variations you might encounter moving forward.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What special kind of variable can be used on a server to store secrets?
• What are two widely used packages that can be used to store and import
these variables?
• What is the name of the file dotenv looks for when injecting these variables
into our app?

Nodejs Page 219


Project: Members Only
Thursday, July 7, 2022 3:52 PM

Introduction
In this project you’ll be building an exclusive clubhouse where your members can
write anonymous posts. Inside the clubhouse, members can see who the author of
a post is, but outside they can only see the story and wonder who wrote it.
This will be a chance for you to use the authentication skills we learned in the last
project, you will also be practicing your database skills so buckle up!
Assignment
1. Begin by thinking about how to set up the database models you are going to
need to accomplish your goal. You will need users with full-names (first and
last), usernames (you can use email for this) passwords and membership-
status. Users should be able to create messages that have a title, a timestamp
and some text. Your database should keep track of who created each
message.
2. Setup your database on Mongo and generate or otherwise create your project
skeleton, including the models you designed in the last step.
3. Start with a sign-up form so you can get some users into your DB! Don’t forget
to sanitize and validate the form fields and secure the passwords with bcrypt.
You should add a confirmPassword field to your sign-up form and then
validate it using a custom validator. Read how to do that here.
4. When users sign up, they should not be automatically given membership
status! What fun is a private club if just anyone can join? Add a page where
members can “join the club” by entering a secret passcode. If they enter the
passcode correctly then update their membership status.
5. Create a login-form using passport.js like we did in the last assignment.
6. When a user is logged in give them a link to “Create a new message” (but only
show it if they’re logged in!). Create the new-message form.
7. Display all member messages on the home page, but only show the author
and date of the messages to other club-members.
8. Add an optional field to the user model called Admin and then add the ability
to delete messages, but only allow users who have admin == true to see the
delete-button and delete messages. You’ll need to add a way to actually mark
a user as an ‘admin’ so either add another secret pass-code page, or just put
an “is admin” checkbox on the sign-up form.
9. By this point, anyone who comes to the site should be able to see a list of all
messages, with the author’s name hidden. Users should be able to sign-up
and create messages, but ONLY users that are members should be able to see
the author and date of each message. Finally, you should have an Admin user

Nodejs Page 220


the author and date of each message. Finally, you should have an Admin user
that is able to see everything and also has the ability to delete messages.
Obviously this is a simple and silly little app, but the things you are practicing
(creating and authenticating users and giving users different abilities and
permissions) are things that will be very useful to you!
10. When you’re satisfied with your work, deploy your project to heroku and
share it below!

Nodejs Page 221


APIs
Thursday, July 7, 2022 3:54 PM

We use what we've learned to create API-only backends that can serve JSON to
any front-end we want.

Nodejs Page 222


API Basics
Thursday, July 7, 2022 3:56 PM

Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Know what REST stands for.
• Explain the purpose of using REST when structuring an API.
• Detail the REST naming conventions for your API endpoints
• Have a reinforced understanding of the HTTP Methods/Verbs
• Describe the Same Origin Policy
• Explain the purpose of CORS
• Use CORS as middleware in Express (Globally and on a single route)
• Configure CORS to only allow certain origins to access our API
• Explain CORS headers

Introduction
In recent years, a new pattern for developing websites has been gaining popularity.
Instead of creating an app that hosts both the database and view templates, many
developers are separating these concerns into separate projects, hosting their
backend and database on a server (either on something like Heroku or on a VPS
like Digital Ocean), then using a service such as GitHub Pages or Netlify to host
their frontend. This technique is sometimes referred to as the Jamstack.
Organizing your project this way can be beneficial because it allows your project to
be more modular instead of combining business logic with view logic. This also
allows you to use a single backend source for multiple frontend applications, such
as a website, a desktop app, or a mobile app. Other developers enjoy this pattern
because they simply like using frontend frameworks such as React or Vue to create
nice frontend-only, single-page applications.
Frontend and backend applications usually talk to each other using JSON, which
you have already encountered if you’ve gone through our frontend JavaScript
course. So at this point, all you really need to learn is how to get your Express
application to speak JSON instead of HTML, which fortunately for you is extremely
simple! The assignment at the end of this lesson will take you through a tutorial,
but essentially all you have to do is pass your information into res.json() instead of
res.send() or res.render(). How easy is that?
It is also quite possible to have an Express app that both serves views and JSON by
using the Express router to set up different routes. If you think back to the
organization of the routes in our Library Tutorial (here’s a link to it). All of our
routes were set up in a catalog module, so to get the view for our list of books you
would access /catalog/books. Setting the Library project up to also serve JSON
Nodejs Page 223
would access /catalog/books. Setting the Library project up to also serve JSON
would be as easy as creating a different router module called api and then
adjusting the controllers so that /catalog/books would serve up the HTML list of
our books and /api/books would serve up the same information as JSON.
REST
The structure of an API can take many forms, for example you could have routes
named /api/getAllPostComments/:postid or /api/posts/:postid/comments.
However, it’s conventional to follow REST (an acronym for Representational State
Transfer), a popular and common organizational method for your APIs which
corresponds with CRUD actions. Following established patterns such as REST make
your API more maintainable and make it easier for other developers to integrate
with your API. Software development is often about clear communication which is
aided by following expectations.
The actual technical definition of REST is a little complicated (you can read about it
on wikipedia), but for our purposes, most of the elements (statelessness,
cacheability, etc.) are covered by default just by using Express to output JSON. The
piece that we specifically want to think about is how to organize our endpoint URIs
(Uniform Resource Identifier).
REST APIs are resource based, which basically means that instead of having names
like /getPostComments or /savePostInDatabase we refer directly to the resource
(in this case, the blog post) and use HTTP verbs such as GET, POST, PUT, and
DELETE to determine the action. Typically this takes the form of 2 URI’s per
resource, one for the whole collection and one for a single object in that collection,
for example, you might get a list of blog-posts from /posts and then get a specific
post from /posts/:postid. You can also nest collections in this way. To get the list of
comments on a single post you would access /posts/:postid/comments and then to
get a single comment: /posts/:postid/comments/:commentid. Below are some
other simple examples of endpoints you could have.
Verb Action Example
POST Create POST /posts Creates a new blog post
GET Read GET /posts/:postid Fetches a single post
PUT Update PUT /posts/:postid Updates a single post
DELETE Delete DELETE /posts/:postid Deletes a single post
Each part of an API URI specifies the resource. For example, GET /posts would
return the entire list of blog posts while GET /posts/:postid specifies the exact blog
post we want. We could nest further with GET /posts/:postid/comments to return
a list of comments for that blog post or even GET
/posts/:id/comments/:commentid for a very specific blog post comment.
CORS
Nodejs Page 224
CORS
The Same Origin Policy is an important security measure that basically says “Only
requests from the same origin (the same IP address or URL) should be allowed to
access this API”. (Look at the link above for a couple of examples of what counts as
the ‘same origin’.) This is a big problem for us because we are specifically trying to
set up our API so that we can access it from different origins, so to enable that we
need to set up Cross-origin resource sharing, or CORS.
Setting up CORS in Express is very easy, there’s a middleware that does the work
for us. The official docs can be found here.
For now, it is acceptable to just allow access from any origin. This makes
development quite a bit easier but for any real project, once you deploy to a
production environment you will probably want to specifically block access from
any origin except your frontend website. The documentation above explains how
to do this.
Assignment
1. This article is a good resource for understanding and organizing RESTful APIs.
2. Read and code along with this tutorial on setting up a REST API in Express. This
is one of the best Express tutorials we’ve come across, it also talks about
modular code organization, writing middleware, and links to some great extra
info at the end.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• A simple example based definition of REST.

Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What does REST stand for?
• What are HTTP verbs and why are they important to an API?
• What is the Same-Origin Policy?
• How do you enable CORS in your Express app?
• Which HTTP verb does each letter in CRUD (Create, Read, Update, Delete)
correspond to?

Nodejs Page 225


API Security
Thursday, July 7, 2022 3:58 PM

Learning Outcomes
By the end of this lesson, you should be able to do or answer the following:
• Explain how token authentication differs from session based authentication.
• What are JSON Web Tokens?
• What is an authorization header? How do we use it?
• Identify and explain the methods used to sign and verify tokens.
• Write custom middleware to verify tokens on a given route.
• Have familiarity with token expiration with JWT.
• Expand PassportJS implementations to use JSON Web Tokens.

Overview
Securing your API is an important step. When we were using Express to serve view templates we
used PassportJS along with a username and password to authenticate users, but that is not the
only way to secure an Express app, and in the context of an API it often makes sense to use a
different strategy. The username and password session pattern that we learned previously will still
work of course, though it is made a little more complicated by the fact that we’ve separated our
front-end code from the back-end.
Another strategy is to generate and pass a secure token between our back-end and front-end
code. Doing so will make sure that our user’s username and password are not compromised and
will also give us the ability to expire our user’s session for added security. The basic idea is that
when a user signs in to our app, a secure token is created, and then for all subsequent requests
that token is passed in the header of our request object. In the end, the process is pretty simple
since you should already be pretty comfortable with using passport to authenticate users.
This strategy, while particularly useful with APIs can be used with a traditional view-template
project as well. The main difference here is that instead of setting and checking a cookie we’re
passing a special token in the header of our request. In our previous Authentication Tutorial, the
Passport middleware checked the cookie that was sent and then either authenticated or denied
our user. In this case, we’re going to do something very similar, but instead of using cookies, we’re
going to pass the token.
Assignment
1. This video is a great resource that explains everything you need to know about creating and
verifying JSON Web Tokens.
2.

Nodejs Page 226


2.

3. This article covers setting up JSON Web Tokens within the PassportJS system that you should
already be familiar with. In this case you don’t really need Passport, but it does handle quite a
bit of stuff that the guy in the video set up manually.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental.
• This article goes even further in depth than the one that we posted above. It provides a little
greater understanding but is harder to follow.
• This article covers the same thing as the above one, but is a little more concise. Might be a
good reference for when you’re setting this up on your own later.

Knowledge Checks
This section contains questions for you to check your understanding of this lesson. If you’re having
trouble answering the questions below on your own, review the material above to find the
answer.
• What is a JSON web token?
• What are two things a secure token will do?
• Where in the code is a secure token passed?

Nodejs Page 227


Project: Blog API
Thursday, July 7, 2022 4:00 PM

Introduction
Do you know what you need? You need a Blog. Or maybe you don’t, or maybe you
already have one, in any case, this project will be a great way to practice and see
the benefits of creating an API only backend. We’re actually going to create the
backend and two different front-ends for accessing and editing your blog posts.
One of the front-end sites will be for people that want to read and comment on
your posts while the other one will be just for you to write, edit and publish your
posts.
Why are we setting it up like this? Because we can! If you already have a portfolio
site and you want to add your blog posts to that site feel free to do that instead of
creating a new site just for that. The important exercise here is setting up the API
and then accessing it from the outside. There are some security benefits to setting
up separate websites for blog consumption and blog editing, but really we’re just
doing it like this to demonstrate the power and flexibility of separating your
backend code from your frontend code.
Assignment
1. Begin by designing your back end models and schemas. How you design it is
up to you, but you might want to think through a few things: - For a simple
blog with only a single author you might not need a user model, but you might
want to set up authentication so that you can protect the editing functions
with a username and password. In that case, it might make sense to set up a
minimal user model, even if you are the only user. - Your blog should have
posts and comments, so think about the fields you are going to want to
include for each of those. - Are you going to require users to leave a username
or email with their comments? - Are you going to display a date or a
timestamp for posts and comments? - Posts should probably have a title, but
should comments? - A useful feature for a blog is the ability to have posts that
are in the database but not published for the public to read. How might you
designate published vs unpublished posts in your DB?
2. Set up your express app, and define the models in mongoose.
3. Set up your routes and controllers! Think about RESTful organization for this
one. Most of the examples in the previous lesson were centered around posts
and comments so this shouldn’t be too tricky. - You can test your routes
however you want. Using curl in a terminal is one handy way, but it can be just
as effective to use a web browser. There are some platforms that allow you to
send PUT and POST requests without needing to set up and fill out HTML
Nodejs Page 228
send PUT and POST requests without needing to set up and fill out HTML
forms. Postman is probably the most popular.
4. Once your API is working you can focus on your front-end code. Really, how
you go about this is up to you. If you are comfortable with a front-end
framework then go for it! If you’re happier using plain HTML and CSS that’s
fine too. All you should have to do to get your posts into a website is to fetch
the correct API endpoint and then display the results. Working with fetch and
APIs from a front-end perspective is covered in this lesson
5. Create a second website for authoring and editing your posts. You can set this
up however you like but the following features might be useful: - A list of all
posts that shows whether or not they have been published. - A button to
publish unpublished posts, or to unpublish published ones! - A ‘NEW POST’
form. If you want to get fancy, you could use a rich text editor such as
TinyMCE. - The ability to manage comments (i.e. delete or edit them).
6. How much work you want to put into the front-end code on this one is up to
you. Technically this is a back-end focused course so if you don’t actually need
or want a blog on your website feel free to focus mainly on getting a REST API
up and running.

Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it
supplemental.
• As mentioned earlier, the cli-tool curl and Postman are popular choices for
testing your routes. Alernatively, the Thunder Client VS Code extension is
another way of testing your API.

Nodejs Page 229


Testing Express
Thursday, July 7, 2022 4:01 PM

In this section we learn what it takes to write tests for our Express projects.

Nodejs Page 230


Testing Routes and Controllers
Thursday, July 7, 2022 4:01 PM

Unit Testing is important for many reasons that we probably don’t need to cover
right now. If you’ve already taken our basic JavaScript course you’ve already
encountered Unit Testing, and the point of this lesson is not to teach you the
philosophy or mechanics of writing tests, but how they apply to our Express
applications and APIs.
Learning Outcomes
By the end of this lesson, you should be able to do or answer the following:
• Use the supertest module to test Express routes/controllers.
• Describe how supertest handles our express application.
• Explain the functionality superagent provides to supertest.
• Describe what the done parameter is used for.
• Explain and have a firm understanding of .expect() method’s functionality.
• Have familiarity with supertest’s documentation and methods.
The most important, basic requirement for testing something in your code is that it
must be in an exported module. This is true for both custom middleware and your
routes/controllers, so the very first thing you need to do is separate those things
into their own modules, if they aren’t already.
In the case of routes, you already know how to do this using Express.Router. Below
is a very simple example.
//// app.js
const express = require("express");
const app = express();

app.use(express.urlencoded({ extended: false }));

const indexRouter = require("./index");


app.use("/", indexRouter);

app.listen(3000, () => console.log("running"));


//// index.js
const express = require("express");
const index = express.Router();

const array = [];

index.get("/", (req, res) => {

Nodejs Page 231


index.get("/", (req, res) => {
res.json({ name: "frodo" });
});

index.get("/test", (req, res) => res.json({ array }));

index.post("/test", (req, res) => {


array.push(req.body.item);
res.send('success!');
});

module.exports = index;

These two files, app.js and index.js simply define a couple of routes and then set
up and start our express app. For the moment we do not need to test app.js
because it only contains code that starts and runs an express app! It doesn’t
include any of our own logic so we don’t need to test it. index.js however does
include some things that we want to test.
To facilitate actually testing these routes we’re going to use a library called
Supertest, so go ahead and npm install supertest --save-dev and while it’s installing
take a few minutes to look through the readme on their git repo (linked above).
In the examples below we’re going to use Supertest inside of a Jest style
describe/test block, but the syntax and use of these are common among most
testing libraries, so the concepts should be easily replicated in Mocha with Chai or
Jasmine or Tape or whatever testing library you prefer.
Here’s our test file:
const index = require("../index");

const request = require("supertest");


const express = require("express");
const app = express();

app.use(express.urlencoded({ extended: false }));


app.use("/", index);

test("index route works", done => {


request(app)
.get("/")
.expect("Content-Type", /json/)
.expect({ name: "frodo" })
.expect(200, done);

Nodejs Page 232


.expect(200, done);
});

test("testing route works", done => {


request(app)
.post("/test")
.type("form")
.send({ item: "hey" })
.then(() => {
request(app)
.get("/test")
.expect({ array: ["hey"] }, done);
});
});

Let’s step through it piece by piece.


To begin, we have to import the module we’re testing, in this case it’s the file
index.js from above.
const index = require("../index");

Next, we include both supertest and express. We’re setting up a new express app
and then using the index router that we imported previously. The reason we have
to do this setup here is because we are not actually touching our original app.js
file. The main reason that we’re doing it this way is so that we can avoid calling the
app.listen command and starting our server, but it’s also useful because, in larger
apps, we can skip some of the optional configuration steps and only include the
bits that we need for our testing purposes. In a larger test suite, it would probably
be useful to abstract this part out to its own file that gets imported into each test
file.
const request = require("supertest");
const express = require("express");
const app = express();

app.use(express.urlencoded({ extended: false }));


app.use("/", index);

The tests themselves are relatively simple thanks to the Supertest library!
Remember that we imported supertest as the function request which we use as
seen below. We call it on our freshly created express app, pass it our route, and
then use it to make sure that the responses match the types and content that we
expect.
Nodejs Page 233
expect.
Notice the parameter done that is passed into the test callback. Most testing
libraries use this to signal that the test is complete in the case of asynchronous
operations. In this case, supertest allows us to pass it into the last .expect and calls
it for us. Thanks, supertest!
test("index route works", done => {
request(app)
.get("/")
.expect("Content-Type", /json/)
.expect({ name: "frodo" })
.expect(200, done);
});

Our second test is very similar to the first one, but tests the post method. You can
(and should) read about all the possible functions on the supertest readme, so I
won’t go into the details of every step here. The last bit however is important to
us. By this point in your JavaScript career, you should be familiar with Promises, so
the .then() syntax should be familiar. In this case we wait for the POST request to
finish and then we call the GET request when that promise resolves to check if that
item has been pushed into the array.
test("testing route works", done => {
request(app)
.post("/test")
.type("form")
.send({ item: "hey" })
.then(() => {
request(app)
.get("/test")
.expect({ array: ["hey"] }, done);
});
});

If we were using a real database here, then we would want to do something similar
using either a test or a mock database. We’ll talk about setting something like that
up in a separate lesson. Suffice it to say for now that you do not want to run test
code on your production database!
Assignment
1. Make sure that you read through the Supertest docs
2. Supertest actually pulls from another related project called Superagent. Any
method that you can call in Superagent you can also call from supertest, so
you’ll need to take a look through the SuperAgent docs as well.
Nodejs Page 234
you’ll need to take a look through the SuperAgent docs as well.

Knowledge Checks
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is the motivation behind SuperTest?
• What is the purpose of done? What convenience does supertest provide
concerning it?
• What is the difference in handling errors when using .end() method in
conjunction with .expect() provided by SuperTest?
• What are the methods provided by SuperAgent to handle multipart requests
and how to use them?

Nodejs Page 235


Testing Database Operations
Thursday, July 7, 2022 4:04 PM

Introduction
When the code that you are testing has to touch a database, the amount of setup
that you have to do gets quite a bit more complicated. Obviously you don’t want to
run your testing code on your production database because of the risk of
compromising your user’s data. In this lesson we’re going to set up a new in-
memory version of a mongo database and then tell our app to use that when
running our tests.
Learning Outcomes
By the end of this lesson, you should be able to do the following:
• Explain the purpose of using a separate database for testing.
• Use mongodb-memory-server to create a testing database
• Familiarize yourself with an alternative method of database setup for your
testing environment.
But do you even need to test that?
Before diving in, you might want to consider whether or not the database
operations you’re testing even need to be tested in the first place. If you are simply
reading and writing straight from a database using mongoose or some other db
module, you might not really need to test that code. Mongoose (and presumably
all other popular db modules) already has plenty of tests for all of its actions, so if
you are just serving up a JSON API and all you’re doing is leveraging functions from
another module then those operations are already covered.
If your queries are complicated, you might justify adding tests to make sure that
you are using them correctly and that the code you have written is doing what you
intend it to, and if you are using any of your own code to do some filtering, sorting,
or other manipulations of the data you will want to test that as well. In the case of
your own code, however, it would be better if you could pull those things out into
their own modules, separate from your database operations so you can test them
without messing with the database.
mongodb-memory-server
There are cases, however, when you are going to want to test things that touch
your database, so this lesson is going to cover how to do that.
We’re going to use an npm package called mongodb-memory-server. You can see
the specifics on their github repo, but basically this package will spin up a fresh in-
memory mongoDB server that you can connect to with mongoose, and then use
for your testing environment. Since it’s creating a fresh DB every time you don’t
have to worry about trying to keep your data in sync, or polluting your production
Nodejs Page 236
have to worry about trying to keep your data in sync, or polluting your production
database.
Setting it up is actually pretty simple, but there are a few things you need to do.
First, in your actual app, you need to move your mongo/mongoose setup into its
own file as seen in the simple example below.
//// mongoConfig.js
const mongoose = require("mongoose");

const mongoDb = `YOUR MONGO URL`;

mongoose.connect(mongoDb, { useNewUrlParser: true });


const db = mongoose.connection;
db.on("error", console.error.bind(console, "mongo connection error"));

The above code should look very familiar to you by now.. it’s the same setup code
we’ve been using all along. The only difference is that we’ve moved it out to its
own file so that in our test files we can use a different config file that sets up
mongodb-memory-server for us. All you have to do now is
require("./mongoConfig") in your app.js file.
Next we need to create a separate config for our testing environment. The config
file that you can find on the mongodb-memory-server repo README should work
just fine. Below is a slightly edited version of it. Copy this to a new file called
mongoConfigTesting.js
//// mongoConfigTesting.js
const mongoose = require("mongoose");
const { MongoMemoryServer } = require("mongodb-memory-server");

async function initializeMongoServer() {


const mongoServer = await MongoMemoryServer.create();
const mongoUri = mongoServer.getUri();

mongoose.connect(mongoUri);

mongoose.connection.on("error", e => {
if (e.message.code === "ETIMEDOUT") {
console.log(e);
mongoose.connect(mongoUri);
}
console.log(e);
});

Nodejs Page 237


mongoose.connection.once("open", () => {
console.log(`MongoDB successfully connected to ${mongoUri}`);
});
}

module.exports = initializeMongoServer;

Now, if your tests are set up similarly to the tests in our last project, you can simply
call this function in your testing file, and then any operations that work on your
mongo database will use this testing one instead of your real one.
A couple of notes
Since you are starting your tests with a fresh database it will probably be useful for
you to use a beforeAll function in your testing suite to add a couple of items to the
database before running tests.
This is also not the only way to set up a testing environment! If you are using
nconf, or command-line arguments or anything else to set up your development
and production environments, you could easily add a testing environment that
uses this mongodb-memory-server. The Jest Docs demonstrate an alternative (but
similar) setup to the simple one we have here. The common element here is that
no matter how you accomplish it, our goal is to use this alternative DB when
running our tests.
Knowledge Check
This section contains questions for you to check your understanding of this lesson.
If you’re having trouble answering the questions below on your own, review the
material above to find the answer.
• What is the purpose of using a separate database for testing?
• How would you create and setup a testing database using the npm package
mongodb-memory-server?
• What is an alternative method of database setup for your testing
environment?

Nodejs Page 238


Video Course + Project
Thursday, July 7, 2022 2:19 AM

course: Angular - The Complete Guide (2022


Edition)
Instructor : Maximilian Schwarzmüller
Section lectures Time
1 Getting Started 14 41 min
2 The basics 30 1 hr 54 min
3 Course project- The basics 17 1 hr 4 min
4 Course project- Component and Data binding 6 31 min
5 Course project - Directives 2 7 min
6 course project-Services and Dependency Injection 8 31 min
7 Course project- Routing 15 46 min
8 course project- Observables 2 6 min
9 course project- Forms 23 1 hr 15 min
10 course project - Http 8 34 min
Total 125 7 hours 48 min

Project Name : Shopping List and Recipe book

Angular Page 239


Video Course + Project
Thursday, July 7, 2022 2:19 AM

Course : NestJS Zero to Hero - Modern TypeScript Back-end


Development
Instructor: Ariel Weinberger
section lectures time
1 Introduction to NestJs & Pre-requisites 5 6 min
2 Task Management Application (Rest API) 24 1 hr 42 min
3 Validation and error Handling 7 20 min
4 Data Persistence - PostgreSQL and TypeORM 19 1 hr 9 min
5 Auth Part1 - Authentication 15 1 hr 16 min
6 Auth Part2 - Task Ownership and Restrictions 9 24 min
7 Bonus Configuration Management 8 36 min
8 Bonus Graph QL + MongoDB 28 1 hr 41 min
total 115 7 hr 23 min

Project Name : Task Management Application

Nestjs Page 240


Final Project
Thursday, July 7, 2022 4:56 PM

Introduction
You’ve come a long way, congratulations! At this point you should feel comfortable
with building new applications and using DB to model and store data. This project
will require you to put all of that knowledge to the test. It’s not going to be easy,
but should be well within your capabilities and it will be a great portfolio piece.
You’ll be building Facebook. As with our previous lessons, how much effort you
want to put into the styling and front-end is up to you. The important stuff is the
data and backend. You’ll put together the core features of the platform like users,
profiles, posts, “liking”, “friending”, and the news feed. You’ll also implement
signing in with the real Facebook using our old friend passportJS.
Some features of Facebook are things we haven’t been exposed to such as chat,
realtime updates of the newsfeed and notifications. You won’t be responsible for
those unless you’re feeling really confident in your skills at this point. (It’s not that
hard.. look here if you want to see what’s involved.)
Assignment
Build Facebook! You’ll build a large portion of the core Facebook user functionality
in this project. We won’t be worrying about some of the more flashy front-end
stuff unless you really want to, but you shouldn’t need it to get a nice user
experience.
This project will give you a chance to take a relatively high level set of
requirements and turn it into a functioning website. You’ll need to do some of your
own research and read the documentation for a few of the modules we’ll be using.
Keep the following requirements in mind. We’ll cover specific steps to get started
below this list.
1. Users must sign in to see anything except the sign in page.
2. Users should be able to sign in using their real facebook details. This is fairly
easily accomplished using PassportJS, and you should be able to use the
knowledge you already have to figure it out from the documentation.
3. Users can send friend requests to other users.
4. A user must accept the friend request to become friends.
5. Users can create posts. (begin with text only)
6. Users can like posts.
7. Users can comment on posts.
8. Posts should always display with the post content, author, comments and
likes.
9. Treat the Posts index page like the real Facebook’s “Timeline” feature – show

Final Project Page 241


9. Treat the Posts index page like the real Facebook’s “Timeline” feature – show
all the recent posts from the current user and users she is friends with.
10. Users can create Profile with a photo (you can get this from the real facebook
when you sign in using passport)
11. The User Show page contains their profile information, profile photo and
posts.
12. The Users Index page lists all users and buttons for sending friend requests to
those who are not already friends or who don’t already have a pending
request.
13. Deploy your app to Heroku!
Extra Credit
1. Make posts also allow images (either just via a url, or by uploading one.)
2. Allow Users to upload and update their own profile photo.
3. Create a guest sign-in functionality that allows visitors to bypass the login
screen without creating an account or supplying credentials. This is especially
useful if you are planning on putting this project on your résumé - most
recruiters, hiring managers, etc. will not take the time to create an account.
This feature will give them an opportunity to look at your hard work without
going through a tedious sign-up process.
4. Make it pretty!
Getting Started
1. Think through the data architecture required to make this work. There are lots
of models and the relationship between them is more complicated than
anything you’ve done before. How are you going to model a user’s list of
friends and friend requests? Posts should be able to have likes and comments
associated with them, how are you going to model that? Take some time to
plan your approach before diving in.
2. Start your app however you like, using the express-generator or from scratch.
3. Work your way down the list above! Each step will involve a new challenge,
but you’ve got the tools.
4. You can populate data like users and posts with fake data using the Faker
module from npm. To accomplish this create a new JavaScript file named
seeds.js which imports your mongoose models and uses the faker module to
generate and save a bunch of new users.

Final Project Page 242

You might also like