Introduction to the JAMStack

Saving Updated Toggle State

Jason Lengstorf

Jason Lengstorf

Learn With Jason
Introduction to the JAMStack

Check out a free preview of the full Introduction to the JAMStack course

The "Saving Updated Toggle State" Lesson is part of the full, Introduction to the JAMStack course featured in this preview video. Here's what you'd learn in this lesson:

Jason adds the option of toggling items as complete, adding more functionality to the app and showing another example of how to manage state.


Transcript from the "Saving Updated Toggle State" Lesson

>> The next thing that I wanna do is add support for toggling these todo items as complete. We wanna be able to mark if it as complete. Or if it's complete, we wanna be able to uncheck that, so that we can keep it on our list. So to do that, we're going to start by creating a new function.

And this function is going to be called toggle-completed. Because what we're gonna do is actually just flip it from whatever the previous state was. So if it was false, it'll be true. If it was true, it'll be false, because we want people to be able to choose multiple time.

You should be able to click that button a bunch of times, and it should always do what you expect, which is switch to the other checkbox state. So we're gonna pull in our sendQuery helper, and that's going to be in /utils/send-query. And then we want to grab, we're just gonna set up another GraphQL query right here.

This one's gonna be a mutation, and it's going to accept a couple variables. So we have an ID, the text, and the completed. So for this update, we're actually just gonna send all three in. Theoretically, what we could do in the future is add support for changing the text of the todo, but we're not gonna do that here.

So our ID is going to be an ID type. Our text is going to be string type. And then we've got completed, which is going to be a Boolean. All of those are required. Okay, so we have, make that a little bit bigger, so we can see. So we've got our mutation, we've got our variables declared.

And inside, we can then say, we're gonna update the todo. And that will take the ID, and then it takes the data that we want to change. So what we're saying is I wanna update the todo item with this ID. And then I want to update its data to be the value of text, and the value of completed.

Let's make that wrap. And then what we're gonna get back is whatever we want. I'm gonna send back just the ID and the completed. So let's set up our handler, exports.handler. And that is going to be async, and it's going to get the event. And we will pull the ID, the text, and the completed out of the event.

So we're gonna JSON parse the event.body And then we also wanna get the data and errors out of sendQuery. And we'll send in TOGGLE_DONE, and we'll also send in our ID, our text, and whether or not it's completed. So these are our variables that are gonna complete this ID, the text, and the completed.

That needs to be, okay, the ID, the text and the completed, which has a dollar sign, so that we can actually use it. So once we've got that, I'm gonna go into our createtodo, and I'm gonna get this back, because we're just using that again. And then down here, I'm going to change this over to the updatedtodo, and we'll just send back data.updatetodo.

We're gonna get that value out. So with that created, we can start netlify dev. And I'm going to create a new, Button in our todo component. Because what I wanna show is I wanna have a little check box here on the left that I can toggle. So let's make that happen, if I just make that into a thing.

And then I can create my label, and we'll give it an HTML4. And that's going to be for the todo toggle. And we'll use the todo's ID, so that it's unique, because we're creating a for label. We need to make sure that that's going to correspond to something unique.

And by using the todo's ID, we can ensure that each todo will have a unique label and ID. Which allows us to identify it in screen later, in a way that's actually useful to people. It also avoids a problem, where if they all have the same HTML4, if we click on the label, it would toggle all of the checkboxes on the screen at the same time.

So we're gonna do that, and we'll also add a class name of styles.label, which we'll have to define in our module CSS. And we're gonna say Mark Complete. And then next to that, I'm going to add an input. And that is going to have an ID of here, so I can just copy that straight across.

And then it will also have a type of checkbox. It's going to have a checked, and that checked is going to come out of the todo's, this is not a controlled input. So much as it is a like state managed input, we don't control what the value is, the todo itself controls it.

And then when we run on change, we want to do something. So we're gonna create a helper called toggleCompleted. And that's gonna live up here. We'll have to actually write it, but, We'll get to that in just a moment. And finally, we'll add a class name, it's gonna be styles.toggle.

Okay, so we'll create a little space there. And when I save this, okay, it did what we want. We've got a button, but I don't actually wanna see this mark complete. I just want that to be available for screen readers. So let's add a couple styles over here to our module.CSS to help us out.

The first thing I'm gonna do is just up at the top. Let's add some label text, and I'm gonna use the kinda standard, visually hidden accessible screen-reader text, class rules. So we set a border to 0, and then we're gonna set the clip to a rectangle of four 0s.

We're gonna set the height and the width to 1 pixel. And we will set the margin to -1 pixel, to offset that height. Then we're going to set the overflow to hidden, so that nothing escapes this little box we've created. We'll set the padding to 0, the position to absolute, so that it doesn't cause anything to reflow, and then I believe that's it.

Yes, so now that we've done that, the label disappears, but screen readers will still be able to find it. And so that's really important when people are tapping through our app. We want them to be able to get that label text, so they understand why that input exists.

Next, let's style up this toggle a little bit, and I'm gonna rely mostly on just the browser styling. The main thing that I wanna do is I want to have a chart with a cursor pointer. And I'm gonna add just a little bit of right hand margin, so that it's not crumb against the text like that.

Whoops, I wanted to be just on the right for now. There we go, that looks more correct. So from here, we need to make this this handler actually do something. So let's get into our todo one more time. Where did it go? Here it is. And up here in our toggleCompleted, we're just gonna write out some logic to make this do some things.

So we need to import Axios, so that we can send that command, or we can call our server less function. And inside of toggleCompleted, we are going to run, and we'll hit /api/toggle-completed. And we're gonna send in some data to that. So in Axios, the second argument is any data that we wanna send in.

So I'm gonna say that the ID is todo._id. I'm going to say that the text is todo.text, and completed. We're going to flip the Boolean state. So we're gonna do the opposite of whatever the current completed state is. And once that's done, we want to reload the todo's.

So we already wrote this helper, we just need to pass it in. So in our form, I can take this reloadTodo's that we already wrote. Not on our form, in the index. We wrote reloadTodos. So now in our todo, we can just include that. So we can save this.

Come back out to our todo, and then we can call this, We need to grab it out of the props. Okay, so assuming all is gone well, when I check this box, I think should happen, but it didn't. What did I do wrong? Let's see, cannot read property, updateTodo of undefined, which means I missed something in our toggleCompleted.

So data came back undefined, well, let's just console log that, and figure out what happened.
>> I think you have todo and todos.
>> Did I do it wrong? UpdateTodo, And then that's coming back as-
>> UpdatedTodo?
>> This is the one that we need. Let's see what I did.

Okay, so we should have logged this, but we're getting nothing back, so that's interesting.
>> Yeah, update versus updated.
>> Yeah.
>> [INAUDIBLE] parts, yeah.
>> Never mind.
>> Yeah, something wrong is happening here. Let's see if we're getting there, and it's just not logging correctly. It's not giving us anything back, interesting.

>> Does it need to be error first, or am I?
>> It needs to be awaited, is what's wrong.
>> Sorry, makes sense.
>> It is getting toward the end of the day, and my brain is shutting off. Okay, so this should solve the problem. The problem was that this is returning a promise, and since we didn't await it, that'll do it.

So after we have awaited sendQuery, we will get the data and the errors back. And upon toggling, it checks, hey, hey.

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