تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Intro to Web Storage0:03

I want to store the state of a game so that as we are playing it, we can hit the refresh button and then it will prompt the user to, you know, pick up where they left off or start a new one. And the way that we can do that is by using one of the storage objects. We have two of them. The first is called sessionStorage, the second is called localStorage. They are both similar, at least as far as their API.

the second is called local storage. They are both similar, at least as far as their API. So once you know how to use one, you can use the other. The only difference is for how long they store their information, which we'll talk about. But I think the best place to start is inside of this init function because this is where we initialize the game and it kind of makes sense to check

Prompt to Resume Game0:44

because this is where we initialize the game and it kind of makes sense to check to see if we have a saved game and if so does the User want to continue it. So let's say that we are going to have a static method on the Game class just called hasSavedGame. And if this is a true or at least a truthy value, then we want to ask the User if they want to continue that game.

or at least a truthy value, then we want to ask the user if they want to continue that game. So we're going to use the confirm function, which I'm not sure if we've talked about, but this is a function that's built into the browser. It's kind of like alert and confirm in that it allows us to provide a message and get a response back from the user. So we'll just simply ask, do you want to continue the saved game?

So we'll just simply ask, do you want to continue the saved game? And if this is true, then we need to do a few things. The first thing is create our game object. But really what we want to do is load the saved game, but then we need to prepare the UI as well so that we will show the game area. We also need to enable the game area. So we will set disabled to false. We need to disable the settings UI.

So we will set disabled to false. We need to disable the settings UI. So we will set its disabled property to true. And there's a few other things that we would need to do, but for right now, I think that's going to give us a starting point. This way, you know, the game is responsible for saving its own state and it's also responsible for loading a new game based upon that saved state.

Saving State to SessionStorage2:10

and it's also responsible for loading a new game based upon that saved state. So let's go to the Game class. And I think the best place to at least save state is inside of the checkGuess method so that every time that we make a guess, we update the saved state. So to start, we are going to use sessionStorage to store the state of the game. And in order to save something we call the setItem method,

And in order to save something we call the setItem method, this accepts two arguments. The first is the key that we want to associate with the data. So we'll just call this gameState. And then the second is a string value that we want to associate with our key. Now, the fact that we store a string is important because we can only store strings, we can't store objects,

Now, the fact that we store a string is important because we can only store strings, we can't store objects, we can't store numbers, we can't do anything like that. In fact, if we try to save a non-string value, it's going to try to convert whatever it is that we tried to save as a string. In some cases it works. In some cases it doesn't. So this is where using JS is very beneficial because the game state is, well, it's a complex object. I mean in the grand scheme of things, it's not complex,

because the game state is, well, it's a complex object. I mean in the grand scheme of things, it's not complex, but it's more than just a simple string. It's a combination of keys and values. So converting that into a string as json gives us the ability to store everything that we need by using a single key. So here we'll just call jsonString offi. We'll pass in this for this object and that will save the state.

We'll pass in this for this object and that will save the state. Now one thing to note, keys are of course strings. And based upon my experience, I am going to mistype that key. So I'm gonna create a constant, we'll call it gameStateKey, and we'll set it to whatever value that we need it. It's really arbitrary, it doesn't matter, but at least this way I can be sure that I use the same key.

It's really arbitrary, it doesn't matter, but at least this way I can be sure that I use the same key whenever I set and get the value. Now, before we can actually see this in action, we need to implement a few things because I used some code here that doesn't exist, like this hasSavedGame method. So let's define that. Uh, let's do this, I guess right here where we have the static initRange values.

Uh, let's do this, I guess right here where we have the static initRange values. But I want to keep this in alphabetical order. So H comes before I, and all we need to do here is try to get something from the sessionStorage. We use the getItem method and then we specify the key. So we'll use our constant there. Now the getItem method is going to return one of two values.

Now the getItem method is going to return one of two values. If the key doesn't exist inside of the storage, then it returns null, otherwise it will return the string value associated with that key. So in this case, our hasSavedGame method is going to return a truthy or falsey value. So in that sense, we don't need to do anything else as far as the hasSaved.

So in that sense, we don't need to do anything else as far as the hasSavedGame method is concerned this will be truthy or falsely based upon if we have a saved game. But then we also need to implement this loadSavedGame method. So let's do that. We don't really need to do anything specific yet. I just wanna have this method there just so that we don't run into any errors because it doesn't exist.

I just wanna have this method there just so that we don't run into any errors because it doesn't exist. So let's go back down to where we store our game state. And let's take a look at this in the browser. Let's pull up the developer tools. And in Firefox you will want to go to the storage tab. Now if you're using a Chrome based browser, which is of course every other browser in the world, then you'll want to go to the application tab. But overall it's going

to go to the application tab. But overall it's going to have roughly the same thing on the left hand side. It's going to have several different storage options. The thing that we are concerned with is sessionStorage. Now notice the URL here it is for our website. It's not for this particular page that we are on. It is for the entire domain and that's how these storage objects work. So whatever we store within sessionStorage

and that's how these storage objects work. So whatever we store within sessionStorage or localStorage is available across all pages on this given domain. Now, there are some caveats which we will talk about, but generally that's the case. So now we just need to make a guess because that is how we store our game state. So if we play the game, we guess one and submit there, we see our data.

Serializing Proper Game State6:38

So if we play the game, we guess one and submit there, we see our data. The key is gameState and the value is, well, it's our gameObject, but it is only history. Whenever you serialize an object, the string find method only serializes public properties. Now you could say yes, we have some public properties, we have minRange, we have maxRange, we also have maxAttempts.

we have min range, we have max range, we also have max attempts. And yes we do. However, these are getters, these are not actual properties. Now there are ways that we can get around that, but I think in our particular case it would be better if we just build a whole new object because there is some information that we need to save as far as the game state is concerned. But they are private properties like

as far as the game state is concerned. But they are private properties like allowDuplicateGuesses. And the most important thing is the secretNumber. So whenever we save the state of our game, let's just build an object that has the information that we need. So instead of serializing this, we will serialize this object that has a minRange property, which we can get from minRange,

we will serialize this object that has a minRange property, which we can get from minRange, but I'm gonna use the private field here. Either way, it's going to give us the same information. I just think it fits better to use the private here. So the minRange, the maxRange, the maxAttempts, and then we also need the allowDuplicateGuesses. We need to include the history as well as the secretNumber. So let's do secretNumber first, and ideally I would've put this in alphabetical order,

So let's do secret number first, and ideally I would've put this in alphabetical order, but I didn't, which is a shame. I'll have to do that later. And then history is simply the history. So this is our game state. We are going to save this in our sessionStorage. So let's see that in action. Now we need to do a refresh, but notice now we have that question.

Now we need to do a refresh, but notice now we have that question. Do you want to continue the saved game so we can at least see that the code checking to see if there is a game state is actually working here. I don't want to click okay, because we have some code that doesn't work yet. So we'll start a new game. Let's go down to sessionStorage. Notice that our game state is still here. That is because we haven't changed the session,

Notice that our game state is still here. That is because we haven't changed the session, which I'm getting ahead of myself. So let's play the game. Let's make a guess. The game state data changes. Let's make another guess. And the game state changes again. Now between all of the guesses, the only thing that changes is the history. Because at least as far as our game state is concerned, that's the only thing that changes.

Because at least as far as our game state is concerned, that's the only thing that changes. However, do keep in mind that any time that you call the setItem method, you are completely replacing the value for that given key. So it's not like that we can pick and choose and say, Hey, just update the history here. No, this is an all or nothing thing. Every time we call setItem, we are setting a brand new value, replacing the old value.

Loading Saved Game State9:29

Every time we call setItem, we are setting a brand new value, replacing the old value. So let's load that data from our storage, but we want to parse it into an object that we can use and we have a choice. We could call sessionStorage then getItem here. But we also have, you know, that hasSavedGame method. So we could technically use that if we wanted. I don't necessarily want to just because of the name. So here I'm just gonna use sessionStorage.getItem.

I don't necessarily want to just because of the name. So here I'm just gonna use sessionStorage.getItem. And we want the gameState key. So this will give us an object that represents our state so that now we can create a game by newing up the Game constructor passing in the state object. That's going to take care of most of the settings because our constructor accepts the midRange, the maxRange, the maxAttempts,

because our constructor accepts the midRange, the maxRange, the maxAttempts, and the allowedDuplicateGuesses. However, there is no way to set the secretNumber except that since we are inside of the class here, we do have access to the private fields. So we can set the secretNumber of this game to whatever is from our state. And we essentially went to do the same thing for the history.

And we essentially went to do the same thing for the history. So we'll say state history. So we create a game with our state, we set the secretNumber, we set the history. All we have to do now is return the game. And that should get us back to our saved game. So let's refresh. Do we want to continue the saved game? Yes, but uh, we have an error. If we take a look at the console loadSavedGame is not a

Yes, but uh, we have an error. If we take a look at the console loadSavedGame is not a function that is UI line 101, loadSavedGame one keystroke will make your code not work. So yes, we want to loadSavedGame, our UI is ready to go. We can take a look at the storage, but you know, our guesses aren't populating here. So probably what we should do is after we set the secretNumber,

So probably what we should do is after we set the secretNumber, after we set the game, let's do this to where for each item within the history, we will call ui or no, we don't wanna do that here because we don't have access to the UI that is inside of ui. Okay? So right here where we are getting the UI ready to work, uh, we'll do this, we'll say gameHistory for each and for each value we want ui.updateHistory,

for each and for each value we want UI update history, and then we will pass in the value. Now, this isn't going to be 100% perfect because you know, there's other information that we include, but our, our guesses didn't show up. Why was that? Let's do a hard refresh and okay, and there we go. When in doubt, always Ctrl + F5. Okay, so our sessionStorage, we have a history of 1, 5, 8.

When in doubt, always control F five. Okay, so our session storage, we have a history of 1 5 8. We can see 1 5 8 being loaded here, which means that we have what, four more attempts. So let's try it. Yep, three more attempts. And, and this is where it isn't perfect, you know, because by loading from the game state, all we have are the numbers we don't have. If it's too low or too high, we of course could fix that, but I don't think we need to spend time on that.

Clearing Storage and Using LocalStorage12:38

If it's too low or too high, we of course could fix that, but I don't think we need to spend time on that. That's more of a logic issue as opposed to a JavaScript issue. However, one thing we do need to address is now that the game is over, if we refresh the page, our game state is still inside of storage. So if we load that, you know, there's, there's nothing to do because the game is over. So when the game is over, we need to clear what we have.

to do because the game is over. So when the game is over, we need to clear what we have in our session storage. So back inside of our Game class, we can do that. And really we don't want to clear everything because we could clear everything. There is a clear method that will clear everything outta session storage. But we don't want to do that. We only want to remove our game state.

But we don't want to do that. We only want to remove our gameState. So we'll call removeItem, we'll pass in our gameState key and that will remove our gameState. But you know, one thing I want to be absolutely sure of is that there isn't any kind of issue by setting the gameState and removing the gameState. So let's do this. Let's move where we set our gameState to after, if the game is correct or if it's over and then we will remove the item, we will return.

after, if the game is correct or if it's over and then we will remove the item, we will return that way there isn't any problem between set item and remove item. So with that in place, let's delete our sessionStorage. Let's do another medium game. Let's start making guesses and let's refresh. Yes, we want to load the game. Sure enough, we can pick up where we left off. And whenever the game is over, uh,

Sure enough, we can pick up where we left off. And whenever the game is over, uh, let's show our information there. When the game is over, our game state data should be removed and it is. Now of course there are some differences between sessionStorage and localStorage. The primary difference is that sessionStorage is for a single session. Now sessions are a little bit different.

for a single session. Now sessions are a little bit different. As a php developer, you know how a session works on, you know, php. The session is really determined by the browser that the user is using. As long as they are using the same browser, it is the same session. So they can have 25 tabs open. All of those tabs are the same session.

So they can have 25 tabs open. All of those tabs are the same session. They could have 50 tabs open on three different windows, but as long as it is the same browser, those 50 tabs are using the same session. When it comes to just the browser itself, a session is a single tab. So that means that everything that we store in session storage is for this given tab here.

that we store in sessionStorage is for this given tab here. So we can make a few guesses and then we can open up another tab. We can go to this same page, but we will not have access to that sessionStorage because the session is this other tab. So sessionStorage cannot be shared across multiple tabs. And there are plenty of uses for sessionStorage. However, a lot of times you want information

And there are plenty of uses for session storage. However, a lot of times you want information to be shared across multiple tabs, in which case you would want to use local storage. And I think in our case, local storage makes sense. So let's change our code so that every time we use session storage, we will change it to local storage. That's a few changes, but not really a whole lot. Here where we load the saved game, we have local storage.

That's a few changes, but not really a whole lot. Here where we load the saved game, we have localStorage. And whenever we check if we have a saved game, that's localStorage. So sessionStorage is just for a single tab. It can be used across multiple pages as long as it is inside of that same tab, but it is still restricted to that one tab. localStorage can be shared across multiple tabs, and I think more often than not you will reach

Local storage can be shared across multiple tabs, and I think more often than not you will reach for localStorage instead of sessionStorage.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟