\ \ | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / | \ \

JavaScript Talk - test_04.html

[220118] Framework Free - Functional HTML Rendering and State Management in Vanilla JS - Drew Warren by UtahJS (Oct 4, 2019)

Description:
There are a lot of librarires and frameworks (React, Vue, JQuery, Angualr(2)...) available to web developers today that provide a myriad of benefits and solutions, but they all have a learning curve. This talk will teach you how to accomplish all of this without having to import any packages, learn any libraries, or set up any framework environments using JavaScript functions that are natively available and supported in all major browsers. (www.utahjs.com)

5:22 - Establishing vocabulary and giving context to 'Framework Free - Functional HTML Rendering and State Management in Vanilla JS':
What is a framework? Wikipedia says a web framework is a software framework designed to support the development of web applications. web frameworks provide a standard way to build and deploy web apps on the worldwideweb. their aim to automate the overhead associated with common activity to perform web development. examples include JQuery, Backbone, AngularJS, ReactJS, Vue and others. so, for the purpose of this talk, libraries and framework will be synominous.

So What is Functional HTML Rendering?
simply put, we're going to use functional programming techniques with javascript to render HTML elements. So what is Functional Programming?

So what is Functional Programming?
first is the concept of a pure function. a pure function is one that given the same input, will always return the same output, and also produce no side effects. 2nd is composition. Composition is the act of combining small methods into a larger task. we create specialized functions that do one thing, then we can string them together or pass them into each other to accomplish much more complex tasks. last is Imutability. imutability is the idea of not changing the contents of a variable once it has been created. a common technique to achieving immutability is that instead of changing a variable, we create a new variable and assign to it the work we've done on the starting variable. the best way to understand the paradigm of Functional Programming is to build something with the Functional Programming language (and lessons learned from that will make you a better Javsascript developer).

7:50 - What is Vanilla JS? ...And DOM APIs?
Vanilla JS means JavaScript that can be run in any major browser with no compiling and importing. and... to be clear... the DOM APIs we are discussing are NOT Javascript. the DOM was designed to be agnostic of any one programming language. and similarly, javascript is not limited to only running in the browser, and this is how we have server-side javascript w/ NodeJS and other things. but it is in the web browsers that we are able to directly access DOM APIs using javascript. the browser will parse HTML text into nodes and objects, called the Document Object Model (or DOM), so that programming languages can connect to the page.
   • so when we call Document.createElement() (a method that creates the HTML element specified by tagName), we are using a javascript method supported by the browser to access the DOM API. quick disclaimer, the DOM is inherently object oriented -- so unfortunately, we're going to break some of the rules that 'author' laid out with functional programming. so... again, Vanilla Javascript means javascript that runs in any major browser without a build step, compiler, webpack, babble -- none of that.

9:15 - Single Page Application (SPA) vs. Multiple Page Applications (MPA)
with the Single Page App, it's important to understand the concept with regard to functionally rendered HTML. a single page app is just that, an application that exists on a single page. you have one HTML file, and rather than routing to multiple HTML files, you use javascript to update a page to HTML. one of the benefits is that all the resources of an app can be loaded just once on the initial load. further actions of the user won't trigger another load. once a SPA is loaded, you can theoretically disconnect from the internet and continue to use the application to go from view to view. this does lead to a longer initial load time, which is a trade off. some other trade offs can come in the form of SEO, browser history behavior (like whether your back button does anything) and of course if a user has javascript disabled -- you're app is just not going to work. there are some work arounds. you can use metatags to help with the SEO, URL parameter manipulation if you want the back button to work, and node script tag to show your user they should enable javascript. and these are all things to consider before deciding if an SPA is the right choice for your app.

10:35 - Functional HTML Rendering (a Blank Canvas)
so we have a blank canvas, and now we want to put something on it:

<!DOCTYPE html>
<html>
<head>
   <title>Framework Free</title>
   <link rel="stylesheet" type="text/css" href="./styles.css">
</head>
<body id="app" />
   <script src="./scripts.js"></script>
</html>


11:38 - Creating Greeting Container
• in the first function, we're going to call a querySelector to target this container div by its class name and set it to a variable.
• then we'll call document.createElement() to create a paragraph element and set that to a variable.
• next, we set the className property of the element. this lets us add a class... note: this is not functional programming, we're changing the variable.
• after that we call a createTextNode() function -- this is going to return a text node.
• then we append our text node to our paragraph element,• • and then finally, we append our paragraph element to our container using the element's appendChild() methods.
   
• in the second function, we take a different approach. we create the element as a blank div, then we use the outer HTML property to more or less completely rewrite it.
so there is the innerHTML property which is the stuff between the open and closed tags, and the outerHTML is the stuff 'in between and including the tag'. so it's a one stop shop for applying an id, a class, event handlers, data attributes -- that will set the tags as well as anything inside them.
so any valid HTML string in this second to last line can be used with outerHTML. here, we're transforming an empty div to a heading level one with a class name and some text content. -- and finally, we pin that to our container.

// create and add greeting to greeting container
function sayHello() {
  const container = document.querySelector(".js-hello-container");
  const newHello = document.createElement("p");
  newHello.className = "hello-text";
  const newHelloNode = document.createTextNode("Hello!");
  newHello.appendChild(newHelloNode);
  container.appendChild(newHello);
}

function sayBonjour() {
  const container = document.querySelector(".js-hello-container");
  const newHello = document.createElement("div");
  newHello.outerHTML = "<h1 className='french-hello'>Bonjour!<h1>";
  container.appendChild(newHello);
}

14:18 - Destroy an Element
so now that we have some HTML, but our user wants to visit another page, and we can't just keep appending Children and tacking stuff onto the bottom. so we need to clean up our mess and start fresh. we start by grabbing a reference to the element we want to remove the contents of. here, we've chosen our hello container, you can target the whole body, and id, class name (whatever you can find with your document.querySelector() method or other methods). the easy way is to just set the innerHTML to an empty string. so that will take everything in between your starting and closing tag, and make it disappear. however, there is another way to accomplish this seen in the while loop of our first function fastGoodbye(). this loop looks for the first child of our targeted element, and as long as it finds one, it will call removeChild.
so we're adding elements, we're removing elements, but this doesn't look any better than writing raw HTML. so why write 3 or 4 functions to get a single line of HTML?

// clear the greeting container
function fastGoodbye() {
  const container = document.querySelector(".js-hello-container");
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
}

function slowerGoodbye() {
  const container = document.querySelector(".js-hello-container");
  container.innerHTML = "";
}

15:39 - Create Elements from an Array
so here's where composition comes back into play. we've got our function that does one thing; it gives us an html element. well, instead of one string we want to show, what if we have an array of strings? we can pass our functions into a higher order function like the map method available on arrays to return an html element for each value in the array. so here, instead of making one line with three functions, we're making four elements by writing four functions. what if we want forty elements? so let's say we have our forty different greetings, and instead of divs, we want them rendered as <il> elements. ... so here we change our container to a 'ul', and change the one parameter div to 'li' -- 6,500 lines of HTML hidden with one small change in your code.

// create elements from an array
const listOfGreetings = ["Bonjour", "Hola", "Howdy", "Konnichi wa"];

// create and add each greeting

function allTheGreetings() {
  const container = document.querySelector(".js-hello-container");
  return listOfGreetings.map(greeting => {
    const greetingToAdd = document.createElement("div");
    container.appendChild(greetingToAdd);
    greetingToAdd.innerHTML = greeting;
  });
}

16:55 - Higher Order Functions
at its core, a higher order functions is one that takes a function as a parameter. this parameter function is often referred to as a callback. you can build your own higher order functions to do all sorts of wonderful things, like piping, mapping, flat mapping, all sorts of combinators that will blow your mind. one favorite is to take an array of objects and return an object, b/c keys are a value from the object (like an ID), and then the value is the objects themselves; this is often called a dictionary b/c it lets you easily look up objects with something like the ID.
there are a few that are natively included in javascript as array methods (Map, Filger, and Reduce). [see 18:10 for descriptions...] Higher Order Functions are really the bread and butter of taking data structures and returning HTML.

19:00 - Functional HTML Rendering
so what is a render() function? a render function is a function you can call that will cause your app to be or become another state. it will make your application. in this example, the render function is the showPageOne(). it will clear the contents of the app, then will return Header, and then return the contents of the page.
so what does a render function require? if it's going to make your app, then it needs to undestand the state of your app to know what to cause your app to be or become.

// create and add a nav bar
function buildHeader() {
  const app = document.getElementById("app");
  const pageOneButton = document.createElement("button");
  app.appendChild(pageOneButton);
  pageOneButton.outerHTML = 
    '<button onclick="showPageOne();">Page One</button>';
  const pageTwoButton = document.createElement("button");
  app.appendChild(pageTwoButton);
  pageTwoButton.outerHTML = 
    '<button onclick="showPageTwo();">Page Two</button>';
}

// clear the app, create and add first page
function showPageOne() {
  const app = document.getElementById("app");
  while (app.firstChild) {
    app.removeChild(app.firstChild);
  }
  buildHeader();
  firstBuild();
}

19:35 - State Management (lots of functions)
application state is the information necessary for your render process to display the proper elements with the proper attributes. so using that definition we can manage state a couple different ways, but you better believe they're all going to involve functions. the more complex the app, the functions you're going to have to call to display the proper elements with the proper attributes. we can do this statically like in the showPageOne() function [see above example], no matter where you are when you call this function, you're going to get your header and the page one contents. or we can do it dynamically by passing in state [like below with render(state) function]; so again we'll clear the page and then we'll call a layout that will look up the piece of state to determine the layout, and then the contents similarly, and finally the progress.

function render(state) {
  clearPage();
  buildLayout(slides[state.slide].layout);
  addContent(slides[state.slide].type, slides[state.slide].content);
  addProgress(state);
}

20:45 - State Management (localStorage)
so state is great, but the internet by default is stateless. how do we handle that? we need to store our state somewhere we can access after our session. to really have some permanence, we'd want to store this in a database. but the application isn't so important that losing the state is going to have a severe negative impact on our user, we can just use localStorage. localStorage will allow us to cache information in the browser and access it at a later point. since I'm storing an object, and localStorage only stores strings, I'm using some JSON APIs to stringify and parse the object.
so in this example (w/ function getState()...), I have an initial state in case the user has either purposefully or accidentally cleared their localStorage, and then when I increment the slide, I create a new object that looks like my state with an update; and then I call object assign to apply that to the starting state changing the fields that are present in my updated state. so it's important to note here that I did not mutate the state object that I got, we created a new object. if I were to console.log my starting state right before this return, it would look the same at the end of the function as it does at the beginning but I get a new state that I can set to local storage -- that's the immutability.

const initalState = { slide: 0 };

function getState() {
  return JSON.parse(localStorage.getItem("frameworkFree"));
}

function incrementSlide(state) {
  const slideUpdate =
    state.slide < slides.length - 1
      ? {
          slide: slides[state.slide].number + 1
        }
      : { slide: 0 };
  localStorage.setItem(
    "frameworkFree",
    JSON.stringify(Object.assign({}, state, slideUpdate))
  );
  return render(getState());
}

22:03 - Why? (useful errors)
so now we know how to use vanilla js to make a SPA -- but why? was this purely an academic endeavor? did our quest to find out if we could, eclipse our responsibility to ask if we should? No. there are some objective benefits as well as some subjective ones that you'll get if you go framework free. first, errors. let's compare the console errors we get when we try to reference an undefined variable in javascript versus in ReactJS. [23:03 for more info ...bottom line, vanilla javascript error summaries are a lot less than ReactJS...].
the next benefit is code readability. when comparing the code of hello world SPA in javascript (see below) to one with ReactJS, ReactJS uses thousands of lines of code from several files just to render 'Hello World' onto the page, compared to the 6 lines of code (seen below) for vanilla js. so the newer thing (frameworks like ReactJS) are not always the better thing.

function sayHello() {
  const container = document.getElementById("app");
  const newHello = document.createElement("div");
  container.appendChild(newHello);
  newHello.innerHTML = "Hello World!";
}

\ \ \ \ | / / / / / | \ \ \ \ | / / / / / | \ \ \ \ | / / / / / | \ \ \ \ | / / / / / | \ \ \ \

 

 

 

 

else if (x > 10) {
   alert("x is larger than 10");
}
else {
   alert("x is 10");
}


var x = parseInt(prompt("Enter a number: "));
if (x < 10)
{
   document.getElementById is less than 10";
}


arr.sort([compareFunction])
• used in sorting for a compare function. it will sort in alphabetical order, but not helpful is sorted.


[extra notes]

[Extra stuff:] code and stuff
    ...more explainer here supposedly so.

 

And some more text...
And some more text...
And some more text...

 

Thank you for your patience.