Vanilla JS: You Might Not Need a Framework

Browser Routing & History API

Maximiliano Firtman

Maximiliano Firtman

Independent Consultant
Vanilla JS: You Might Not Need a Framework

Check out a free preview of the full Vanilla JS: You Might Not Need a Framework course

The "Browser Routing & History API" Lesson is part of the full, Vanilla JS: You Might Not Need a Framework course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano discusses navigating between pages using the DOM for single and multi-page applications. The History API will be used to push new entries to the navigation history.


Transcript from the "Browser Routing & History API" Lesson

>> But before actually rendering the data, we need to solve one important part of the app that has to do with routing. We're going to create a single-page application. I mean, it's not mandatory, we don't need to. We can create a multi-page application, that is, you have multi HTML files, different HTML files, the home page, the order, each detail has different HTML files.

But we are doing a client-side application. We will do a single-page application, which means we will have just one HTML, and with JavaScript, we will change the contents of the page based on the URL. And we have at least for now two icons. We have this coffee icon and we have this cart icon.

They're not just icons, if I inspect them, they are links, anchors. So actually, if I click Order, I wanna go to the Orders section. And if I click Back in the coffee when I go to the Home, to the menu so we should navigate between pages. So let's get into that part, how to do that part And how to understand how that works.

So I'm going back to the slides for a second and we're going to see how to navigate between pages using the DOM. So, you understand the idea we have different sections. And the idea is that I'm in Section 1. If I click on section 2, I wanna change the section.

If I click on section 3, I wanna see section 3, so simple to understand. How to do that from a DOM point of view. One way is that every time you change the page, you remove the previous page from the DOM, and you inject a new page into the DOM.

By the way, what's a page? It's a concept that we are creating right now. It's not really a DOM concept, it's like the service, it's just a design pattern. We call it a page. It can be also a route, a view. Just put any name, it's an abstract concept.

In this case, it will be a DOM element that will render the contents of one particular section of my app. So one way is to remove from the DOM one page and put the other one, okay? The other option is to have all the pages in the DOM that then use hide and show.

I'm not saying that one is better than the other one, it depends on the case. So, quick example, so to, finally understand this, if you wanna remove the previous page and inject the new one, it may look like this. You have first a nav section that it's always available.

So that section is always available, and then we have a section element, this case, Section 1, because it's the one that we are seeing. If I click on the nav on Section 2, I'm removing that section from the DOM and I'm adding another section element. So now I'm seeing Section 2.

And of course, the same if I do this on Section 3. Make sense? We remove elements from the DOM, we put elements back. They can be a section, a div, whatever HTML element you want. That's one technique. The other technique is to hide and show. In this case, the three sections will always be in the DOM.

I will just change visibility, for example, using the HTML hidden attribute. So with hidden then you can say, okay, if I'm in Section 1, that's the one without hidden, and the other two are currently not visible. If I click Section 2, I'm just changing attributes to show and hide.

Yeah, this version might not be as scalable if you have a large application. But again, not every app that we are doing these days is a large application. So it's still a possibility that can be really performant for some apps, so it depends on the app, okay? So we need to change the content of the page based on what the user select.

And typically, these days, we call this a router. But that's another concept that is not in the DOM, it's an idea, it's an abstract idea router, a little tool that will make this work. Do we have a router in the DOM? No, a router in this case, it's something that we will code using the DOM API's okay?

But you will see it's actually pretty simple, it's not so complicated these days. So we have the homepage where we will see the menu of options for the coffee store. Then we may get into the details of one particular product like cappuccino I wanna get and get the description or the new cinnamon dolce latte with honey wherever.

Well, we can read the description calories, and for that we get into the details. Then we have the order, where we will have the current state of my order with my shopping cart, okay? So in our case, we won't have multiple HTML files. So, we will use the DOM APIs and something known as web components that we haven't covered yet.

And we will use the History API to push new entries to the navigation history. And here comes the magic part that is actually pretty simple. So as a web developer, sometimes we think that if we see a URL in the URL bar, that's because there is, I mean, the web server has answer to that URL.

Well, today, that's not always the case. With JavaScript using the History API, you can fake the URL after the domain. You cannot fake the domain the host, you can fake the path wherever it comes after the first forward slash. So you can fake it. And maybe in the server it's 404, but you can change it.

And not just you can change it, you can listen for changes. So if the user is using the Back button, then you can know that and know the current URL, even if that URL does not exist on the server. So that's the History API, that's how we build a router that it's really simple.

So this is how it works. To push a new URL, we use history.pushState. We pass an optional state object, that's an object where we can pass metadata, you will see how to use that later. There is a second argument that today in the spec is defined as unused, so we don't use it.

So they have to do with the history of the spec, but actually, that was a title. The string that was used as a title for the history menu, blah, blah, blah.. But finally, the spec, meaning the folks working on the spec decided not to use that but they didn't wanna remove that because of some browsers already implemented that bla bla bla bla.

Well, anyway we have the second argument that we won't use or we can pass anything including null. And then the URL, the fake URL, client-side only URL. And you will see that, that will trigger a change in the URL. Is it changing the contents of the page?

No, not at all, change the URL. It's up to us to capture that change in the URL and maybe change the DOM. And that's the idea of building a router. And for that, here at the bottom, the second part, is how you listen for changes in the URL, it's just popstate.

So, on the window, every time the URL is changing, with a big warning that I will tell you in a minute, we will get that event being fired. And we can get what's the current URL. And based on the current URL, we can decide which element to show, hide or inject.

Make sense? That's the idea, from an API point of view, it's actually not so difficult, okay? Popstate won't be fire if the user clicks on an external link or if the user goes and changes the URL manually. Because if that happens, the browser will initiate the new navigation and it's getting out of our web app.

So this event handler only works when we are working with the history in our own app. Does it make sense? Because we are still under the umbrella of a browser, and the browser works with page navigations, okay? So if the user clicks on, you wan't get that history, because that means you're getting out of your web app the browser will stop you, your router won't be able to detect that.

By the way, the same happens on React router or Angular router, you can't detect routes that are outside of your app. So if you're creating a single page application, you should set up your server properly. That means, that what happens if the user tries, that fake URL or press refresh on a URL that is fake, the server will return 404.

So, typically when you're doing a single page application, the same happens, we React. So this is not specifically a Vanilla.js problem, you need to set up your server so every request, every URL, should forward to the index HTML, not redirect forward

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now