Last active
July 2, 2024 11:44
-
-
Save prof3ssorSt3v3/f7c23df64a9cb9285c5d6b20e860cf01 to your computer and use it in GitHub Desktop.
Using History.state and popstate to manage calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const APP = { | |
init: () => { | |
console.log('init'); | |
document.querySelector('footer').innerHTML = `<p>popstate with ${JSON.stringify(history.state)}</p>`; | |
if (!history.state) { | |
console.log('clear url'); | |
history.replaceState(null, null, './index.html'); //default value | |
} else { | |
APP.readState(); | |
} | |
//moved from one history entry to another | |
window.addEventListener('popstate', APP.pop); | |
document.querySelector('form').addEventListener('submit', APP.submit); | |
}, | |
pop: (ev) => { | |
//popstate event | |
console.log('popstate', history.state); | |
document.querySelector('footer').innerHTML = `<p>popstate with ${JSON.stringify(history.state)}</p>`; | |
APP.readState(); | |
}, | |
readState: () => { | |
console.log('read state and call search'); | |
let state = history.state; | |
if (state && 'key' in state) { | |
console.log(state, 'had state'); | |
//Eg: {key:keyword, type:'movie', something: 'else'} | |
document.getElementById('key').value = state.key; //the input element | |
APP.processSearch(); | |
} else { | |
//no state value for key | |
console.log('no state or no key'); | |
//clear the form | |
document.getElementById('key').value = ''; | |
//clear any old results | |
document.querySelector('main h2 span').textContent = '---'; | |
document.querySelector('main p').textContent = 'No search keyword.'; | |
// At this point we could choose to read values from a querystring or a hash value. | |
// Adding this support we could now have external links to URLs | |
} | |
}, | |
readURL: () => { | |
//get the location.search and the location.hash and search based on values there... | |
}, | |
submit: (ev) => { | |
//form submitted | |
//stop the page from loading | |
ev.preventDefault(); | |
//run the fake search | |
APP.processSearch(); | |
}, | |
processSearch: (key) => { | |
let keyword = document.getElementById('key').value; | |
console.log('processSearch', keyword); | |
if (keyword) { | |
document.querySelector('main').classList.add('active'); | |
APP.doSearch(keyword) | |
.then((results) => { | |
//update URL | |
console.log(`Search results ${results}.`); | |
let state = { key: keyword }; | |
if (history.state && history.state.key && history.state.key === keyword) { | |
console.log('state is same so call replaceState...'); | |
history.replaceState(state, null, `./index.html`); | |
} else { | |
console.log(`Call pushState with the new state.`); | |
history.pushState(state, null, `./index.html`); | |
} | |
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'); | |
let state = { type: 'movie', key: keyword }; | |
history.replaceState(state, null, `./index.html`); | |
}); | |
} else { | |
console.log('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('fake api searching....'); | |
setTimeout(resolve, 1400, keyword); | |
}); | |
}, | |
}; | |
document.addEventListener('DOMContentLoaded', APP.init); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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>History Nav using State</title> | |
<script src="./app.js" defer></script> | |
<link rel="stylesheet" href="./main.css" /> | |
<!-- https://gist.github.com/prof3ssorSt3v3/f7c23df64a9cb9285c5d6b20e860cf01 --> | |
</head> | |
<body> | |
<header> | |
<h1> | |
Using | |
<code>`history.state`</code> | |
Instead of | |
<code>`location.hash`</code> | |
</h1> | |
</header> | |
<form action="#"> | |
<label for="key">Keyword</label> | |
<input type="text" id="key" name="key" /> | |
<button id="btnSearch">Search</button> | |
</form> | |
<main> | |
<h2>Title about <span>keyword</span></h2> | |
<p>No search keyword.</p> | |
<div class="loader">Loading...</div> | |
</main> | |
<footer></footer> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
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, | |
footer { | |
padding: 1rem 3rem; | |
} | |
code { | |
display: inline; | |
font-family: monospace; | |
color: cadetblue; | |
} | |
label { | |
margin: 0 1rem 0 3rem; | |
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; | |
font-size: 2rem; | |
} | |
main h2 span { | |
color: coral; | |
} | |
p { | |
margin: 1rem 0; | |
color: coral; | |
font-size: 1.5rem; | |
} | |
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