Everything You Should Know About Working With Forms In SvelteKit

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey friends in the last part we talked about data loading in swelker but in this part we're going to learn how to work with forms in cell kit so let's talk about the project setup first we are going to open the sidebar and this is just a regular skeleton circuit project with typescript so you can go to source and really there isn't anything special here I just have a root layout here let me just close the sidebar so I include the Pico CSS someone asked me last time hey can I write Global Styles in the layout and of course you can do it like this so you can import whatever you want here globally then you can Define some Styles here I want some padding for the body and I want some rounded corners for the inputs and buttons and this is how you can easily do it in circuit that's basically the setup and nothing special here in the plus page Trail file I just have a title here and nothing special and of course I'm running a development server so if I go here I have this default styles using Pico and here just have a title so if you want feel free to catch up alright before we get started I'm going to keep it simple and I'm going to create a fake database and we're also going to learn something neat which is server only modules so remember how we said that if you type dot server TS where a file is going to be only available on the server and same for your data loading this works for any other file so for example here is how I'm going to do it I'm going to go to source and I'm going to create new file I'm going to create the lib folder which as you already learned is the default alias in swellkit and now inside I can create either a file that's going to be called database server TS or I can create a folder which I'm going to do here I'm going to just say server and now I can say database TS which is honestly even calling you generous a fake database because this is just going to be an array of to-do's so let me just press enter and here I'm going to start by defining our type to do so it's going to have an ID which is going to be number it's going to have a text which is going to be a string and completed which is going to be a Boolean so now I'm going to create our fancy database which is just going to be to do's and this is going to use the to-do type which is going to be an array right and the first time I did it I over engineered it completely I used a map or whatever and I was like okay it's time to stop just keep it simple an array is fine for me right and we don't need anything else right so let me just give one default example here so we can see that it works and of course I'm going to give it a date now for the ID because I really don't care and now for the first one we're going to say learn how phones work and then we can say completed false all right so let's just Define a couple of functions and then we're done so we can say export function git to Do's or whatever else you have and we're just going to return the to-do's and really need to do this because really can just export this because it's going to be reference forever so we always have to run some other function is going to return the new updated to do's and then let's keep it simple I'm just going to scroll here we can say export function add to do this is just going to accept the text which is string and we're going to create a to-do which will satisfy this type right so we're going to say ID date now let's just give it a text that you pass through the function and we're going to say completed false and now we just need to update it to do so you can say to do push or dear with mutating data oh no okay let's save this and I can now Define or remove to do function you can say export function remove stew is going to take in an ID which is going to be number and this is going to be really simple we're just going to reassign the value we can say to this filter is going to take in a to-do and we just have to say hey does this to do not match the one we passed in and it is going to filter out the to-do's and the last function I'm going to Define export function clear to-do's so you can clear the to-do's and I'm just going to initialize the to-do's back to an empty array alright so that's it in the next part we're going to start to talk about forms this part is going to be a reintroduction to forms why do I say a reintroduction because we kind of know how phones work but we really don't from years of using JavaScript Frameworks and avoiding forms like the plague so we used our event handlers on buttons and Etc and we kind of know what happens when we submit the form but how does the form actually work so I'm going to talk about that in this section so let's start first by defining what the form is a form is a way to exchange information between the browser and the server and it's just a container for form controls or also called widgets believe it or not as said on mdn with some optional attributes to configure how the form behaves so let's have a look at that alright so inside the editor I'm going to go to routes and I'm going to open the plus page soil file and I'm going to start by defining a form so we can say form which is interesting so what is this method yeah that's interesting right and now we can define an X section and say login and now we can close the form and now we can specify some input fields or as we just learned they're called form controls so we can say input type which is really important just tells a browser what type of input this is you can have a button you can have check boxes and Etc and this is the most important part you have to specify a name because this is used on the server to get the data right and we can also say input type password so the browser now knows this input field is a password and knows to treat it as such and to hide the user input and now we can also give it a name we can say password you don't really have to even finish closing the stack like this because these elements are also called void Elements which means they don't need a closing tag but honestly this is just habit and now for the button we can optionally say type submit which is the default and now you can say login let's just save it and now we should get a beautiful form so here in the form the action attribute defines the location URL where the forms collected data should be sent and the method attribute defines which HTTP method to send the data with and the form attributes are optional if you exclude for example the action it's just going to get or post to itself so first let's see how get works the get method requests a resource on the server and appends the form data at the end of the URL so what you expect is going to happen when I type something in so we can say test one two three four and we're redoing a get request so I can say login oh interesting so now it redirected us to the action which is slash login and now we can see it appended the login which is the user query params test and password one two three four so this is great to request a resource or maybe play around with query params but in case of this form this is a actually insecure because you're showing the password in the URL right it's also not great for sending a large amount of data over the wire because the body is empty and that's why this gets appended to the end of the URL so let's change this method to post and save it and I'm also going to go back like this and basically the post method is similar to get but it can return a resource depending on the data sent in the request body and no data is going to be appended to the URL and the data is going to be included in the body instead so let's see how this works I'm going to open the network tab so now let's say test one two three four and pay attention to what's going to happen of course we had redirected again and we can see here we get a response so we can see here is the payload user test and the password one two three four and we can also view the source so again instead of being appended to the end of the URL is going to be sent in the body to the server as a list of key value Pairs and this is why the name attribute is so important because if you didn't have the name attribute then it wouldn't know what to assign to these values right and now on the server side we can just say okay give me the form data whatever you have and then we can just plug the values from it I'm going to show you how you can use API endpoints to work with forms and this part is important for understanding how forms work because it's going to give you more appreciation when you learn how simple cell kit makes working in forms in the next section and this is also going to help us understand how that actually works under the hood so next I'm going to create a to-do's folder with some route files so I'm going to go to our editor I'm going to open the sidebar and if you have the swelki extension you can right click anywhere in your project or use the command palette in vs code and we can say circuit file and you can create a route so you can give it a name we want to name the folder to use and now you can select the files you want so using spacebar I can say page sweld we also want server TS this is going to be the data for the page and we also want the endpoint for the form so I'm going to press enter and now it's going to create it so it's going to create the folder to do so now we have here the page.s cell file we have our data for the pages we're going to fetch in a second and here is our endpoint so let me just close the sidebar and first what we're going to do is fetch the data for the page which in our case is going to be the to do and you might see this if you're using typescript this satisfied page server load I'm honestly not a huge fan of this because it makes the code harder to read for no actual benefit so we can just remove this and I can just use it like this we can save page server load and that's it it works the same of course satisfy is useful in other areas but in this case it really doesn't do anything alright so because we're using typescript in our editor is super smart I can just say const to do's and I'm going to start typing get to Do's aha is going to know that we should import this so we can go here and of course it's aliased and we can just go here so I'm going to say dollar sign you would see what you would have to do if it wasn't Alias so you would have to do all of this nonsense which is really awesome because it's elliott-based default and if it's confused about this you should restart your development server and it's going to work so right now we can just return the to-do's inside of an object let me just save this and we can go here and I love using pre so we can say data and now we should see the to-do's on the page if we go to slash to do's and actually these are going to show the one to do alright so I have the page data and I'm just going to make a to do so we're going to create two functions we're going to need a function to add that to do which is going to take the event of type event and let's also make another to do I'm going to say function remove to do and simple like that so now we can go inside our template and we can Loop over the to-do's so let's go here and I'm just going to say UL and I have this each snippet and now we can get it to do is we can say data to do's is to do and now we can put it inside an ally and we can use a span so now we can say to do text and now we're just going to use a form and this might be real to you if you use the JavaScript because you might be thinking okay in the past I just might have used the button here have an event handler so it's really going to feel weird that you're using forms in quotes for these small things but don't be afraid just use forms whenever you can because that's the right way to do it so I can say form and then I can say on submit so we're just going to use JavaScript in this case we can say prevent default which is provided by cell and now we can say remove to do and the method is going to be post so let me just close the form and now I can Define our button which is going to be type submit which is optional of course and I'm also going to give it a class delete which you're going to create in a second I'm going to do this and let's give it an emoji so we can say Cross of course you should make this more accessible but a question is for example how are we going to send the ID to the server right so you know what to do to remove it and the answer is quite simple we can just create a hidden input field which is going to send the ID to the server so I can say input type hidden and now you can give it a name which we can grab on the server and for the value I can even say to do ID so we can grab the value all right sweet so now we can save it and we should see here is the first to do and we're going to include some Styles in a second to make this better but we also need another form now so this was the form for our to do and to delete them so you can go here let's create another form on submit so you can say prevent default and now we can use the to do function we can say method post let's close the form and this is straightforward we can just say type text I'm going to give it a name to do and then button type submit and we can just say add to do and now let's add some styles oh let me show us to this I can create a style tag so I'm going to say UL padding zero let's just give some styles for the Li you can say justify content space between align items Center and I'm also going to save for the span protection form should be capitalized and we just need to specify the delete and error classes so I can say delete margin 0 this is just some styling because of pickup so you can say background zero and border none actually background is going to be none and border is going to be none also and now for the last hour class we're going to be using in a minute we can just say color tomato all right so let's save this and everything should look a lot nicer so you can see here it's still complaining it says okay I have no idea what this is and usually you can restart the development server so you can go here say pin PM run Dev and this should resolve it and now it's going to generate whatever it needs and you can see it's happy now and as we learned previously you can see how we didn't specify the action attribute for the phones because we're going to submit it to the same page so now inside the server TS file we're going to create the post and delete functions so let me just scroll up here and we already have the data here so we really don't need this I can just close this I can go here so let me just remove this response and the first thing I'm going to do is actually declare a type data and this is just going to be responsible for returning success and errors for the page so this can be whatever you want this is just the shape I decided on so we can and do things based on what is returned from this so this is going to have a property success which is a Boolean it's going to have an object of errors and how we type errors in typescript you can use record and then we say hey the key is a string and then we can also maybe say unknown for the value but we can also give it string and this really isn't important and now instead of using get because this is going to be a post submit we're also going to use post and we need a request so we can get the form data right so we can go here and now we can say const from data so we can get the form data await request and types we can help us out so we can say request okay what is here form data nice and then you can get it to do so we can say form data get to do and this is the name of the field on the form right and now we need to make sure that this is a string because if you hover over this is going to be form data entry value typescript really doesn't like this so you can just say string and that's it so now I'm going to create the data object I can say const data actually let's give it the type data this is why we created it so I can say by default false and we can say errors is just going to be empty and now we can say if there is no to do we can say data errors to do and we can say required which really isn't important and then we should probably throw this and catch it on the fronted but really this isn't important so we can just return Json we can use the helper from cell kit let's say Json data and we can also give it a status which is going to be 400. and now if everything works I'm just going to go here and I'm going to say add to do this is going to also import it from our file so you can see here it works everything nicely in the background so let me just sort these things awesome so we can say a to do and we can just pass it the text right and then we can say data success true and we can also return the Json with that data let's do it like this I can save it and now this is the pose done and the delete is also going to be simple so you can go export const you want to use delete going to be the same type request Handler async we're going to the structure request let's say again form data again we're going to get the form everybody thinking yourself this is tedious and you can just subtract this inside the function or whatever so you can see Forum data and now we can say cons to do ID and we can say form data get and we call it ID right so if I go here let me just see yeah we gave it the name ID and this is going to give us the to-do ID so we can go back here we need to cast it to a number because it's going to be a string so we can do it like this and then we can just import remove to do so again it's going to import it because typescript is smart like that and now we can say remove to do we can pass it the to-do ID and that's it and let's return some Json and we can even say success true and we can save this and that's basically it so now on our front end we can fill in the function so if I go here here is the attitude so let's fill that in but first we're going to need the same type so I can even scroll up here let's just copy paste it you can already see how this is starting to be tedious now we need to copy over that part data right and now I also need to keep track of whatever we're going to return so I can create this variable this is going to hold data right and now we can fill in the add to do so we can say const form element event Target we need to say s HTML form element so typescript is happy and then we can say data new form data and we can pass in the form element and I'm also going to console log it out like this and we're going to see that in a second but first i'm going to Ping the endpoint so I can say cons response and I have to say await fetch what we want to Ping we actually don't need to specify here because we have a reference to the form element so we can say form element action how awesome is that and now we can give it some options we can say method post and we can pass the data so now before I continue let me just show you how that works so I can open the developer tools let me go to the console and now we can submit it or whatever and we can see the form element is here and now we have everything which has to do with that form so we got the action you can also get the method but this can only be a post like this so we type post and you can also see the data so instead of the form let's log our data so now if I type whatever you can see form data and let me see if I say log and we can see the form data object and all the properties available on it so you can get the value and Etc but I'm just going to remove this and let's just continue so now that we get the response we're going to populate this form right this is why we did this data thing here so now we can for example say const response data and now we can just await the Json that we return so let me just cancel all the dial so you can see what's going on response data I'm going to clear this so let's not submit anything we can see success false and now we get back the errors which is required so you can use this in our template but let's see what happens if we submit something so we can say test and now success is true and errors should be empty so now basically what we need to say we need to set the form variable we can say form is equal to the response data another thing you can see is that this persists when you submit the form and how do you reset the form well you have access to the form right the simple is saying form element reset as you can see you get great autocompletion so now if I type test and submit it it should disappear there's one more thing we have to do so you can see how nothing updated on the page let me see if I refresh the page you should see ah here the to-do's that we typed in okay so how can we fix this let me just close this so we have space to work with and you can see here are the to do's and basically this is happening because we have to invalidate the page data and we have to rerun the load function so in the data loading part we learned that we can use invalidate which we can use right here so you can say update invalidate let's just use the nuclear option we can say invalidate all and I'm just going to save this and now if you see if I type in test and add it it should object immediately and awesome it works so you can see let me just say banana you can see it added banana alright so sweet this wasn't that bad right so let's do the one for removing the to do and also I can just remove this placeholder and let's do it and now again I can say cons form element Target is HTML form element I can say cons data new form data so we just passed in the form and now again we can just say const response we can say await fetch use form element action and let's pass it some options so an interesting thing is that a form can only do a post and get so even if you do a delete it's going to do a post to the server and that's basically to the way the HTTP standard is made and that's really a story for yourself where basically silky is going to know what to do because we created a function delete so if we say here method delete it should work without a problem and now we can also pass it the form we can say body data and remember we have to invalidate the data so you can say a weight invalidate all which is already imported here at the top for us all right so now that's basically it so we can just save this and only see if it works so let me just start deleting things okay awesome you can see how this works alright but for example how do we show the feedback to the user so right now there's nothing right but remember we returned this data thing so it has a success and errors and this also gets updated right so now we can use this in the template so here it is with the to do so let me just make space I can just say if and now we can say form and because the next value might not exist we can use this Nifty trick we can say errors and because if you do might not exist we can also use a question mark and now we can create the P tag which is going to have that class of error that we made and now we can say this field is required or whatever else you want and let's also do one for the success so here we can say if and now we can say form if there's success we can also give it a paragraph add it to do and let's give it some Emoji we can say party so right now if I submit the form the user should see the feedback which is me so the field is required awesome so now let's add something we can say banana edit edit to do and how awesome is this then you can of course see everything in the network tab so let's see how this works if I go here and submit nothing you should see 400 to do is empty and if we submit something else we should see new to-do's which is going to be test and you can see in the preview and the response is the data which returns so this is the raw response and here you can see errors success and for the other one that failed we can go here you get the errors back and yeah that's basically it so this was basically just an exercise so I can show you that it really doesn't matter what your return it's basically up to you how you want to handle the error validation which leads us to the next part so this taught us a lot about forms and endpoints but this is not a great user in developer experience and why is that because for example this only works with JavaScript so you can see here for example how we had to prevent the default form Behavior now we had to go here even if we have a server right here we had to implement all of this ourselves we had to use fetch which is really tedious so imagine how it would look like with a more complicated form we we had to invent our own wonky validation like this thing is not ideal I wouldn't use this right we also had to use Fetch and invalidate all which is the nuclear option right and really the framework should do more for you and this is why you should use swelkit form actions in the next section I'm going to show you why they're so awesome so finally let's talk about swellkit form actions so remember how inside a standalone plus the server TS endpoint you can use functions that map to http verbs like get post and delete like we've done it here so you can see delete post and whatever else you want but form actions take this idea a step further and you can Define methods that map to an action inside a plus page or server TS file so you can go here and you can export an actions object which is going to map to the actions in your form I'm going to convert the previous example to use form actions first I'm going to delete this endpoint file because we're not going to need it anymore so I can close it and I can go to the sidebar and let me just press delete and we can move it to trash because we don't need it and now inside of here we can Define the form actions nothing else changes about this file you still use it to fetch the data for the page but now you can also Define form actions so let's start with creating actions for adding removing and clearing the to-do items so this is how you do it you can say export const actions and it uses the type actions which is going to be import for you so let's put it at the top and now you can give it an object so this is going to use default if you don't have any actions on your form like this but if you define a named action which you're going to use then you can't use default anymore so now let's just Define the actions we have and this is really simple and awesome because also remember when we use post right so if I go here and where is it in our template let me just go here so for example here it was for adding that to do but now what if you want to clear the to-do's or do something else or have three four actions or have different forms now this starts to get hairy because every method is going to be post so now you probably need to include some query params or have some hidden Fields so you know on the server what you should do based on what it gets right and this is really tedious and annoying and form actions are amazing because of this so let's just Define our form actions so we're going to have one that's going to be add to do we can say async and also remember this takes in an event object like we've seen everywhere you have something with data loading you're going to have this object we already learned about it so you can have cookies fetch locals params or whatever else here you're going to take in our request from here and let's also add remove to do so we're going to say remove this is also going to be async and it's going to take the request and we can also say clear to do's and you can honestly keep it like this because this is just going to be the function that we created but let's just be more clear what this is so I can just give it an empty function I can just say clear to those and this should Auto Import it for us and let me just save everything and everything works all right sweet so now we're going to see how much less code we're going to write so first let's fill in add to do I'm going to go here so I can say const form data await request it has phone data on it and now we can say cons to do and now we can use phone data we can say get to do let's turn this into a string and now we're going to do some error validation which is going to be way easier than what we did before so now we're going to say if there is not to do swellkit has a handy fail function that we can return a status and whatever else we want so we can say return import fail which is going to import the function if we go here so here it is fail and now let's see the argument so we can give it a status we can say 400 and now again this is up to you you can return whatever you want so in our case let's actually return the value so we can use it in case the form gets reset then we can just repopulate it so we can return the same value we can say to do and now we can say missing true or whatever and this is going to be available on the same form prop that we've seen but now it's official by swellkit alright so that handles the error case and let's just import and to do and same as before replace it to do and now we can just return success true and basically let me save this and now let's also fill in the remove to do again we can say form data request form data let's say cons to do ID let's just say number because we already know and we can actually let's just get the ID sometimes typescript is overzealous and this is because we need to also include a weight request all right so now it's FBC how typescript saves your bacon I would notice this and I would waste minutes of my life alright sweet so now let me just scroll up here and now I can say remove to do again I'm going to press enter this is going to import it let's just pass to do ID everything should work great and we can return success all right let me save this and this is it basically you can already see how much less code this is all right so now let's update our template so if I go here and now I can remove all of this nonsense I can remove these functions let me remove this I'm going to remove this type of deleting code feels better than writing code to be honest we don't need invalidate or a suite so now we have export late data this won't change at all ah now we have another thing from cell kit export let form which is going to be of the type action data and let me just instead of data we're going to save form and right now there's nothing but we're going to see how we can update our template so now we want to use JavaScript here so we can remove on submit for the Post Edition you're going to stay post and now we can Define the action right so how do we do it and this might look like magic first okay so check this out so we say action question mark and we can say remove to do but that wouldn't work right because this is a query param and sulkit won't know that this is an action or you're trying to invoke connection so how do you do it in swellkit well you just add a slash here and now swellkit knows that you want to call this function alright awesome so now let's update the other form how good does this feel right so we can delete this code and now we can say action what was it question mark slash add to do and now we can update this so we return form missing and now we can keep this as this field is required and also let me show you something else what is cool so we want to clear the videos right so if I add this button we can say clear okay but how do we do it so let me first add a class which is going to be secondary and this is of course optional but I like having it let me just save it so you can see here we have cleared okay but how can we invoke other functions right because we specified here that this form should invoke at to do well simple this isn't a swelkit API or anything this is using web standards so on the button you can use this property form action if specify it overrides the action attribute of the buttons form owner okay so this is going to override it awesome so let's see form action and now we can again say question mark slash clear to do's and save it how awesome is this and here nothing changed we again return success so this should work one downside though is that this type generation is sometimes wonky like here for example here you can see it's form missing but you're going to see that this should work so when I go here let's first see the error handling so I can say attitude this field is required also notice how our browser refresh because we're not using JavaScript and this is why your app is going to be more resilient because it's going to work before JavaScript so you can see how we get back that to do and missing so basically the editor doesn't know about this but what you can do you can press Ctrl P type the pointy boy you can say restart Lancer and sometimes that's going to do it sometimes you need to restart the development server and really if continuous airing like this just ignore you because you can see everything works just fine alright so let's see we can say test we can submit it oh how awesome it is or let's see if we can delete it ah awesome so now let's edit back again let's add more things and now let's see if clear is going to work right ah awesome how beautiful is this so let's also look at the network type right let's see what's going on I'm always curious about that you know me so for example just add a banana so you can see all this junk here and we can see how this is parsed so in the headers it did Slash deduce you can see this is a query program but because it uses a slash selki knows it should invoke this function here you can see the payload here so it parse the query string here and you also get the form data which is really awesome so you can see the preview and the response here which is going to be the HTML document of course so let's try removing this and this should also update of course it does a complete refresh you can see here is the ID and the parse query string parameters and again actions might look like magic but they're just a URL that invokes a function as you've seen swelkid makes it special by including a slash that lets zelkid know hey I should execute this map as you can see how this is really an awesome mental model you can have as many actions as you want and forms and Etc you can just go here to your actions object you can just add a new one let's talk about Progressive form enhancement so we've seen how already this is really awesome so we can add our to-do's or whatever else but the page refresh is really not a big deal but what if you want to preserve that awesome single page application experience and this is what Progressive form enhancement is for let's pretend that in this case the user doesn't have JavaScript because it can fail for whatever reason right your form is still going to work and Etc but if the JavaScript is available on the page we can enhance the user experience so we can do client-side validation or whatever else you want and let's see how simple this is to do and remember the point is not that your site should work without JavaScript but before it because JavaScript can fail and this is what makes your app more resilient so remember in the first example how we had to do everything by hand well basically swelkit does it for you and wraps everything in a pretty bow in a neat use enhanced sweld action this is unrelated to form action this is swelled actions which let you hook into life cycle methods of elements so how do we do this this might sound like super complicated but believe me it's one line of code if you count the input all right so how do we make this work we can go here to the form and now we can start using a swelt action we can say use enhance and as you start typing in hands you can import it so you can see here at the top it imported enhance from App forms ah awesome so now let me just copy this over that's it that's all trust me so now we can go here to the other phone we can say using hence ah interesting so what happens now you can see now if you look here the page isn't going to refresh oh awesome how awesome is this say test or whatever and now we can also remove the videos and notice now we get that awesome experience but let's see what's going on in the network tab right so let me just do delete like this and now instead of refreshing the page right it's going to use JavaScript script and client-side rendering because the JavaScript is available on the page so you can see our fetch request and here it is you can see preview it Returns the data status and the type which you're going to look into here is the raw response and let me just close this so when you submit the form using the use enhance action is going to update the form so right here is going to update this it's going to update the dollar sign page dot form store and it's going to update the dollar sign page.status property it's also going to reset the form and rerun the load function for the page so you don't have to use invalidate all yourself and in a case of a redirect is going to use go to so you can see if we go here and add whatever is going to work just great and also the error handling so you can see here it updates live and this is why I wanted to show you previously how you can work with forms using an API endpoint so you can understand actually what swelki does under the hood otherwise you will just use this and treat it as black magic which I honestly don't like I love magic but I also love understanding how things work and let's look at the implementation which really isn't spooky I honestly maybe don't understand half of this but if you can at least understand the general idea of what he's doing and this is going to look really familiar okay so when I look at something like this I'm like okay junk junk I really don't care about this series oh here it is here is the magic sauce here is the salt actions I already know about cell to actions right so I can see okay export enhance it accepts a form right and a submit value and we can already start seeing some familiar things here we can ignore this here it has a handle submit so it really does the equivalent what we've done before it prevents the default behavior of the form here it specifies an action then it does again that things with the form data right how familiar is this right you really don't need to understand these things but get a high level concept of how it understands this is going to give you more confidence in working with these things right and here is the abort controller so you can prevent requests and Etc and really here is the response so it's trying a response ah this looks really familiar right look a weight fetch action method post here is some special sauce headers are actually not important you can see some other things which you can dive into and basically that's it and here is a cleanup if you know what swell actions are all right friends how cool is this but now I want to show you how you can customize the enhanced action and we're going to use it to show a loading UI so how can we customize the behavior of the using hands action and you can do it by providing a submit function that runs before the form is submitted so here you can do your validation or whatever and then you can also return a callback that has access to the result so let's see how this looks like so here for example where I have add to do we won't edit for the removing of the to-do so we can just go here and where it using hands is now we can specify a function so you can just say add to do you can name this whatever you want whatever flows your boat like banana right so we can go here and now we can define a function and I'm going to do it using an error function because I want to use the type which wouldn't be possible using a regular function I'm going to say const I had to do and this is of type submit function so this should import it from App forms all right so now here we have the first argument which is going to be the input and now let me just put it like this and now inside of here you can do something before the form submits so now maybe you can here do validation of the inputs or whatever because we're going to see what you have access to here and this is maybe you don't really want to submit the form to the server right for no reason if you can already validate the data for example let me say that I'm typing my name here and it's really a frustrating user experience if you find out your name is taken once you submit the form I want to know immediately if my name is taken you know what I'm talking about how many annoying sites do that right so this is something you can do here and then you can provide a return function so you can say return async and this has options so you can do it like this and this is do something after the form submits and you can see because we're using our custom callback functions the form isn't going to work using the user enhanced method that we're going to see how to make it work again so let's just see what do we get so we can say console log input and now we can also go here options let me save this and now I'm going to open the developer tools let's just go to the console and now let's just type something in ah so this is really interesting so for the input we get this object we get an action which is a URL you can get a Cancel message you can cancel the request this is the abort controller which you can also use for canceling requests here is the form data itself right how awesome and you have access also to the form element and here is very similar for options it has an action it has the form data the form itself but it also has a result which we're going to learn about in the next section and how awesome is that and here we have something which we can use so we can do whatever we want here and we can call this update and this update function is basically going to run the logic it will do otherwise if you didn't specify a custom callback otherwise you would have to re-implement all that fetch nonsense yourself and Etc but swelkit really makes this easy so let's look at a real use case for this you can't always rely on a fast response from a server in which case the user might leave your site because it looks completely broken so what I'm going to do next let me just close this I'm going to go inside page server TS and I'm going to define a sleep function which is going to simulate a slow response so right after the load function we can Define it here and we can say async function sleep is going to take in milliseconds and then we can just say return you promise like this we can use resolve and we can say set timeout and we can just resolve it in whatever time we pass in so I can save this and now that we have this nice helper you can put this in your utils or whatever let's just go here and before we add it to do we're going to simulate a slow Network you can also do it from your developer tools or whatever but I can just say await sleep and we can say two seconds so now if I go here and add a beautiful banana you should see oh there's no feedback and the user is already starting to be frustrated they're like okay what is happening and in this case nothing is happening because we lost the default Behavior so if I go here let me just the structure update and now we can say away update and we can also remove this output because we don't usually need it here just remove this I'm going to save it so now again let's try adding something again nothing is happening it's going to take two seconds and ah you see and we already submitted the old one so now we get two bananas which is awesome two bananas is better than one okay so how can we give the user something useful right so let's first Define some state in our component so you can say let loading false all right so now you know that here you can do something before the form should miss and here you can do something after it's done so do you already know the solution so of course we can go here we can just say loading automatically to true and let me just bump this up so we can say loading false when it's done right you can say false and it's going to update and now also let me update the template so if I go to adding R to do Pico has this awesome thing which is Arya busy so if Arya busy is true is going to show a loading spinner which is really awesome so you can say Aria busy and we already have a Boolean right here's the loading how awesome is this and we can also give it a conditional class we can do it like this class secondary what is the Boolean loading let me just say this how awesome is this friends so now if we go here and I can say one two three four whatever now this should show a loading spinner here because it's going to take two seconds or let's see oh how awesome and we can also even make this better so here where the text is let me just put it like this and now we can just do if it's not loading show the text so you can just say add to do let me just save this and we can put this on one line but who really cares okay so now let's go here and we can start adding something all right so now it's going to take two seconds and awesome and you can also disable the input or whatever you want all right so how awesome is this so now for example if you get an error or success State you can show a toast notification to the user which is really awesome but I'm going to leave that to you as an exercise alright friends let's learn how we can do form validation in circuit and first I'm going to show you the hard way and then I'm going to show you how you can use a popular schema validation Library like zot and show you a couple of Tricks along the way and I'm going to create a login route using this first example so this is from plus page.soil you can just copy over this form and now I'm going to close it and let's go to the routes we can say swell kit files create route we're going to create a login route we're going to need plus page.sveld and you're going to need plus page server ts4 order form actions so let's press enter and now you should have a login folder so here is our page and here is our endpoint so we can just remove everything here we're not going to need it and here let me just copy this form over so we don't need to specify an action here because it's going to point to itself which is already slash login but I'm going to import using hence like this which is awesome and I can even specify they should use typescript all right so let's save it all right so let me go to that route we can say slash login and now if I submit it nothing is going to happen right so we can say required which is natively supported in the browser so now if I try to submit it's going to say hey please fill out this field but there's a problem with this any hackerman can come along and they can inspect this and they can say Okay required not today type password I really feel like you should submit an email today and this is going to cause chaos okay and this is why you should always do server side validation alright so I'm going to close this and I'm going to remove required for now because it's going to get in the way and now I can go to the page.servert TS file and we can say export cons actions it has the type actions which should be imported so we can use the default method and we can draw the structure request like this and awesome all right so let's get started first we need to get the form data of course const form data you can say a weight request form data and now we need to get the input values so we can say user we can say form data get user and then I can just copy this over and we can say password and of course we need to turn this into a string you can already see how this is starting to feel tedious because imagine if you had something more complicated and yeah I'm just painting a picture here so all right so here is something else we need to do now we need to invent our own way again how to handle errors you can do this many ways but I'm just going to have an errors object any of the error object has anything in it we're just going to return the errors so I can say const errors going to be an object let's just give it a type like this so remember record and we can say the key should be a string and unknown and this really isn't important so this should be empty and now let's do the validation right so let me just make space here so it's readable and now again now you have to do your own validation and you might not be even thinking about these things so for example you might be thinking okay if the user doesn't exist maybe that's it but you also need to check that they're not screwing with you so you have to say type of user so if this is a string right and then if this fails we can say errors user required but really doesn't matter what you say here okay so now we have to do the same thing for the password so now we just have to say password or type of password is it equal string and I'm already falling asleep I don't know about you and now we can say errors password required and all right this is how everything is going to work so now we can say if so now we need to get the length we can say object keys and we can pass errors and now we can say hey is there any errors here and then we can do something and also here I can just fix this it's not three s's so you can use it like this awesome that is resolve and now we can do this validation so now we can return fail so if I press enter it's going to import it let's see at the top all right that worked fine and now we can give it a status and we're going to return some data and let's just make this more readable so I'm going to Define it like this I'm going to say cons data okay so the first thing I want to return is some data right and then I'm also going to return the errors all right but how do I return this data and basically I just want to turn the form data into some object we can get so we can say object from entries and we can pass it form data and this is going to return an object instead of form data and we can just return the errors and that's basically it it really doesn't look complicated but again it's really tedious right and for the last part we can say if everything was successful let's learn about a new thing okay so how can we redirect okay swelkit also has a useful method for this so we can throw a redirect you can Auto Import it so it's going to import redirect okay now awesome let's see what are the options you can specify a status let's say three or three and where we want to redirect well let's pretend the user is logged in and now they can go to the to-do's all right so now we really didn't use the validation in the template but let's say if we type this one two three four it should redirect to deduce all right awesome all right so now we can go to the template and again we need the form data so we can say export plate form which is going to be action data let me just do my snippet here so you can see what's going on all right so this is really cool so for example if we don't specify anything we're going to get this shape so you're going to get data user password empty and the errors right which is really awesome and then let's say if we specify the username or whatever you can see here is the user so now because the form resets we can use this value here so let me just show you and let me just go here I'm just going to make space here we can go to the user and now here we can say value and now we can say form data if user is located we can use that value otherwise we can say hey just leave it empty and then let's do some validation we can say form errors user let's also not forget the question mark and we can also give it a paragraph let's see paragraph class error and now we can say name is required all right so let's copy this over we're going to do the same for password you can already see this is easy so we can say password and you can say password is required all right so let's save everything and let's specify some style so you can say Style error color tomato so now we can see here password is required let me just remove this so you can see we get both name is required so if we input our password name is required but if you do this everything should work great and you should redirect us awesome let me just refresh for good measure and now you can see what's going on again here password required and that's how we can output this in the template alright this is really cool but again as I said this is really tedious imagine if you had something more complicated now you have to do all of these if statements you need to get the data from the form and this is where result comes in and so it is basically going to validate the schema which you can set up yourself so we don't really need to do this if or whatever and the template is actually going to stay the same which is really awesome so I'm going to open the terminal let's stop the development server and now I can say pnpmi zot and I'm going to use another package which is Zod form data which is really awesome because you can just pass the form data or URL search params which you can parse and it can validate that so let me just do that quickly and another awesome thing about zotform data is a great example of using web standards because that package was made for remix but because remix and swellkit use the web platform it works flawlessly all right so let's start the development server again let's close this so now let's change this example to use zot for validation and I'm just going to remove everything here just so we can see how that works all right so let's make some space and now again we just need the form data so we can say I'll wait request form data so now we can Define the schema and how do you do that and we can say login schema and we're going to use sort form data so you can say zfd and this should be Auto imported awesome and then we can say form data and now you can Define your schema instead of doing all those if conditionals right and what are the fields we can say user so we can say zfd type of texture can even use Zod which also has validation methods and we also have password on it which should be zfd text and this is really awesome all right so we need to parse it so we can say const result and you can say login schema and on the login schema we can invoke save parse and we're going to pass it the form data and this is why this library is awesome so let me just scroll up and I'm just going to put it like this and now we need to check if there was an error so you can do it by saying hey if the result wasn't a success and now we can do the same thing that we did before so I can say return fail we can give it 400 and we can return the data now you can see what is going on so you can say data and this is awesome all right so how do we return back the data I can just say object from entries and let's pass form data back in and now for the errors which is more interesting you can learn more about this by reading the Zod documentation from the result you get error and we can flatten it and now we can also return the field errors so let's return the field errors and lastly let's also do a redirect so we can say Throw redirect if everything is fine 303 slash to Do's all right let's save everything and you can see already how this is so much nicer and easier and now you can store these schemas in a separate file you can abstract this validation logic in another file and you can pass it form data in the schema and you can return back the data in errors if you want and make it reusable and as I said before you shouldn't have to change anything here and now when you go here let's see if this works you can see data user password and the errors and of course I don't know how to type because you can see here we use it two hours and here let me just see errors yeah left we can adjust it and let's see okay now name is required password is required so I can say test awesome so now if we just do this and let's submit okay so now let's do both and this should redirect us to reduce awesome how awesome is this right of course this isn't the only way to do validation result and you can read more about error handling in this alternate documentation but form validation honestly deserves its own video alright friends in the last part I want to show you some Advanced enhanced action customization for example I mentioned how actions can be invoked from other pages in this example I want to reuse this login form so just want to copy it over let me just close it and here in the page cell which is our home page or root we can just replace it and let me just save it so now if you go here and you will maybe expect that this would work and if we go here of course it wouldn't it's undefined because the form didn't get updated because it has no idea even if we let me just we have to say action it should go to login right because we're inside our root and we're going to basically Target the slash login so now we go here again nothing is happening the redirect should only work so now if we type anything here it should redirect you to Do's but how do you make this work and we can make this work customizing the use enhanced action so for example I can go here and let me just say login and now we can go here and I can say cons login which is type submit function so it's going to get Auto imported for us and let's just do this and now we can return the Callback which is going to be async so previously we learned about update right it might be thinking okay maybe if I try update but you're going to see this isn't going to work right because this isn't going to update the form data for other routes but only for itself all right so here is something also we can do besides update you get this awesome result so let me just console log out result and let's open the developer tools and now when we submit it you can see we return from the action type failure status even the data with the data and errors and how awesome is this so you can see right now it's not even going to redirect because again we provided a custom callback so now when I say test one two three four it should be a redirect so you can see redirect status and the type how awesome is this so now you can use the apply action method which unlike update can update this form property and the store or for the form from anywhere so you can first get the result like we did it now but now let me just say a weight and we can import apply action so it even tells you what it does the auction updates the form property of the current page with the given data and updates the store and in case of an error is going to redirect to the nearest error page you're going to see how this works in a second you can say apply action and now you can pass this result right so look at this so now when we let me just close this so now when we Press login it's going to return the data which can be reused anywhere how awesome is it so now name is required and now if you say test1234 now we should redirect to deduce and how awesome is this because now you can reuse this anywhere and you don't have to again specify the same actions and return the same data alright but let's have a closer look at apply action so let's just cancel out the result which we already did but what does apply I actually really do and really it depends on the result DOT type so if we go here let me just remove this so we can make space and say result type and now we have everything here from success to whatever else so you have error failure redirect so let's say for example that we only want to do something when it's a success otherwise it won't do anything we can just go here then you can do whatever you feel like doing here and then you can say await apply action and you can pass it back the result and this is only going to do what this logic does in the case the result type is a success and nothing else so for example in this case this is only going to redirect us on success or if there's a redirect so for example it changes to redirect but this really isn't going to return data for validation Etc so if I press login here we shouldn't get validation back because this is only going to apply the logic related to this type of result type so if you press login you can see it doesn't work but it's only going to do this if the type is redirect so now it gets back to redirect and that's how that works and this might be really confusing at first the difference between update and apply action but just so aware of it and when you run into that situation we really then you can be like okay maybe I should go back and re-watch this or I should read the documentation So based on the result type if you get success and failure is going to update the form the dollar sign page result form and dollar sign page.status regardless where you submitted form this is the difference between apply action and update and if it catches a redirect is going to invoke go to and use result.location and if it gets an error is going to render the nearest plus error.swell page this way you can customize the behavior of the using hands action and dip in and out of the regular behavior when you need it alright so that's everything you should know to feel confident working reforms in circuit if you found this helpful don't forget to like And subscribe and if you want to support me you can find the patreon in the description thank you for watching and catch you in the next one peace foreign [Music]
Info
Channel: Joy of Code
Views: 17,444
Rating: undefined out of 5
Keywords: svelte, sveltekit, forms, progressive enhancement, form actions, zod
Id: XNbCp7ZJi-8
Channel Id: undefined
Length: 62min 55sec (3775 seconds)
Published: Fri Jan 20 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.