We need a service function that will update an existing todo on the server. I'm going to copy the createtodo function in the todo services file. I'm just going to modify it or rename it updatetodo. I'll change my argument from just the todo name to an entire todo object.
I want to update the URL that we're going to make this request to. Instead of just a static string, I'm going to use string template syntax so that I can follow this up with the ID from the todo that's being passed in to our function.
I'm going to update my method from post to put. I'm going to leave the headers in place and I want a JSON string to find my body but this time the body is going to be the entire todo. That's everything we need for our update todo function to work. I'm going to save this file.
Then I want to go into my todo.js file where we have to find our other action creators. I'm going to import updatetodo from the todo service, and we're going to use this in an async action creator to handle an update on our server.
I'm going to drop down below savetodo and I'm going to export a new constant, and I'm going to call this one toggletodo. Toggletodo is going to accept the ID value for a todo object and it's going to return a function. That function is going to accept dispatch as an argument.
When we're doing our save operation the first thing we want to do is use dispatch to show a message, and that message will just say saving todo update. Now, I need to get my todos.
I'm going to declare constant todos, and I need to get these out of my state, because I want to take this ID, find the todo from my current state that I want to update, and then perform my update and send that to the server.
In order to do this, I can lean on the second argument that this function is going to receive, which is getstate. I can call getstate, and that will give me back my entire state object. Because we're using multiple reducers all of my todo content is name spaced as todo.
Getstate todo will return all of the state that my todo reducer is concerned with, and that contains the todo's array. I'm destructuring that out here. Now I have my todos and I want to get the todo that matches the ID that's been passed in here.
I'm just going to define todo and that's going to be todos.find, we're going to get each individual todo, and I'm just going to compare the ID here with the ID that's been passed in. That will get me back my matching todo.
Now I'm going to find the toggled version of that, which is going to be a new object, and I'm going to spread todo, and I'm going to set iscomplete flag based on to.iscomplete. I'm just going to negate that.
Now that I have this new updated todo defined I'm going to call my service. I'll call updatetodo and I'm going to pass in toggled, and then I want to handle the response with a then. I'll get a result. That result is going to be my updated todo the server will pass back.
Here I want to dispatch a new action. We haven't created this yet but we're going to want to replace the todo and we're going to pass in that response, which is our todo object.
Let's define a replace todo action creator. I'm going to scroll up to the top here where we're defining these other action constants. I'm going to define a new constant, which I'm going to call todo_replace, and that can just be the string todo_replace.
Now I'm going to export a constant called replacetodo, and this is the action creator that we're calling in our dispatch below. This is going to accept the todo object, and then it's going to return an action object with a type of todo_replace and a payload of the todo object that we just passed in.
With that in place let's scroll down to our reducer function and handle our todo_replace case. Case todo_replace, and here we're going to return a new state object, so I'll spread the existing state and then I want to replace todos.
I'm going to create my new todos by calling state.todos.map. I'm going to pass in the existing todo, and if this todo's ID matches the action.payload.ID then I'm going to return action.payload, which will be my replacement todo, otherwise I'm just going to return the existing todo. I can break this onto multiple lines and make it a little easier to read.
With that done there is one more thing we need to do. I'm going to come up here to the top and I want to export my todo_replace, because when my replacement is done I want to clear up my message in the message reducer.
I'm going to save this, I'm going to go back into messages.js and I want to import todo_replace from todo and I want to add that as a fall through to clear out our messages, todo_replace. I can save that.
With everything set up in our reducers the last thing that's left is to wire this up to our component. I'm going to open up the todo list component and down at the bottom where I'm connecting Redux to this component I want to update my map dispatch to props to include toggletodo.
I'm going to add that here but we haven't imported it yet, so I'm going to scroll back up to the top and add that to my import. Now that I've imported that and added it to myconnect it's going to be passed into my component as a prop.
In my render here I want to pass toggletodo as a property to my todo item component and I'm going to do that by passing this.props.toggletodo. Then in the todo item component, which I have defined up here at the top of the file, I'm just going to add toggletodo as part of the argument destructuring.
Then I'm going to add that here, add my onchange handler. Onchange here is going to be a function that will call toggle todo with the ID which is also being destructured as part of my props. I can break this out so it's a little easier to read.
The only thing left to do here is to change this to fault checked property to checked, because we're now controlling the value of checked through the onchange handler. We can save that.
Now if I go back into the browser I should be able to toggle a todo, and we'll see the message flash up, and then hide immediately. These records are being saved on our server, so if I check a couple more of these and I reload the page they'll be loaded with their previously checked state.