First we'll create a function that creates a state object based upon
the url. This will return an object with all the key values that were
passed in the url.
1
2
3
4
5
6
7
8
9
10
11
12
13
| function getState() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const entries = urlParams.entries();
const state = {}
for(const entry of entries) {
console.log(`${entry[0]}: ${entry[1]}`);
state[entry[0]] = entry[1];
}
return state;
}
|
We can then write the reverse, which will change the location bar to
set values that are in the state object. If we pass in push = true
then in addition to changing the location bar it will also make the
back button keep another state.
1
2
3
4
5
6
7
8
9
10
11
12
13
| function updateState( state, push = false ) {
const url = new URL( window.location.href )
for( const entry of Object.entries(state) ) {
url.searchParams.set( entry[0], entry[1] );
}
if( push ) {
window.history.pushState( {}, "", url )
} else {
window.history.replaceState( {}, "", url );
}
}
|
Now lets handle initial load as well as the popstate
events for when a
user presses the back button. In this model of the page, each of the
url parameters that are passes coorespond to a DOM element.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| function updateDom( state ) {
// Look for all elements with the specified ID and if found, set the value
for( const entry of Object.entries(state) ) {
const i = document.querySelector( `#${entry[0]}` )
if( i ) {
i.value = entry[1]
}
}
}
window.addEventListener("popstate", (event) => {
state = getState();
updateDom( state );
} )
// Initial state loading
let state = getState()
updateDom( state );
|
Finally, lets add some events to our elements. For text inputs we
are updating the value of the state and replacing the current URL,
so linking works, and for the submit button we are pushing the state
which will add an new history entry. This makes the back button
work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Update value of the state on keyup events
document.querySelectorAll( "input[type='text']" ).forEach((input) => {
input.addEventListener( "keyup", (e) => {
state[e.target.id] = e.target.value
updateState(state);
} )
});
// Make the submit change the history
document.querySelectorAll( "input[type='submit']" ).forEach((input) => {
input.addEventListener( "click", (e) => {
e.preventDefault();
updateState(state,true);
} )
});
|