A URL (Uniform Resource Locator) is the address of a webpage on the internet. Aside from just pointing to a page, URLs can also contain information that can be used to modify a webpage. For example, we can use a page URL to scroll to a certain section on a page or set a user token for authentication.
In this tutorial, we’ll be looking at how to use URLs to update the content on a webpage. Specifically, we’ll be looking at using URL parameters to modify a page using the page number and applied filters.
A Bit About URL Parameters
URL Parameters are extra information added to the end of a URL and they can be used to pass along data within the URL.
URL parameters are especially useful on pages that display a lot of data as it allows the user to maintain the page data in their preferred way. Storing data in URLs also allows for specific links to be sent to provide a personalised experience for a user.
To store the page number as a URL param, we’ll be using a previous tutorial on pagination:
In the Pagination tutorial, we added new elements to the page based on whichever page number the user clicks. The page content was updated using JavaScript so the page changes didn’t affect the URL structure. However, this meant there was no way to keep track of which page the user was currently visiting. For instance, if a user was browsing page 4 and decided to refresh the page, they would be taken back to page 1.
So in this tutorial, we’ll update the pagination script to use a URL param to store the current page and then use that param value to display which page content should be displayed.
Since we’re working with URLs, the demo is best viewed in an actual browser using this link https://tutsplus.github.io/jemima-tutorials/page-params.html
Updating URL Parameters
First, let’s write a function to update the URL structure when a page number is clicked. In order to update the page URL, we’ll first need to get the current URL. We can do that using the window.location
variable.
1 |
const currentUrl = new URL(window.location) |
The URL()
Constructor converts the window.location string into a URL object which we can update.
Once we have the URL object, we can use set()
method on the URL searchParams to update the parameters. The set()
method accepts name and value parameters and encodes them within the URL.
1 |
currentUrl.searchParams.set('page', pageNumber) |
Next we want to update the actual URL in the address bar. We also want our updated URL to mimic the usual browser default behaviour e.g. if a user uses the back button, they should be taken back to the previous page they clicked and if they click the refresh button they should see the same page.
We can achieve this using location.assign
– this method updates the browser History state and reloads the page with the updated browser URL.
1 |
location.assign(currentUrl) |
For more information on the different ways to update URLs using JavaScript, checkout this article on How to Change the URL in JavaScript: Redirecting
Our finished URL function looks like this:
1 |
const updatePageParams = (pageNumber) => { |
2 |
const currentUrl = new URL(window.location) |
3 |
currentUrl.searchParams.set('page', pageNumber) |
4 |
location.assign(currentUrl) |
5 |
}
|
We can pass this function into the click handler for the pagination buttons so the page param will be updated every time a button is clicked:
1 |
const setCurrentPage = (currentPage) => { |
2 |
updatePageParams(currentPage); |
3 |
...
|
4 |
};
|
The setCurrentPage
function is called when the pagination buttons are clicked so the URL parameters will be updated every time.
Updating Content based on Parameters
Now we’ve gotten our URL to update whenever the page is changed, we’ll need to write a function to actually display the right page based on the value in the URL.
In the pagination tutorial, we defined a global currentPage variable that was responsible for maintaining the current state of the page so that’s the value we’ll be updating based on parameters. We’ll set the currentPage variable to 1 by default.
Then, we’ll get the URL object of the current page and use the get()
method to retrieve the parameter we need.
1 |
const currentUrl = new URL(window.location) |
2 |
const page = currentUrl.searchParams.get('page') |
If the URL contains a page query, we’ll update our global currentPage variable to the value of the page in the URL. This is what the finished function looks like:
1 |
const getPageParams = () => { |
2 |
const currentUrl = new URL(window.location) |
3 |
const page = currentUrl.searchParams.get('page') |
4 |
|
5 |
if (!page) { |
6 |
return
|
7 |
}
|
8 |
|
9 |
currentPage = Number(page) |
10 |
}
|
We’ll need to call this function whenever the page is reloaded so we can do this using an event listener:
1 |
window.addEventListener("load", () => { |
2 |
getPageParams(); |
3 |
setCurrentPage(currentPage); |
4 |
}
|
Now when the page is loaded, the currentPage variable will be updated to the value in the URL or it will remain as 1 if there is no URL value.
However, since we’re reloading the page by updating the URL every time the setCurrentPage()
is called, we’ll need to include a condition to prevent the page from being caught in a loop.
1 |
const setCurrentPage = (currentPage, onload = false) => { |
2 |
if (!onload) { |
3 |
updatePageParams(currentPage); |
4 |
} |
5 |
} |
We’ll add an onload
parameter with a default value of false to the setCurrentPage()
method and only update the page URL if the onload
parameter is false. Next, we’ll update the function in the event listener:
1 |
window.addEventListener("load", () => { |
2 |
getPageParams(); |
3 |
setCurrentPage(currentPage, true); |
4 |
}
|
And with that we’ve successfully been able to modify page content using a URL.
Adding Multiple Parameters to a URL
However in real life situations, URL structures tend to be more complex than that. It’s possible to have multiple parameters attached to a URL, like below:
Let’s take a look at how we can pass multiple queries to a URL using another tutorial:
The final demo can be viewed here https://tutsplus.github.io/jemima-tutorials/filter-params.html and the complete code can be seen here https://github.com/tutsplus/jemima-tutorials/blob/main/filter-params.html
We’ll be updating the multi-filter feature to pass the selected filters to the URL and also filter the page on reload based on the filters in the URL.
For this feature, we’ll be using the append()
method instead of the set()
method. The set()
method replaces a key with the value being passed while the append()
method creates a new instance of the key value pairing within the URL.
1 |
currentUrl.append('key1', 'value1') |
2 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value1
|
3 |
|
4 |
currentUrl.append('key1', 'value2') |
5 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value1&key1=value2
|
6 |
|
7 |
currentUrl.set('key1', 'value3') |
8 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value3
|
Another change from the previous method is that instead of updating the state history and reloading the page, we’ll just be replacing the URL without reloading. Since we’re selecting multiple filters and making async calls to fetch the data, it would be bad for performance if we were reloading the page every time the URL was updating.
In this case, rather than using location.assign
, we’ll use history.replaceState()
instead. The history.replaceState()
method allows us to modify the URL within the address bar without needing to reload the page. It also doesn’t store the updated URL within the history so if the user presses the back button, they won’t be taken to the previous filter state.
The replaceState()
method accepts three parameters: data
, unused
and url
. The main parameter we need is url as that’s where we can pass our updated URL so the other two parameters can be null.
Our updated URL function now looks like this:
1 |
const updateFilterParams = (filter, value) => { |
2 |
const currentUrl = new URL(window.location) |
3 |
currentUrl.searchParams.append(filter, value) |
4 |
history.replaceState({}, '', currentUrl) |
5 |
}
|
Deleting Parameters from URL
Another function we’ll need to include is removing the parameters from the URL when a filter is unselected. We can do this using the delete()
method.
1 |
const removeFilterParams = (filter, value) => { |
2 |
const currentUrl = new URL(window.location) |
3 |
currentUrl.searchParams.delete(filter, value) |
4 |
history.replaceState({}, '', currentUrl) |
5 |
}
|
The delete() method accepts two parameters: name and value. If no value is provided, the delete method will remove all instances of that name from the URL.
1 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value1&key1=value2&key1=value3
|
2 |
|
3 |
currentUrl.delete('key1', 'value2') |
4 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value1&key1=value3
|
5 |
|
6 |
currentUrl.delete('key1') |
7 |
// https://jemimaabu.github.io/tutorials/filter-params.html
|
Next we can pass these two functions into the filter button click event handler:
1 |
const handleButtonClick = (e, key, param) => { |
2 |
const button = e.target; |
3 |
const buttonState = button.getAttribute("data-state"); |
4 |
if (buttonState == "inactive") { |
5 |
updateFilterParams(key, param); |
6 |
} else { |
7 |
removeFilterParams(key, param); |
8 |
}
|
9 |
};
|
So if the button is first clicked, the URL will be updated with the selected filter but if the button is deselected, the parameter will be removed from the URL.
Getting Multiple Parameters in a URL
Next we’ll want to update the content on the page based on the URL parameters. We’ll need to update the filter buttons to match the filters in the URL and then filter the button on the page.
When retrieving multiple parameters, we use the getAll()
method, which returns an array of all the values assigned to that key in the URL.
1 |
// https://jemimaabu.github.io/tutorials/filter-params.html?key1=value1&key1=value2&key1=value3 |
2 |
|
3 |
currentUrl.getAll('key1') |
4 |
// ['value1', 'value2', 'value3'] |
The filter create function now looks like this:
1 |
const createFilter = (key, param) => { |
2 |
const currentUrl = new URL(window.location) |
3 |
const filterKey = currentUrl.searchParams.getAll(key) |
4 |
if (filterKey.includes(param)) { |
5 |
filterButton.setAttribute("data-state", "active"); |
6 |
} else { |
7 |
filterButton.setAttribute("data-state", "inactive"); |
8 |
}
|
9 |
};
|
Next, we’ll need to fetch the URL params and use them to update the data displayed on the page. In the multi-filter feature tutorial, we defined a function handleFilterPosts() which is what we’ll be using to update the page based on the filters in the URL.
We can also check if the URL contains any parameters before we call the function, using the size
property:
1 |
const getFilterParams = () => { |
2 |
const currentUrl = new URL(window.location) |
3 |
|
4 |
if (currentUrl.searchParams.size <= 0) { |
5 |
return
|
6 |
}
|
7 |
|
8 |
currentUrl.searchParams.forEach((value, key) => { |
9 |
currentFilters[key].push(value) |
10 |
});
|
11 |
|
12 |
handleFilterPosts(currentFilters); |
13 |
}
|
We’ll call the getFilterParams()
function in our fetch request so the page will be updated with the selected filters once the data is gotten. In a larger-scale application, the filter would most likely be handled server-side so we would only need to pass the filters as params into the fetch request.
1 |
fetch( |
2 |
'https://...' |
3 |
).then(async (response) => { |
4 |
...
|
5 |
getFilterParams() |
6 |
});
|
And that’s all we need. Now we can update and modify page content based on URLs!