Our posts form needs some kind of validation to prevent bad submissions from going through. We’ll want to start be validation sever-side since that is essential, and only do front-end validations as enhancement later.
We can do a validation in our action by creating an errors object that has three ternaries that check if any field is empty. Then we check if there are errors, and if there are, we return the errors as JSON instead of submitting the form and redirecting.
Then in our component we can use the errors data to display messages to the user.
Kent C. Dodds: [0:00] It probably wouldn't be great to create a post that didn't have a title, slug, or any markdown, so let's do some validation. We can, of course, do validation on the client side, as we usually do with React and so as users type in and stuff, they can get some validation.
[0:14] We're always going to want to do validation on the backend because users can circumvent your frontend client side logic. You always have to do your validation on the backend at least, and then you can progressively enhance by adding some validation to the client. We're just going to do backend validation, and you could go ahead and add your client side validation yourself later.
[0:36] What we're going to do is we're going to make this errors object. This is going to have a property for each one of the elements that can say whether that thing has an error. For the title, say, if there is a title, then we'll just assume that things are good, and we're going to say null. If title is falsely, then it's probably empty, so we'll say, "Title is required."
[1:02] We'll do the same thing for the slug and the markdown. Slug and markdown. Then here we'll say, the slug is required, and the markdown is required. With that now, instead of doing the createPost and redirect, we actually want to send back a response that says, which of these properties are in error, but we only want to do it if it has an error.
[1:26] We can determine that by checking whether any of these properties is truthy. We'll say, hasErrors, Object.values. Now, I've got an array of all the values of the errors. If some of them are truthy, then we'll know that we have some errors.
[1:42] If hasErrors is true, we're going to return a JSON response. JSON is going to come along with redirect. Our JSON response would simply be the errors. Then down in our component, we can get those errors with useActionData.
[1:58] This is similar to useLoaderData. It's also going to come from remix-run/react. If a form has been submitted and action data has been returned like we're doing here, then errors is going to be defined.
[2:14] Right after the title we can say, if errors is defined and there's a title on it, then we're going to make an em element with a className, text-red-600. We'll say, errors.title. Otherwise, we don't need to show an error because there is no error message.
[2:33] We'll do the same thing for the slug, except this of course will be slug, and for our markdown, except this will be markdown.
[2:43] With that now, if I try to submit this, then we're going to get those error messages. If I submit this with a new thing like, I love my pint. I-love-my-pint. I travel with this thing. Then Create Post, then the whole thing works, and there's "I love my pint."
[3:03] We can look at our post listing and there it is. To do some validation, we simply validate the data that the user submitted, determine whether there are any errors. If there are, then we'll return a JSON response.
[3:16] Then we can get that JSON response with useActionData and based on the presence of that response, we can show the errors that are necessary.