launchschool

How to use jQuery and Handlebars in your website

jQuery and Handlebars are both external to the core functionality of JavaScript. Both are libraries that we can use and include when making websites. Doing so is very simple. We include <script>s in the head of our HTML file, as in the following example:

<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  </head>
  <body>
    <h1>Hello, World</h1>
  </body>
</html>

Note that jQuery is now modular, so you may want to consider whether you want to include the entire library. Above I chose to download it from Google's CDN, but there are other options listed here.

Using APIs to make things happen on the web

Towards the end of the Launch School core syllabus, we start to work with API calls. These allow us to pass information between servers. It turns out, this is really useful to be able to do.

Many if not most of the things you do online involve API calls. That little widget on the side of the web page that shows today's weather: an API call. Even things like Siri which aren't exactly web pages: using API calls.

Being able to make those calls and to interact with the services available through the internet gives users all sorts of power. The creativity comes, then, in how these things are all combined together.

That said, the dreams of the connected web have been somewhat oversold in the past. What are we on now, web 4.0?.

From a technical perspective, in this part of the course I enjoyed seeing how simple text in the form of JSON objects was behind so much of our communication and interactivity online these days. (All the more reason to have more secure ways of exchanging those plain text data).

I was also conscious of how much creativity and widened thinking has gone into expanding the possibilities of what HTML, CSS and a bit of JavaScript can do over the internet. Some of these capabilities mean that we're straining the possibilities in this area or that, but above all I take away some inspiration in how people made do with what they had instead of feeling like they needed to reinvent the wheel.

How events drive programming for the web

As part of my studies for Launch School, last month I was introduced to the idea of 'events' and how we can use the DOM and JavaScript to cause things to happen without having to force a full reload of the page. This is sometimes known as AJAX requests, which stands for Asynchronous JavaScript And XML.

In this mental model, we can think of the HTML and CSS code loaded by the browser (when you visit a website, for example) as the part which we can interact with. Absent any JavaScript code we include, this is somewhat static.

If we add in some JavaScript, we can first make sure that the DOM is fully loaded. For this we add an event listener for the DOMContentLoaded event.

Then after that, the sky is the limit. We can add event listeners to basically anything in our document (or just the whole document object itself). This is the list of events that we can watch for.

From reading outside the course, I know that companies' monitoring of user behaviour via JavaScript events triggering is a really big source of privacy violations or issues. I am not sure how the current model of how the web works serves to limit these violations. For instance, do people know that their mouse movements and clicks and patterns of mouse behaviour can all be monitored while they're on a site. So even if you don't click on an object, the website can still track that you're hovering over a particular element. That, to my mind, is a step too far, but it's the world we live in. You can disable JavaScript completely, but then you break a majority of sites that you're visiting.

Of course, if you're browsing in something like emacs' eww, or in brow.sh, then you bypass this problem somewhat.

Back to the JavaScript, though, the most interesting thing I found was the sheer amount of events that the browser was built to encounter. I'd love to see a chart showing how and when all these events were added to the browser's capabilities.

The Four Positions for Inserting Elements into the DOM

As part of my Launch School studies, I'm revising the ways we can use JavaScript to insert nodes into the DOM. These can be simple text nodes, or they could be elements, but the difficult part I've found is recalling the arguments for position. This is an argument you add into your method call which states where the node, for example, should be inserted. It looks something like this in action:

let newNode = document.createElement('p');
document.body.insertAdjacentElement('beforebegin', newNode);

Where you see beforebegin is where you can include one of four different text strings:

  • beforebegin — before the calling element
  • afterbegin — immediately inside the element, before its first child
  • beforeend — inside the element, just after its last child
  • afterend — after the element itself

The words chosen for these position arguments never felt fully clear to me, so writing it out has been useful to clarify their meaning. This is also a useful code excerpt, from the MDN docs:

<!-- beforebegin -->
<p>
  <!-- afterbegin -->
  foo
  <!-- beforeend -->
</p>
<!-- afterend -->

Different ways of accessing the text contents of DOM nodes in JavaScript

For a while now while studying the DOM and JavaScript's interaction with the web browser, I've been wondering about various properties available on nodes that relate to their contents or text values.

I spent a bit of time the other day unpacking what each of those do. This is a bit of code you can play around with to evaluate how they all work:

<!doctype html>
<html lang="en-US">
  <head>
    <title>title</title>
    <meta charset="UTF-8">
  </head>

  <body>
    <div>
      <h1>First bit of text.</h1>
      <p>Some <span>old</span> text</p>
      <textArea>pre-written</textArea>
    </div>
  <script>
    console.log(document.querySelector('div').innerHTML);
  </script>
  </body>
</html>
  • .textContent

This property concatenates the text of the element plus all child elements including any whitespace (from the HTML markup itself).

  • .data

This is the text content of a text node.

  • .nodeValue

For text nodes, this is the text content of that text node (i.e the same as .data). For comments, it is the comment content. For element nodes (and most other types), it is null.

  • .value

This is either an attribute property on an element (in which case the value is whatever was assigned to that property), or it is the contents of a textArea element.

  • .innerText

This is the rendered text (i.e. as displayed on the browser page) of the node and child nodes. Note, if it is not being rendered, then this will be identical to the .textContent property.

  • .innerHTML

This is all the HTML markup contained within the element (including nested elements and text (and whitespace). Note that sometimes this will just be plain text. Note too, that this can be used to create HTML inside an element as well.

Using CSS selectors with JavaScript DOM methods

I've been using JavaScript methods that interact with the DOM all week as part of my Launch School course. Among them, document.querySelector() and document.querySelectorAll() seem really useful. I realised I didn't fully understand the selectors that you were supposed to pass in as an argument, so I'm writing up some of what I discovered about them here. (See here for the documentation).

The simple part is when you have a single selector. Three important selectors are:

  • id selectors (#) — so if the html contains an id attribute of 'some-id', then you could write #some-id.
  • class selectors (.) — so if the class was 'special-style', then you can write .special-style.
  • tag selectors — for these, you just write the page itself

When combining tags, there is a complex set of options depending on whether things are siblings or descendants or children. For the most part that is TMI. The important ones to remember are:

  • descendant selector combinations — place a space between elements — so if you want to select all <div> tags that descend (however far down in the tree) from a <p> tag, then you can write p div.
  • child selector — place a > between the elements — this allows you to find elements that are direct children (i.e. no intermediary levels) of other elements. p > div will find all div elements that are the direct children of paragraph elements.

(For a more complete exploration of this topic, specifically the combination of selectors, read this blogpost.)

Turning array-like objects into arrays with JavaScript

I've long been wondering how the following piece of code works:

// assuming a website with a bunch of elements with 'h1' tags
let liveCollection = document.querySelectorAll('h1');
let arrayVersion = Array.prototype.slice.call(liveCollection); // returns that live collection of elements in the form of an array

So I thought I'd write up a little on my understanding of how it works.

Array.prototype.slice is simple. The slice() function is stored inside the prototype object property on the Array constructor. That's all as you might expect given how JavaScript handles things with the prototypal chain.

But why are we using call here, and how does that work when you pass in liveCollection as the object within which you want to invoke slice()?

Normally when we have an array that we want to call slice on, we have to do that using slice as a method. Arrays have the slice method available to them through the prototypal chain (also in the Array.prototype object). But our array-like object (i.e. the live collection in the example above) don't have those methods available to them.

Under the hood, when the slice method is invoked, what it does is iterates over the array as part of its more special functionality (which I'll ignore for now). If we have an array-like object with a length and with elements that you can sequentially iterate over, then we can run something like slice on that array-like object.

So how do we bring these two pieces together? We use call. call is a way of using a function inside a different execution context. In our case, we want to use the execution context (i.e. what this is set to) of the live collection, but still have it use the functionality defined in slice. call and apply are both ways we can do this.

(For more on this, there are some very useful explanations in this stackoverflow post.)

Understanding the use cases for Closures in JavaScript

I spent today revising some of my Launch School JS225 topics. Among those was the idea of closures, or in other words how functions can capture and package away any variables or 'state' in scope at the point of function definition.

I hadn't fully realised just how useful that can be. Other languages have other ways of realising the same functionality. In JavaScript, it turns out this is a really useful feature because it effectively allows you to keep some variables, functions and whatever else available to our objects or functions, but we can control access to them. They are accessible via whatever interfaces we provide, but to an outsider trying to access those elements via our API or function calls, they are effectively private.

There are a bunch of ways that this is useful in things that I don't yet understand and haven't studied yet (async or promises seem high up that list) but closures play a role in those as well.

I write all of this mainly because it's useful from time to time to step out of the weeds and remind oneself why any or all of this is actually useful.

What is Lexical Scope?

Scope defines what functions / variables and values are available at any point in a programme. Lexical scope is when you can derive the scope from looking at the code, or by looking at its position within the code. Lexical scope is also known as static scope.

The source code of our JavaScript code — in my example — defines the scope. It particularly relates to functions and nested functions. In those cases, we can create a hierarchy of scopes.

The inner functions have access to everything outside them, but the outer functions don't have access to everything from the inner functions.

Every function creates a new local variable scope. Every block also creates a new local variable scope. The code doesn't have to be executed for these scoping rules to be true, for these inner and outer scopes to exist.

This example below will log 'hello from inner scope' but will then give a ReferenceError since the variable secret is only available / accessible inside the inner scope function:

function outerScope() {
  function innerScope() {
    let secret = 'this is in inner scope';
    console.log('hello from inner scope'); 
  }

  innerScope();
  console.log(secret);
}

outerScope();

Working with JavaScript's Object Prototype model

Today I worked on some more exercises relating to implementing object-oriented design patterns in JavaScript.

I'm taking the position that a lot of my difficulty in absorbing the materials is because JavaScript itself wasn't designed with this in mind. Any implementations that look or seem intuitive are probably going to be hacky, or hide complexity under some syntactical sugar.

The exercises revealed some models for how to work with OLOO code (see this for an example), particularly when you want to conceal some kind of 'private' data along with your encapsulation of methods. For this latter implementation, an IIFE seems to do the trick, though it also feels a bit of a hack.

Tomorrow I will try to complete the rest of my exercises for the module and then get some more practice of these paradigms / models in examples of my own creation.

Two Ruby patterns around map and reduce

When you're going to choose a method to work to transform a group of n things in Ruby, there are two broad patterns you can choose: work with a map function or work with a reduce / inject function.

This pattern choice was recently explained to me as part of my Ruby education at Launch School. I hadn't fully grokked that the choice around how you transform a bundle of things (an Array, perhaps) really can be summarised by those two options.

You use a map method when you want to transfer your array into another array of (transformed) things. (For example, you wanted to transform an array of lowercase names into an array of uppercase names).

example_array = ['alex', 'john', 'terry', 'gill']
transformed_array = example_array.map(&:upcase) # => ["ALEX", "JOHN", "TERRY", "GILL"]

You use a reduce method when you want to transform n number of things (inside your array) into a single thing. (For example, you wanted to sum up the values of an array).

example_array = [1, 3, 5, 7, 9]
transformed_array = example_array.reduce(:+) # => 25

How the Internet Works

The internet. It just works. Understanding exactly how is a bit more complicated than many pieces of engineering. The more you examine the different aspects and parts that make it up, the more you see complexity concealed under the surface.

Visiting this website, for instance: it feels like a trivial thing to do, but there are many different parts making that happen, from the parts that actually transport the bits of data across the physical infrastructure, to the pieces that serve it all to you on a secure connection (ensuring that what I've written hasn't been altered by a third-party).

I've just finished Launch School's LS170 module which takes you a decent way down in the weeds to explain exactly how all of these pieces fit together to make up 'the internet'. So today I thought I'd retransmit some of that as a way of cementing it in my own mind.

At a very abstract level, the internet can be thought of as a network of networks. A network itself is a set of two or more computers which are able to communicate between each other. This could be the computers attached to a home network, or the computers that connect through a central server to a particular Internet Service Provider or ISP.

The internet makes use of a series of 'protocols', shared rules and understandings which have been developed or accreted over time. These protocols allow a computer on the other side of the planet to communicate in a mutually comprehensible manner. (If these shared sets of rules didn't exist, communicating with strangers or sending messages from one server to another would be a lot more difficult).

So once we have this top-down understanding of the internet as a bunch of networks that interact with each other, what, then, is the process by which a web browser in the United Kingdom communicates with a web server in China? Or in other words, if I want to access a website hosted on a Chinese webserver, how does that series of communication steps work to make that happen?

At this point, it's useful to make use of another abstraction: communication across the internet happens across a series of layers. There are several different models for these various layers. Two of the more common models — the OSI model and the TCP/IP model — are represented below:

layered-system-osi-tcp-ip-comparison.png

At the top level — "Application" — you have your website or whatever the user comes into contact with that is being served up to your web browser, let's say. All the layers below that are progressively more and more specialised, which is another way of saying that they become progressively less comprehensible if you were to eavesdrop on the data as it were passing over the wire or through the fibre optic cable.

Let's move through the big pieces of how information is communicated, then, starting at the bottom. (I'll mostly follow the TCP/IP model since it's a bit less granular and allows me to split things up in a way that make sense). This chart will help keep all the pieces in your mind:

layersofinternet.png

Note that each layer has something known as a 'protocol data unit' or PDU. A PDU is usually made up of a combination of a header, payload or chunk of data and an optional footer or trailer. The header and footer contain metadata which allows for the appropriate transmission / decoding etc of the data payload.

The PDU of one layer is used by the layer below or above it to make up its own separate PDU. See the following diagram as an illustration:

encapsulation.png

Physical Layer

Before we get into the realm of protocols, it's worth remembering and reminding ourselves that there is a physical layer on which all the subsequent layers rely. There are some constraints relating to the speed or latency with which data can be transmitted over a network which relate to fixed laws of physics. The most notable of those constraints is the fact of the speed of light.

Ethernet is the protocol that enables communication between devices on a single network. (These devices are also known as 'nodes'). The link layer is the interface between the physical network (i.e. the cables and routers) and the more logical layers above it.

The protocols for this layer are mostly concerned with identifying devices on the network, and moving the data among those devices. On this layer, devices are identified by something called a MAC (Media Access Control) address, which is a permanent address burned into every device at the time of manufacturing.

The PDU of the Ethernet layer is known as a 'frame'. Each frame contains a header (made up of a source address and a destination address), a payload of data, and a footer.

Internet Layer — The Internet Protocol (IPv4 or IPv6)

Moving up a layer, part of the Ethernet frame is what becomes the PDU for the internet or network layer, i.e. a packet.

This internet layer uses something known as the internet protocol which facilitates communication between hosts (i.e. different computers) on different networks. The two main versions of this protocol are known as IPv4 and IPv6. They handle routing of data via IP addressing, and the encapsulation of data into packets.

IPv4 was the de facto standard for addresses on the internet until relatively recently. There are around 4.3 billion possible addresses using this protocol, but we are close to having used up all those addresses now. IPv6 was created for this reason and it allows (through the use of 128-bit addresses) for a massive 340 undecillion (billion billion billion billion) different addresses.

Adoption of IPv6 is increasing, but still slow.

There is a complex system of how data makes its way from one end node on the network, through several other networks, and then on to the destination node. When the data is first transmitted, a full plan of how to reach that destination is not formulated before starting the journey. Rather, the journey is constructed ad hoc as it progresses.

Transport Layer — TCP/UDP

There are a number of different problems that the transport layer exists to solve. Primarily, we want to make sure our data is passed reliably and speedily from one node to another through the network.

TCP and UDP are two protocols which are good at different kinds of communication. If the reliability of data transmission is important to us and we need to make sure that every piece of information is transmitted, then TCP (Transmission Control Protocol) is a good choice. If we don't care about every single piece of information — in the case of streaming a video call, perhaps, or watching a film on Netflix — but rather about the speed and the ability to continuously keep that data stream going, then UDP (User Datagram Protocol) is a better choice.

There are differences between the protocols beyond simply their functionality. We can distinguish between so-called 'connection-oriented' and 'connectionless' protocols. For connection-oriented protocols, a dedicated connection is created for each process or strand of communication. The receiving node or computer listens with its undivided attention. With a connectionless protocol, a single port listens to all incoming communication and has do disambiguate between all the incoming conversations.

TCP is a connection-oriented protocol. It first sends a three-way handshake to establish the connection, then sends the data, and sends a four-way handshake to end the connection. The overhead of having to make these handshakes at the beginning and at the end, it's a fairly costly process in terms of performance, but in many parts of internet communication we really do need all the pieces of information. Just think about an email, for example: it wouldn't be acceptable to receive only 70% of the words, would it?

UDP is a connectionless protocol. It is in some ways a simpler protocol compared to TCP, and this simplicity gives it speed and flexibility; you don't need to make a handshake to start transmitting data. On the negative side, though, it doesn't guarantee message delivery, or provide any kind of congestion avoidance or flow control to stop your receiver from being overwhelmed by the data that's being transmitted.

Application Layer — HTTP

HTTP is the primary communication protocol used on the internet. At the application layer, HTTP provides communication of information to applications. This protocol focuses on the structure of the data rather than just how to deliver it. HTTP has its own syntax rules, where you enclose elements in tags using the < data-preserve-html-node="true" and > symbols.

Communication using HTTP takes the form of response and request pairs. A client will make a 'request' and it'll receive (barring some communication barrier) a 'response'. HTTP is known as a 'stateless' protocol in that each request and response is completely independent of the previous one. Web applications have many tricks up their sleeve to make it seem like the web is stateful, but actually the underlying infrastructure is stateless.

When you make an HTTP request, you must supply a path (e.g. the location of the thing or resource you want to request / access) and a request method. Two of the most common request methods are GET and POST, for requesting and amending things from/on the server respectively. You can also send optional request 'headers' which are bits of meta-data which allow for more complicated requests.

The server is obliged to send a HTTP status code in reply. This code tells you whether the request was completed as expected, or if there were any errors along the way. You'll likely have come across a so-called '404' page. This is referring to the 404 status code indicating that a resource or page wasn't found on the server. If the request was successful, then the response may have a payload or body of data (perhaps a chunk of HTML website text, or an image) alongside some other response headers.

Note that all this information is sent as unencrypted plain text. When you're browsing a vanilla http:// website, all the data sent back and forth is just plain text such that anyone (or any government) can read it. This wasn't such a big issue in the early days of the internet, perhaps, but quite soon it became more of a problem, especially when it came to buying things online, or communicating securely. This is where TLS comes in.

TLS or Transport Layer Security is sometimes also known as SSL. It provides a way to exchange messages securely over an unsecured channel. We can conceptually think of it as occupying the space between the TCP and HTTP protocols (at the session layer of the OSI framework above). TLS offers:

  • encryption (encoding a message so only authorised people can decode it)
  • authentication (verifying the identity of a message sender)
  • integrity (checking whether a message has been interfered with)

Not all three are necessarily needed or used at any one time. We're currently on version 1.3 of TLS.


Whew! That was a lot. There are some really good videos which make the topic slightly less dry. Each of these separate sections are extremely complex, but having a broad overview is useful to be able to disambiguate what's going on when you use the internet.