Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@prof3ssorSt3v3
Created November 26, 2022 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prof3ssorSt3v3/863f55b81d29ec2375dda71ad3816729 to your computer and use it in GitHub Desktop.
Save prof3ssorSt3v3/863f55b81d29ec2375dda71ad3816729 to your computer and use it in GitHub Desktop.
Sample about using the History API and putting form data in the URL hash
const APP = {
lastSearch: null,
init: () => {
console.log('init');
if (!location.hash) {
console.log('clear url');
history.replaceState(null, null, '/#/');
} else {
APP.readURL();
}
window.addEventListener('popstate', APP.pop);
window.addEventListener('hashchange', APP.hashchange);
document.querySelector('form').addEventListener('submit', APP.submit);
document.getElementById('btnSearch').addEventListener('click', APP.click);
},
pop: (ev) => {
//popstate event
console.log('popstate', location.hash);
APP.readURL();
},
hashchange: (ev) => {
//hashchange event
console.log('hashchange - not being used.');
},
readURL: () => {
console.log('read url and call search');
let hash = location.hash;
if (hash) {
let [, key] = hash.split('/');
document.getElementById('key').value = key; //the input element
APP.processSearch();
}
},
submit: (ev) => {
//form submitted
console.log('submit');
ev.preventDefault();
APP.processSearch();
},
click: (ev) => {
//button clicked
console.log('click');
ev.preventDefault(); //this will short-circuit the submit even when hitting enter
APP.processSearch();
},
processSearch: (key) => {
let keyword = document.getElementById('key').value;
console.log('processSearch', keyword);
if (keyword && APP.lastSearch != keyword) {
document.querySelector('main').classList.add('active');
APP.doSearch(keyword)
.then((results) => {
//update URL
console.log(`Search results ${results}.`);
if (location.hash == `#/${keyword}`) {
console.log('no need to call pushState and duplicate...');
} else {
console.log(`Call pushState.`);
history.pushState(null, null, `/#/${keyword}`);
}
APP.lastSearch = keyword;
return keyword;
})
.then((keyword) => {
document.querySelector('main span').textContent = keyword.toUpperCase();
document.querySelector('main p').textContent = `Found ${keyword}`;
document.querySelector('main').classList.remove('active');
})
.catch((err) => {
console.warn(err.message);
document.querySelector('main span').textContent = keyword.toUpperCase();
document.querySelector('main p').textContent = `${keyword} NOT Found`;
document.querySelector('main').classList.remove('active');
history.pushState(null, null, `/#/${keyword}`);
});
} else {
console.log('No change in keyword, or keyword empty, so no search');
document.querySelector('main span').textContent = '---';
document.querySelector('main p').textContent = `Nothing to search`;
document.querySelector('main').classList.remove('active');
}
},
doSearch: (keyword) => {
return new Promise((resolve, reject) => {
console.log('searching....');
let good = Math.floor(Math.random() * 5);
if (good) {
setTimeout(resolve, 1400, keyword);
} else {
setTimeout(reject, 800, new Error('Bad things'));
}
});
},
};
document.addEventListener('DOMContentLoaded', APP.init);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./app.js" defer></script>
<link rel="stylesheet" href="./main.css" />
</head>
<body>
<header>
<form action="#">
<label for="key">Keyword</label>
<input type="text" id="key" name="key" />
<button id="btnSearch">Search</button>
</form>
</header>
<main>
<h2>Title about <span>keyword</span></h2>
<p>No search keyword.</p>
<div class="loader">Loading...</div>
</main>
</body>
</html>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
}
html {
font-size: 20px;
font-weight: 100;
color-scheme: dark light;
}
header {
padding: 1rem 3rem;
}
main {
padding: 1rem 3rem;
}
label {
margin: 0 1rem 0 0;
font-size: 1rem;
padding: 0.25 1rem;
}
input {
margin: 0 1rem;
font-size: 1rem;
padding: 0.25rem 1rem;
}
button {
margin: 0 1rem;
font-size: 1rem;
padding: 0.25rem 1rem;
border: none;
cursor: pointer;
}
button:hover {
background-color: coral;
}
.loader {
display: none;
font-size: 4rem;
color: coral;
}
main.active .loader {
display: block;
animation-name: pulse;
animation-duration: 0.8s;
animation-direction: alternate;
animation-iteration-count: infinite;
}
h2 {
margin: 1rem 0;
}
p {
margin: 1rem 0;
}
main.active h2 {
opacity: 0.5;
}
main.active p {
opacity: 0.5;
}
@keyframes pulse {
0% {
opacity: 1;
}
100% {
opacity: 0.1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment