GithubHelp home page GithubHelp logo

flexnav's Introduction

FlexNav

Homework Maybe

Examine the files in the other/homework folder. index.html is your starting point and index-done.html the goal. Your assignment is to edit index.html so it matches the goal.

Midterm

Copy the other/homework folder from the previous section (Flexnav) into a stand alone project.

  • index.html is your starting point
  • index-done.html the goal
  • edit index.html so it matches the goal
  • try not to copy directly, use index-done.html only when you get stuck

One task you will have to perform is not in the index-done.html file.

Using the notes in Basilica:

  • add an empty div to the page
  • use JavaScript to change the content of the div when the user clicks on the tabs

Make sure to create a local Git repo.

When you are done push your local repo to Github and use Netlify to deploy your assignment.

Send me a link to the Github repo as well as the Netlify site

Reading

JavaScript Preview & Review - Boulevards de Paris

Recall: document.querySelector('<css selector>') returns the first selected item.

Navigate to this Wikipedia article.

Paste the following in the browser's console and test:

var first = document.querySelector("a");

document.querySelectorAll() returns a collection (nodeList) of the items on the page:

var all = document.querySelectorAll("a");

Demo: console history.

Right click to inspect the first listed boulevard (Boulevard Auguste-Blanqui) and find <div class="mw-category"> in the DOM. (Note: You can reference the currently selected element using $0 in the console.)

var category = document.querySelector(".mw-category");

We can use our category variable as the basis for a subsequent, more targeted query:

var links = category.querySelectorAll("a");

Examine the methods on the resulting nodeList. Try links.length in the console.

Our nodeList looks like an array but isn't. Let's convert the nodeList into an Array:

var linksArray = Array.from(links);
  • Examine the methods on the resulting Array and compare them to the methods on a nodeList
  • Examine one of the anchor tags from the resulting array in the console:
linksArray[0];
linksArray[0].text;

Arrays

We commonly use loops to iterate through an array and perform some action.

Below we initialize an empty array linkText and then loop through the linksArray using its length property. For every item in linksArray we use Array.push() to add it to linkText:

var linkText = [];

for (let i = 0; i < linksArray.length; i++) {
  linkText.push(linksArray[i].textContent);
}

See for on MDN.

Note: another way to create our array of text items is:

var linkText = [];

for (let link of linksArray) {
  linkText.push(link.text);
}

See for...of on MDN.

Let's look at a couple of important array methods: array.map() and array.filter()

Here's an example that uses the array's map method to isolate the text content from our linksArray:

var linkTextTwo = linksArray.map(function (link) {
  return link.textContent;
});
var linkTextTwo = linksArray
  .map(function (link) {
    return `${link.textContent} is in paree`;
  })
  .join(" AND ");

Let's use another Array method, filter, to isolate only those boulevards that contain a specific string:

var de = linkText.filter(function (streetName) {
  return streetName.includes("de");
});

The Terminal

There are many good reasons to acquire a basic understanding of the command line terminal. In this class we will use the Terminal app for GIT and GITHUB as well as for Node Package Manager (NPM).


A Note For Windows Users

A rough equivalent to the Unix Terminal is Powershell but there are important differences. Alternatives to Powershell include the app that comes with Git for Windows aka "Git Bash." Unless you are very experienced with Windows, I suggest using Git Bash instead of Powershell on Windows.


Some basic shell commands (note: the convention in documentation is to use $ to indicate a prompt - do NOT include it when copying and pasting a command):

$ pwd  // print working directory
$ cd <path-to-folder>
$ cd .. // go up one level
$ cd ~ // go to your home directory
$ ls  // list files
$ ls -l  // flags expand the command
$ ls -al

Demo: tab completion and history.

Demo: on a mac you can cd into a folder via drag and drop or by copying and pasting a folder into the terminal.

Before continuing we will run the following commands.

$ node --version
$ npm --version
$ git --version
$ node
> var total = 12+12
> total
> var el = document.querySelector('.anything') // error
> .exit // or control + c to exit node
$ clear // or command + k to clear the terminal

Use cd or the copy and paste method to cd into today's folder.

Initialize GIT and Create a Branch

Configure your installation of git:

$ git config --global user.name "John Doe"
$ git config --global user.email [email protected]
$ git config --global init.defaultBranch main
$ git config --list
$ :q

Create a personal Access Token

Initialize your repository:

$ git init
# $ touch .gitignore
# $ echo node_modules >> .gitignore
$ git add .
$ git commit -m 'initial commit'
$ git branch inclass
$ git checkout inclass

Note the .gitignore file.

Exercise: make a small change to the .gitignore file and the readme and merge them into the main branch.

The Project

Today we will be building this simple page. The UI is spare to keep things simple.

Create and index.html page in app and add a link to styles.css in index.html:

<link rel="stylesheet" href="css/styles.css" />

Add the following to index.html:

<nav>
  <ul>
    <li><a href="index.html">cuisines</a></li>
    <li><a href="chefs.html">chefs</a></li>
    <li><a href="reviews.html">reviews</a></li>
    <li><a href="delivery.html">delivery</a></li>
  </ul>
</nav>

Node Package Manager (NPM)

Node Package Manager is an essential part of the web design and development ecosystem. Node includes NPM as part of its install.

In order to familiarize you with node packages and to test your Node installation we will install a server with hot reloading - as opposed to using VS Code's GoLive extension.

Note the presence of package.json in today's folder. Examine it in VS Code.

JSON (JavaScript Object Notation) is a file format often used for transmitting data. It is ubiquitious in web development.

{
  "name": "flex-nav",
  "version": "1.0.0",
  "description": "A simple navbar",
  "main": "index.js",
  "scripts": {
    "start": "browser-sync start --server 'app' --files 'app'"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "browser-sync": "^2.26.0"
  }
}

NPM init

We can easily recreate this file.

  1. Delete package.json
  2. cd to navigate to today's directory
  3. Then initialize npm and install browser-sync:
$ npm init
$ npm install browser-sync

Note:

  • the installed the software is listed in package.json dependencies (Browser Sync)
  • the addition of the installation folder: node_modules
  • the new package-lock.json
  • the .gitignore file (added by me) declares that the contents of the node_modules folder should not be tracked by git

Examine the contents of node_modules.

Browser Sync is an NPM Package that is developed by a team using Github.

$ npm install browser-sync

Add the script ("browser-sync start --server 'app' --files 'app'") to package.json.

This script is a command line. It was written by consulting the command line documentation.

Make a small change to the HTML and note the hot reloading.

Use ctrl-c to shut down the server.

Try editing the start script to specify the port number:

"scripts": {
  "start": "browser-sync start --port 1234 --server 'app' --files 'app'"
},

Restart the server with $ npm run start.

Flexbox

What is Flexbox?

  • A good reference cheat sheet
  • flex is a display attribute like block, none, inline
  • Do not confuse it with positioning which we have looked at for absolute, relative, static and fixed positioning
  • Get familiar with Can I Use and feature detection

Add and review some basic formatting in app/styles.css:

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
    "Oxygen", "Ubuntu", "Helvetica Neue", Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
a {
  text-decoration: none;
  color: #333;
}
ul {
  margin: 0;
  padding: 0;
}
nav ul {
  list-style: none;
  background-color: #ffcb2d;
}

Note the complex looking font-family value. It is quite common to use a system font stack that allows each operating system to use its native font. Google it.

You could try font-family: system-ui; but that only works in certain browsers. Consult caniuse.

nav ul {
  ...
  padding-top: 1rem;
  display: flex;
  justify-content: space-around;
  /* boder on the bottom */
  background-image: linear-gradient(
    to bottom,
    #ffcb2d 0%,
    #ffcb2d 95%,
    #9b8748 100%
  );
}

nav a {
  padding: 4px 8px;
  border: 1px solid #9b8748;
  border-radius: 3px 3px 0 0;
  background-color: #f9eaa9;
  opacity: 0.8;

  /* tab gradient */
  background-image: linear-gradient(
    to bottom,
    rgba(255, 236, 165, 1) 0%,
    rgba(232, 213, 149, 1) 6%,
    rgba(253, 233, 162, 1) 94%,
    rgba(253, 233, 162, 1) 100%
  );
}
/* prevents collapsing */
nav li {
  display: flex;
}

Note: without wrap there is a horizontal scrollbar on very small screens: flex-wrap: wrap;

Important: Add an active class to the first anchor tag in the navbar.

nav a:hover,
nav .active {
  background-image: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 1) 0%,
    rgba(224, 226, 240, 1) 6%,
    rgba(254, 254, 254, 1) 53%
  );
  border-bottom: none;
  opacity: 1;
}

Aside: Attribute Selectors

A selector can use HTML tag attributes. nav .active could be written nav a[class="active"] or just [class="active"]

See https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors


We have a meta tag:

<meta name="viewport" content="width=device-width" />
@media (min-width: 460px) {
  nav ul {
    padding-left: 1rem;
    justify-content: flex-start;
  }
  nav li {
    margin-right: 1rem;
  }
}

See this Pen for some basic info on how to control flexbox responsively.

Aside: Flex Order

Flex order property (demo only):

nav :nth-child(2) {
  order: 1;
}

JavaScript Navigation

We will add an active class to the tabs when they are clicked on.

Link the empty JavaScript file in index.html above the closing body tag.

<script src="js/scripts.js"></script>

Add to scripts.js:

var tabs = document.querySelector("nav a");
console.log(tabs);

We need to use querySelectorAll because we are gathering more than one item:

var tabs = document.querySelectorAll("nav a");
console.log(tabs);
console.log(tabs.length);

Now we need to attach an eventListener to each of the tabs. addEventListener() requires you to pass in a specific, individual element to listen to. You cannot pass in an array or node list of matching elements.

var tabs = document.querySelectorAll("nav a");

for (let i = 0; i < tabs.length; i++) {
  tabs[i].addEventListener("click", makeActive);
}

function makeActive(event) {
  console.log(event.target);
  event.preventDefault();
}

Since NodeLists have a forEach method we can also do this:

tabs.forEach(function (tab) {
  tab.addEventListener("click", makeActive);
});

Using an Arrow function shortcut (for anonymous functions):

tabs.forEach((tab) => tab.addEventListener("click", makeActive));

Let's use classList again to add a class to the link we click on:

var tabs = document.querySelectorAll("nav a");

tabs.forEach((tab) => tab.addEventListener("click", makeActive));

function makeActive(event) {
  event.target.classList.add("active");
  event.preventDefault();
}

Lets remove the class from all tabs before we add it so that only one is active at a time:

var tabs = document.querySelectorAll("nav a");

tabs.forEach((tab) => tab.addEventListener("click", makeActive));

function makeActive(event) {
  tabs.forEach((tab) => tab.classList.remove("active"));
  event.target.classList.add("active");
  event.preventDefault();
}

We can separate the class removal out into its own function and then call that function (makeInactive();):

var tabs = document.querySelectorAll("nav a");

tabs.forEach((tab) => tab.addEventListener("click", makeActive));

function makeActive(event) {
  makeInactive();
  event.target.classList.add("active");
  event.preventDefault();
}

function makeInactive() {
  tabs.forEach((tab) => tab.classList.remove("active"));
}

Aside: Prettier

Prettier is a code formatter.

You can install and configure the Prettier extension in VSCode - but that will only work in VSCode.

Lets install it using NPM:

npm install -D prettier

Create .prettierrc in the app folder.

{
  "singleQuote": true,
  "trailingComma": "none",
  "semi": false
}

And test.

If using prettier preferences in VS Code:

"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
  "editor.formatOnSave": true
},
"[html]": {
  "editor.formatOnSave": true
},
"[css]": {
  "editor.formatOnSave": true
},
"prettier.singleQuote": true,
"prettier.trailingComma": "all",

Content

Add some variables to the bottom of scripts.js with content:

var cuisines =
  "<h1>Cuisines</h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis.</p>";

var chefs =
  "<h1>Chefs</h1> <p>Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.<p>";

var reviews =
  "<h1>Reviews</h1> <p>Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis.</p>";

var delivery =
  "<h1>Delivery</h1> <p>Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.</p>";

Create an empty div with a class of content below the navbar in the html:

<div class="content"></div>

Create a reference to it and initialize our page with some text using innerHTML:

var contentPara = document.querySelector('.content');
...
contentPara.innerHTML = cuisines;

Style it using CSS:

.content {
  padding: 1rem;
}

Note that we can access the value of the link's href by using event.target.href:

function makeActive() {
  console.log(event.target.href);
  ...
}

So let's make the content of the .content div depend on the link's href. We will use the string method includes as a test for simple equality will fail:

function makeActive(event) {
  console.log(event.target.href);
  makeInactive();
  event.target.classList.add("active");

  if (event.target.href.includes("chefs")) {
    contentPara.innerHTML = chefs;
  }

  event.preventDefault();
}

Expand the conditions:

function makeActive(event) {
  makeInactive();
  event.target.classList.add("active");

  if (event.target.href.includes("cuisines")) {
    contentPara.innerHTML = cuisines;
  } else if (event.target.href.includes("chefs")) {
    contentPara.innerHTML = chefs;
  } else if (event.target.href.includes("reviews")) {
    contentPara.innerHTML = reviews;
  } else if (event.target.href.includes("delivery")) {
    contentPara.innerHTML = delivery;
  }

  event.preventDefault();
}

DOM manipulation: view source.

In web development parlance this is akin to what is known as a Single Page Application or "SPA".

Aside - Design Patterns

Let's examine the samples in other/design-patterns (these are non-trivial examples, you do not need to understand everything, just the basic concepts - static, fragments and SPA or single page application):

  • static/cuisines.html - uses static HTML pages
  • fragments/index-spa-fragments - a single page application with scrolling
  • spa/index-spa-js.html - a single page application with JavaScript

All three approaches are valid and common. For pedagogical purposes we have modeled our design after the last one - a single page application with JavaScript.

Compare our current project with the static version above.

We cannot:

  • refresh the page without losing context
  • copy and page a link to share with others
  • use back and forward buttons in the browser
  • we have very limited search engine optimization
  • our site will not work without JavaScript

The problem with what we've built might be termed maintaining state and routing. If you refresh the browser while you are on the Reviews tab the page reinitializes to show the Cuisines tab and content.


NB: we have a bug in our code. Everything works but if (event.target.href.includes('cuisines')) will never be true.

<li><a href="cuisines.html" class="active">cuisines</a></li>

Event Delegation

Instead of listening for clicks on each individual tab:

tabs.forEach(tab => tab.addEventListener('click', makeActive));

We are going to use "event delegation."

Use:

// tabs.forEach((tab) => tab.addEventListener("click", makeActive));
document.addEventListener("click", makeActive);

Everything works but try clicking on the paragraph and the yellow background.

We will use an if statement and the JavaScript "not" (!) operator to ensure that the user has clicked on a link in the navbar before running our code:

function makeActive(event) {
  if (!event.target.matches("a")) return; // NEW
  console.log(event.target);
  makeInactive();
  event.target.classList.add("active");
  if (event.target.href.includes("cuisines")) {
    contentPara.innerHTML = cuisines;
  } else if (event.target.href.includes("chefs")) {
    contentPara.innerHTML = chefs;
  } else if (event.target.href.includes("reviews")) {
    contentPara.innerHTML = reviews;
  } else if (event.target.href.includes("delivery")) {
    contentPara.innerHTML = delivery;
  }
  event.preventDefault();
}

Working with Objects

let obj = {
  a: 1,
  b: 2,
};

console.log(obj.a);

obj.c = 3;

delete obj.a;

Use <script src="js/data-object.js"></script> in index.html:

const data = {
  cuisines:
    "<h1>Cuisines</h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis.</p>",

  chefs:
    "<h1>Chefs</h1> <p>Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.<p>",

  reviews:
    "<h1>Reviews</h1> <p>Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis.</p>",

  delivery:
    "<h1>Delivery</h1> <p>Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.</p>",
};

Reinitialize using "dot" accessor method - e.g. data.cuisines:

contentPara.innerHTML = data.cuisines; // NEW

And use the accessor in the makeActive function:

function makeActive(event) {
  if (!event.target.matches("nav ul a")) return;
  makeInactive();
  event.target.classList.add("active");
  if (event.target.href.includes("cuisines")) {
    contentPara.innerHTML = data.cuisines; // NEW
  } else if (event.target.href.includes("chefs")) {
    contentPara.innerHTML = data.chefs; // NEW
  } else if (event.target.href.includes("reviews")) {
    contentPara.innerHTML = data.reviews; // NEW
  } else if (event.target.href.includes("delivery")) {
    contentPara.innerHTML = data.delivery; // NEW
  }
  event.preventDefault();
}
...
contentPara.innerHTML = data.cuisines;

Our page is pretty fragile. Hitting refresh still displays the cuisines page and the back button doesn't work. Let's fix it by getting the page contents based on the address in the browser's address bar.

Remove the hardcoded active class in the HTML and replace it with:

var tabs = document.querySelectorAll("nav a");
var contentPara = document.querySelector(".content");

document.querySelector("nav a").classList.add("active"); // NEW

Change the href values to use hashes:

<nav>
  <ul>
    <li><a href="#cuisines">cuisines</a></li>
    <li><a href="#chefs">chefs</a></li>
    <li><a href="#reviews">reviews</a></li>
    <li><a href="#delivery">delivery</a></li>
  </ul>
</nav>

Remove event.preventDefault() from the script. We no longer need it.

Now we'll get the string from the URL using substring:

function makeActive(event) {
  if (!event.target.matches("a")) return;
  makeInactive();
  console.log(window.location);
  var type = window.location.hash;
  // var type = window.location.hash.substring(1);
  console.log(type);
}

Use the substring to set the HTML:

function makeActive(event) {
  if (!event.target.matches("a")) return;
  makeInactive();
  event.target.classList.add("active");
  const type = window.location.hash.substring(1);
  contentPara.innerHTML = data[type];
}

Note the use of data[type] instead of data.type.

var funkyObject = {
  a: "testing",
  "not a variable": "but you can use it in an object",
};

console.log(funkyObject.a);
console.log( funkyObject.not a variable  ) // can't do this, doesn't work
console.log(funkyObject["not a variable"]);
var propertyToCheck = prompt("What do you want to get?");
console.log(propertyToCheck);
funkyObject.propertyToCheck; // doesn't work
funkyObject[propertyToCheck];

You have to click on the tab twice to get the right content although the active / inactive class switching works.

We can set the initial hash with window.location.hash = 'cuisines'

See https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event

And then use another event listener hashchange:

var tabs = document.querySelectorAll("nav a");
var contentPara = document.querySelector(".content");

document.querySelector("nav a").classList.add("active");

// contentPara.innerHTML = data.cuisines
document.addEventListener("click", makeActive);

window.addEventListener("hashchange", setContentAccordingToHash);

function makeActive(event) {
  if (!event.target.matches("a")) return;

  makeInactive();
  event.target.classList.add("active");

  // var type = window.location.hash.substring(1)
  // contentPara.innerHTML = data[type]
}

function makeInactive() {
  tabs.forEach((tab) => tab.classList.remove("active"));
}

function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  contentPara.innerHTML = data[type];
}

var tabs = document.querySelectorAll("nav a");
var contentPara = document.querySelector(".content");

function makeActive(event) {
  if (!event.target.matches("nav a")) return;
  makeInactive();
  event.target.classList.add("active");
  const type = window.location.hash.substring(1);
  contentPara.innerHTML = data[type];
}

function makeInactive() {
  tabs.forEach((tab) => tab.classList.remove("active"));
}

function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  contentPara.innerHTML = data[type];
}

function initializePage() {
  document.querySelector("nav a").classList.add("active");
  window.location.hash = "cuisines";
  setContentAccordingToHash();
}

document.addEventListener("click", makeActive);
window.addEventListener("hashchange", setContentAccordingToHash);

initializePage();

Now that we are using a hash we can look for it when the page loads and then derive a solution for the refresh button:

function initializePage() {
  if (!window.location.hash) {
    window.location.hash = "cuisines";
    document.querySelector('[href="#cuisines"]').classList.add("active");
  } else {
    document
      .querySelector('[href="' + window.location.hash + '"] ')
      .classList.add("active");
  }
  setContentAccordingToHash();
}

Note the use of attribute selectors and concatenation.

We'll replace our concatination with template strings (aka string literals).

const name = "Yorik";
const age = 2;
const oldSchool =
  "My dog's name is " + name + " and he is " + age * 7 + " years old.";

const newSchool = `My dog's name is ${name} and he is ${age * 7} years old.`;
console.log("oldschool ", oldschool);
console.log("newschool ", newschool);

Template Strings use back ticks instead of quotes and have access to JS expressions inside placeholders - ${ ... }.

.querySelector(`[href="${window.location.hash}"]`)

If we want to use the hash change to determine both the active tab and the content being displayed we can dispense with the click event listener.

This also makes it easier to reset both the active state and content when the browser's forward and back arrows are used:

var tabs = document.querySelectorAll("nav a");
var contentPara = document.querySelector(".content");

// when the hash changes
function setActiveTabAccordingToHash(type) {
  makeAllTabsInactive();
  var tabToActivate = document.querySelector(`a[href="#${type}"]`);
  tabToActivate.classList.add("active");
}

function makeAllTabsInactive() {
  tabs.forEach((tab) => tab.classList.remove("active"));
}

// runs on page load and whenever the hash changes
function setContentAccordingToHash() {
  var type = window.location.hash.substring(1);
  contentPara.innerHTML = data[type];
  setActiveTabAccordingToHash(type);
}

// only runs once on page load
function initializePage() {
  if (!window.location.hash) {
    window.location.hash = "cuisines";
    document.querySelector('[href="#cuisines"]').classList.add("active");
  }
  setContentAccordingToHash();
}

window.addEventListener("hashchange", setContentAccordingToHash);

initializePage();

An Array of Objects

This is an extremely common format for data to be sent from a server for use in a page.

https://api.nytimes.com/svc/topstories/v2/travel.json?api-key=uQG4jhIEHKHKm0qMKGcTHqUgAolr1GM0

https://pokeapi.co/api/v2/pokemon/

https://www.reddit.com/r/BudgetAudiophile.json

Examine data-array.js:

const data = [
  {
    section: "cuisines",
    story:
      "Cuisines. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis.",
  },
  {
    section: "chefs",
    story:
      "Chefs. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.",
  },
  {
    section: "reviews",
    story:
      "Reviews. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis.",
  },
  {
    section: "delivery",
    story:
      "Delivery. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi.",
  },
];

An array is commonly used in conjunction with loops.

We will loop through our data array using an if statement in order to find a match for our type variable.

function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  for (var i = 0; i < data.length; i++) {
    if (data[i].section === type) {
      contentPara.innerHTML = data[i].story;
      setActiveTabAccordingToHash(type);
    }
  }
}

We could also use the array's forEach method instead of a for loop:

function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  data.forEach(function (item) {
    if (item.section === type) {
      contentPara.innerHTML = item.story;
      setActiveTabAccordingToHash(type);
    }
  });
}

I prefer a for ... of loop (documentation):

function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  for (var item of data) {
    if (item.section === type) {
      contentPara.innerHTML = item.story;
      setActiveTabAccordingToHash(type);
    }
  }
}

We can use a template string (string literal) to create HTML that uses both the section and story elements:

if (item.section === type) {
  // contentPara.innerHTML = item.story
  contentPara.innerHTML = `<h2>${item.section}</h2> <p>${item.story}</p>`;
  setActiveTabAccordingToHash(type);
}

e.g.:

// runs on page load and whenever the hash changes
function setContentAccordingToHash() {
  const type = window.location.hash.substring(1);
  for (var item of data) {
    if (item.section === type) {
      // contentPara.innerHTML = item.story
      contentPara.innerHTML = `<h2>${item.section}</h2> <p>${item.story}</p>`;
      setActiveTabAccordingToHash(type);
    }
  }
}

And finally, use an event to kick start our page:

// initializePage()
document.addEventListener("DOMContentLoaded", initializePage);

flexnav's People

Contributors

dannyboynyc avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.