Why Offline Status Matters0:00
When we write applications, our responsibility is much more than just providing functionality. We need to provide a useful user experience. Useful user experience. I don't know. You know what I'm saying. This is incredibly important for progressive web apps. The reason why this is important is, let's say that we go offline. As far as the user is concerned, they don't know that we are offline unless if they
As far as the user is concerned, they don't know that we are offline unless if they tried to go to a page that has not been cached, in which case, they know that they are offline. We could make the argument that that's perfectly fine, but I want something else. I want to show the user when they are offline. I want to display a banner, and we can put it underneath the header and right before the main content, just so that if they are offline,
and we can put it underneath the header and right before the main content, just so that if they are offline, it's right there for them to see you are offline. Now, I should also preface this by saying when it comes to providing this kind of functionality, it is largely based upon what the browser thinks. Because it's the browser that's going to determine whether or not if it thinks it is online, and that's what we rely upon. We want to set up something that we can use throughout the entire application.
Creating a Global Store1:25
and that's what we rely upon. We want to set up something that we can use throughout the entire application. Now, I'm using Alpine. I like Alpine. In fact, that's the go-to framework that I use for doing any kind of DOM scripting. We are going to listen for the Alpine init event, because I want to create an Alpine store, and we're going to just call it net. Now, I'm using Alpine. Obviously, you don't have to use Alpine.
Now, I'm using Alpine. Obviously, you don't have to use Alpine. You can use whatever you want. If you're using React or Vue, you can come up with a component that you would want, or if you wanted to use their state management libraries, then have at it. The reason why I'm using a store here is because this is something that I will use throughout the entire application. So I don't want to create a component for this.
because this is something that I will use throughout the entire application. So I don't want to create a component for this. This is information that I will use throughout a page and over several pages. So I want to know a couple of things. First of all, I want to know if we are online, and we can initialize this with true or false. But the browser with the navigator object gives us a property called online. Now, notice the camel casing here. This is one of those cases where we didn't really need to camel case this. This could have been just online, and that would have been fine.
This is one of those cases where we didn't really need to camel case this. This could have been just online, and that would have been fine. This looks weird. It almost looks like an event, and it's not an event. So this navigator.online is going to return true or false based upon if the browser thinks that it is online or offline. And then I think it will be useful to let the user know when the last change occurred. So that if they've been offline for a couple of hours, then we can show that information to them. So I'm gonna call this lastChangedAt, and we're just going to initialize that as null.
Listening for Network Changes3:24
then we can show that information to them. So I'm gonna call this lastChangedAt, and we're just going to initialize that as null. Then we'll have a method to initialize everything, which we could go ahead and do that. And I guess it would be best to go ahead and just through the initialization process, we will set online again based upon navigator.online. But we need to know when the browser thinks that it goes online or offline. And we can do that by listening for two events. These are on the window object. This is not the document.
These are on the window object. This is not the document. This is not part of the DOM. This is part of the browser object model, the BOM. So we want to add an event listener for online. This is essentially when the browser thinks that it is back online, this event fires, so that we can do this. We can set online equal to true. But really, I don't wanna do that. I wanna call a method called setStatus.
But really, I don't wanna do that. I wanna call a method called setStatus. Because not only do we want to change the value of online, but we also need to update the lastChangedAt property. So we'll have that setStatus method to do both of those things. And if we have an online event, chances are pretty darn good we have the offline event, in which case we'll just pass false to setStatus. And we just need to define that setStatus there. So we'll have our value so that we can set this online equal to that value. And then we will set the lastChangedAt to,
So we'll have our value so that we can set this online equal to that value. And then we will set the lastChangedAt to, we will new up the date, and then we'll call toIsoString. The idea here is that this is a place for storing data. So I want to store data here. I don't want a representation of that data. I want the actual data. Because when it comes time to actually using the date, this is one of those complex pieces of information that we could do a lot with. We could just display the time, or we could display the date and the time, or
Building the Status Banner5:35
this is one of those complex pieces of information that we could do a lot with. We could just display the time, or we could display the date and the time, or we could just display the date. So if we store just the time or just the date, then we are limiting ourselves to what we can actually do with this information when it comes time to actually display that information. In which case, we need to be able to display that. So let's make a component, we'll call it OnlineStatus. And all we need is the view. We don't need a class for this component because there's nothing that we need for
And all we need is the view. We don't need a class for this component because there's nothing that we need for there. So that was OnlineStatus, and I'm just gonna paste this in. And this is just the markup as it is. There's no alpine or anything like that here because we're gonna add that. But basically, it's just gonna be a banner that has offline at the top. And we will also have when it was updated. So that if we go to our layout, let's see, between the header and the main, that's where we will use the OnlineStatus component.
So that if we go to our layout, let's see, between the header and the main, that's where we will use the OnlineStatus component. But I also want to go ahead and do this. And where we initialize our store, it's gonna be up to whoever. We could just initialize our store here inside of this component. But I don't necessarily wanna do that. Because this is something that I want to use on more of a global scale. So for me, from a declarative standpoint, it makes sense to initialize this at the body.
So for me, from a declarative standpoint, it makes sense to initialize this at the body. Because how much more global can you get than the body? So we're gonna have xdata here so that we can init. And we want to initialize the store.net. And we will call init there. Okay, so that should be good as far as our layout is concerned. So that means we just need to use that store here. Before we do that, let's be sure that our banner looks okay. Yeah, it does.
Showing and Testing Status7:40
Before we do that, let's be sure that our banner looks okay. Yeah, it does. We have offline, we have updated. And then we will just display that information. And of course, we will hide this when we are online. So let's start there. All we have for this div element is that class. So let's add an x show. And we want to show this when the store.net is offline. So when online is not true.
And we want to show this when the store.net is offline. So when online is not true. That will hide and show that. So that then we have offline. But then when it comes time for the date here, if we don't have a date, we don't want to show anything. So let's do this. We will only show our updated date when we have last updated at. So that when it comes time to displaying that, our text here. We will new date passing in the store.net.lastUpdatedAt.
So that when it comes time to displaying that, our text here. We will new date passing in the store.net.lastUpdatedAt. This goes back to what I was talking about. Since this is an ISO string, we can use that to create a new date. And then we can display however we want to display because we have the complete data here. And we wouldn't have to store it as an ISO string. We could have stored it as milliseconds or things like that. But an ISO string makes sense to me. So we're gonna do that.
But an ISO string makes sense to me. So we're gonna do that. So that we can output to local time string. And that's gonna be that. So if we go back to the browser, our banner is now hidden because we are online. But if we go offline, there we go. And our value didn't change there. Let's do a hard refresh. And we don't have the last updated at. So let's take a look at our code.
And we don't have the last updated at. So let's take a look at our code. When we set the status, we have lastChangedAt. It could be that I typed that incorrectly. So let's take a look, last. I used two completely different identifiers there. But that's gonna fix that. So let's refresh. Whenever we go offline, there we go. We can see that it was updated at 10, 10 straight up with 24 seconds.
Using Status Across UI10:06
Whenever we go offline, there we go. We can see that it was updated at 10, 10 straight up with 24 seconds. And we can see that that updates. So that's great. But now that we have this capability, we can expand that throughout the rest of our application. Like for example, if we are offline, we could hide these buttons. For offline, we could say that, hey, we can't view this. So why don't we hide it? But the issue there is, if we have something cached, well, we can view that.
So why don't we hide it? But the issue there is, if we have something cached, well, we can view that. So we need to be a little bit careful as to what we do with this. There are things that we can do. And I'm gonna put it that way. Because we can allow the user to do certain things when they are offline. And then we can sync those changes later. So ideally, we would just keep these buttons here as they are. But I want to show just a little bit as to what we can do. So that is the index view.
But I want to show just a little bit as to what we can do. So that is the index view. Let's open up the index view so that, let's see, where do we have those buttons? Well, they're all right here. So if we wanted to, we could say that we could show this with store net online. That's the easiest thing that we can do. So that whenever we go offline, we hide all of the buttons. Ideally, we would hide the new meter button there as well. I mean, there's so many things that we could do with that functionality. Now that we know when the browser thinks that it is offline, we could hide things.
I mean, there's so many things that we could do with that functionality. Now that we know when the browser thinks that it is offline, we could hide things. We can show things. We could do whatever we want because we have that ability. And that's awesome. But there are, of course, some caveats to this. The navigator.online property is optimistic. It often means that there's a route to something. It doesn't necessarily have to be a route to your application or your server. So it's not truly determining if it can communicate with your server.
It doesn't necessarily have to be a route to your application or your server. So it's not truly determining if it can communicate with your server. So that means DNS failures, a down API, even your application being down could still return true. And that doesn't help you at all. So in the next episode, we are going to look at a strategy that I've used in the past to determine if an application is truly online.
