Join Bryant for his final 60 minute rush of the season as he attempts to plan and build a form builder.
Speaker 0: Welcome back to another episode of 100 apps, 100 hours where we try to build or rebuild some of your favorite apps and app ideas in 60 minutes or less or die trying. Emphasis on the die trying. But, if you've not seen the show before, there are basically two rules. You have 60 minutes to plan and build, no more, no less. And the second rule, the anti rule, use whatever you have at your disposal.
So today, let's get into the episode, we are going to be building a form builder slash Typeform clone. If you're watching this, you're probably familiar with Typeform, but let's just run through it really quickly. Basically, it is a form builder that, does questions. It's like 1 question at a time. You can customize the design a bit.
It kinda looks like this where, hey, we fill out a form. I have to do an actual email here. Then, another question shows up. We go through this. Another question shows up.
There's a lot of configurability there, but that's it really. It's a nice looking form builder that that hopefully makes people wanna fill out your forms. That's it. That's what we're gonna build. So let's dive into it.
We will put where's my where's my widget? Where's my widget? Timer. Where's the time? Oh, they moved the timer on me.
Okay. So we're gonna put 60 minutes on the clock. Let's roll with this. Alright. So let's start kind of planning this out.
Right? I always like to start with the functionality. Feature what features do we need? Right? We need to be able to build a form, fields, field types, etcetera.
How do I there we go. And then we want to be able to submit that form. Maybe render and submit form. Boom. That's it.
Really? That's all the features that we need for this. We wanna build a form, maybe we call this a schema. Then we wanna render the form and submit the form on a front end. Alright.
So how do we go about actually doing this? Now, there's a project that I created previously called hgos that has a kind of form builder in there. It is, not the most robust solution. So, the setup there is basically using the JSON repeater inside Directus, which is basically, just an array of form fields that we're gonna use. We pass that JSON to our component on the front end that renders a form dynamically based on the different types of inputs that we want.
And then when you submit that, it all goes into a single table, into a single collection. So that is super flexible. And and if all you need to do is, output a a JSON schema to create a form and have a single collection, where you store all that data as JSON, great. Let's take this a step further in this episode though. And let's add this, make this a little more robust.
So when I think about the data model, we're going to have a form or forms. Each one of those forms will probably have some form fields. Great. And then on the submission side, we've got like a form submissions. And within that, we have an ans we have answers, I guess.
And so we've got the form submissions belong to the forms, the answers belong to the form submissions. Just kind of drawing these things out. There'll be a relationship between the answers and the form fields. I skipped the magic arrows here. Great.
There we go. So this is kinda the way I've got it in my mind. We've got a form that holds all of the form fields. There's probably a title. We've got like a redirect or or some kind of on submit action, what we wanna do with it.
On the front end, we fetch that form and all the form fields, we render it. When somebody fills out that form, we create a form submission, and that form submission is made up of answers and probably some metadata about when that form was submitted, who's submitting it, etcetera. That sounds like a good start for our planning. I'm just gonna throw these up side by side so I don't forget. And to start this out, I've got my blank instance of Directus, that's what we're using on the back end here.
We're just going to hit create a new collection. Let's call this Forms. Now I'm gonna use the UUID for this. Maybe we just do the standard format here. User created, date created, date updated.
I'm gonna wanna know what the status of these forms is. Do we need a sort for the forms? Maybe. Do we need a status? We'll just go ahead and add it.
Alright, so let's give the form a title, maybe a form description, so that'll be a text area. And then we're going to create another collection called Form Fields. So we'll just go in, create a new collection. What's happening behind the scenes, obviously Directus is creating these tables in MySQL database. The fields, we definitely need to sort on the fields.
Do we want a status on those? Maybe, maybe not. No. Let's keep status off of this. You know, do we want to know when the actual form fields were updated?
Maybe I'm not super concerned with that, so we'll just leave those off. All right. So for the form fields, when we're thinking through this, right, what are we gonna need on our actual form fields? We're gonna need a name for the field. So what's the field name?
We're gonna need a type for the field. So the type is probably gonna be a string, but maybe as far as, like, the interface that I wanna use, I want this to be a drop down. So we can think about input. Great. Do we have a, like, a form field for that or an icon?
Yeah. Let's try that. Let's do text area. Text area. Text area.
Do we have one for that? We don't. We'll just go with that option. What else do we wanna display? Like a select?
Just thinking along the lines of the actual HTML form elements we're gonna use here. Drop down, maybe select. Good looking icons are sparse here. Okay. So that's probably good for now.
We'll just make this a label, format each label, we don't want to show as a dot. I can actually copy and paste the choices for our interface into the display here. And this is what shows up on the, like, the index pages where you could potentially see a list of the form fields. Alright, so we've got a name, let's make this half width, make it look good when we're actually creating our form. We've got a name, I could double as label.
Trying to think of what else we've got on this. Maybe some type of validation name and type. If it is a select type, we probably need, like, some available choices. Right? So let's go ahead and do that.
We'll do that as the, like, JSON repeater. We'll call this select options, I guess. Great. We'll add a text field. So this is the text we're gonna display or we use kind of the label value format.
So we set that up, that'll be an input, very simple. And then we have a value. In case we wanna store those differently, we can require a value, make that half width as well. Great. And let's add some conditionality to this that, if the type is select that's when we show this.
So I'm gonna go into our field options, let's just hide this by default, and then inside Directus I can add conditionals to the forms inside the Studio by doing something like this. So we'll say show if type equals select. And this is just a description so I can keep my logic together. We'll say if the type equals select we're going to make sure this is not hidden, and that should give me what I am looking for. Right?
We could expand this further and add, like, conditions to our front end and etcetera. What we need to do now, though, is add the relationship between those. So in this case, we want a form field. It should only belong to a single form in my mind. I I you could I guess you could make the argument either way, but in this case, let's just create that relationship.
So this is gonna be a one to many relationship here. So this is gonna be called Fields, and I'm inside our forms collection, our forms table right now. I'm just going to call this key fields and we're going to look, the related collection is our form fields. And the foreign key inside the form fields table, I'm going to create a new field called form that relates back to the actual form. Gravy will show a link to the item.
And if I open up this advanced field creation mode inside Directus, I get a lot more options that I can configure and play with. So I'm going to add a sort field, we're just going to make sure that sort is selected here. That allows us to drag and drop the order of those fields. And then for our triggers, like if we deselect a form field, do I want to delete that item or not? In this case I'm just gonna nullify the form field.
Great, we'll display the related values. Bada bing bada boom. Now we should have a form with some fields. Let's just test this out really quickly. So we're gonna go in, we got a form.
This is our contact us form, the most standard of all forms on the Internet. And here's the standard contact us form. Great. Alright, so we'll do name, is gonna be email, this will be an input. Great.
What are some of the other things that we'd probably want to add to this? Like a placeholder, I would say. First name, that'll be an input. What else? Last name.
Okay. Comments, that'll be maybe a text area. And now let's, let's get into the select option. Right? How can we help you?
Alright. So for the options here, I need a developer, so we'll give it a label. Maybe we store the value as just developer. I need a sales rep. I don't know.
Great. Okay. So a couple of things here. I don't see the actual form values that I I might look. You know, here's they're just showing IDs.
How can I fix that, right? I want to make sure this looks nice when we're setting these things up. So what I can do, if I go into my form fields, we have the display template. So this is the default anytime we're referencing this form field. Or I could go into forms and go to the fields section here and I can control the display template just within forms.
So that's super handy if you, need different display templates in different places, but in this case let's just go and edit the default one. Let's do the name and then we'll maybe put like a special little dot there and maybe we want to show the type of field that is. And now if we just go back to our forms, great, we can kind of see what we're working with here. I don't really let's put first name, last name, then email, then comments, and how can we help you? Maybe we move that up above.
Right. Great. Alright. So now we've got the start to this form. Let's go in and actually start messing with the front end.
We've got 47 minutes on the clock. I'm just gonna pull this up. Let's pull up my Nuxt application. This is just the standard Nuxt application that I have out of the box. That's my weapon of choice in this case.
And let's just go in, I'm going to create a new directory in the pages directory. So this will give us a route automatically on the front end. I'm gonna call this forms, and then I'm gonna do just form in brackets here, and that will give us, like, a a dynamic form. If I do view script setup, TS setup, this is kind of what I want. Great.
We've got the standard Vue Form Component. And we'll just say Form Component. Great. Alright. So let's test this out on the frontend, forms.
Test. What? Uh-oh. Some type of issue going on. There it is.
Form component. And this has got a layout attached to it where we're showing, like, the logo and things like that. Maybe not a huge issue for this, but, you know, the type form has, like, this full screen form effect, so, you know, maybe we dive into that later. Alright. So now I actually want to fetch that form from Directus, right?
So a couple things, we probably need to edit our access control. So by default, Directus locks down every single thing inside your instance. Only admins are able to, interact with the API by default. So we're just going to go in. I'm gonna set readability for our forms and our form fields, and now if I just wanted to test that out quickly, I could do something like this in the browser where I go to my directus url/items/forms, and I can see I get the form data here, and and we'll expand that, once we dive into the Nuxt side of things.
Right? So the first thing that we want to do here, we're gonna get the routes, so we know which form to fetch. And then we're gonna be using the Nuxt Async Data Call. So this Nuxt application, I've got a Directus plug in here that basically fetches information from the Directus API. We provide the SDK to the Nuxt application so I could do things like this where I just simply say give me the Directus client.
And that way it's shared across the actual Nuxt application. So I get my Directus client, and then we're gonna use the, let's say data is coming back. We're gonna use the Async data call from Nuxt. And within that we are going to return Directus dot request. And then we need to import the readitem from the Directus SDK.
Alright. So this is just going to read a single item. We're gonna pick that up from the actual form, from the route itself. So we'll say directives dot request. It'll be read item.
We're reading items from the form collection. And then we've got route dot params dot form. Right? So that will it should give us the form. And then I can pass a a set of parameters to the Directus API to get things like form fields, etcetera.
But let's just take it from here. We'll wrap this in another div. I always end up doing this just to take a look at my data and just wrap it in a pre tag. And now if I do forms test, we're probably not gonna get back any data. If I was to open this up, I don't really see anything here.
Great. Alright. So now let's actually test this with the ID of one of the forms. We'll go in. Great.
Okay. Looks like we are getting a cores error. So I've goos something up in my direct to settings. CORS enabled. CORS origin.
Should be interesting here. Let me restart this Docker container and see if that solves my problem. If I look at my ENV, I've got HTTP local host 8055. That is that's where my direct instance is running. Okay.
There we go. I just needed to set the cores in this case to make sure that local host 3,000 is allowed, and basically, I've done that the quick and dirty way just by allowing any origin here. But, typically, I would set this to, like, local host or something like that. Alright. So we could see here's our form data.
That's great. How do we actually get the form fields? One of the nice things about the Direct Express API is the ability to call this data in a single API call to expand those relationships, right? So inside my form fields, maybe on the front end, I don't really care about this extra data when it was created. So let's just say we want the ID, we want the name of the form, we want the oh, it's actually the title of the form.
Title. Great. And we want the description. And then we get into the fields. All right, so I could do something like this where I add a dot notation and a wildcard which will give me all the items for that field or all the all the fields within the fields collection or the the related items there basically.
So instead, what I'm gonna do, if you're using the SDK, we could pass it a syntax like this where we say fields. And here, we're gonna specify the actual fields. We want the name. We want the type. We want the options, and that should give us what we're looking for here.
Right? And we probably do need the ID of those fields as well. We'll look at submissions in a few. Okay, so now we've got these fields coming in, this looks good, we've got a type, we've got a name for these, we can start to construct like a form with this actual data. Now on the front end in this Nuxt application, I have this Nuxt UI library.
It would be suicide to try to build this without a form library, ahead of time here or, like, some type of UI library so I could do forms. They've got this really nice setup where you can pass it a form component. They've got Zod validation, support for Yelp and Joy if you're into that. But looking at this, everything gets wrapped in this form group component, which gives you like a nice label, etcetera. So let's just try to iterate through this.
Right? We've got a form. They have a u form component. Not concerned with, like, validation at this moment. Let's just display a form.
Right? So we're gonna go through Uform group, v 4 fields and forms dot fields. The field, we wanna pass like a I think there's a name component for each one of these. Like, if we go in and look at the props, we gotta pass a name to it. So we'll do name.
It's field dot name. Great. What else do we need here? So within the form group, then we are going to do the actual component. So we've got an input here.
There's a select box. Great. What else do we have? We had text area. Right?
So what I'm going to do, I'm just gonna create a map here, basically. So we'll do, a field map. And I'm just gonna do something like this where, that actually looks pretty good. You input, you text area. That's how all these are name spaced.
But what I wanna do instead is use this, like, resolve component or, you know, I could even actually import these as well. So this resolve component is just a helper. You could just straight import them as well. And with Nuxt, you can actually load these dynamically as well by adding lazy in the front of them. So it only pulls in that, that component when it actually needs it dynamically.
Alright. So we've got our fields, we've got our form groups within the form, and GitHub Copilot is helpful again in this aspect that we want to do the field dot type inside. We wanna pull that correct component from our map, give it a name, give it an options. Let's take a look. Options are there.
Name and value. Okay. So let's save this, see what we get. It looks like we have some we got some form of something going on. I need to change this right away to input so we can actually see those.
Let's give this a little bit of styling. Right? Maybe we do, like, a max width XL. Format with math width Excel MX Auto. Great.
Maybe we make this a grid. We give it some gap. Why is this actually not should be parsing out my is Tailwind not included in this? What what have we got going on? My styling is not being applied from Tailwind.
That's kind of upsetting. We can definitely sort that out though. And then we need a label for this as well. So we'll do the field dot name for the label. Okay, so now we've got a kinda set up in there.
Let's do view button. And we'll do, like, a submit option here. Let's add that outside the form group. So we get a submit button at the bottom of this. Right?
Okay. So how can we make this kind of like typeform in a way because we wanna answer these one question at a time? Or how can we kind of loop through these? Right? Gillespie.
Great. We don't have a state for these, so we'll we'd need to update that as well. Let's do v model equals set up, like, our form data. Form data, maybe we use like a ref for this. It'll be form data, and we can dynamically do field dot ID.
Let's put this in like an answers array. Answers. And then we're gonna have the field dot ID. Okay. Alright.
And within this, I'm just gonna do answers, and we'll just preset that. All right. So now if I take a look at like my Vue Dev Tools and we go to Form, Okay. I can see my Directus object. I've got my form data.
There's my answers. Now if I populate these, is that actually doing what I want? More data. Click form. Do we see our answers?
Oh, maybe we want to grab the index of this as well. Field index inform dot fields. That could be helpful. Answers field index field dot id. Bryant Gillespie.
Bryantdirectus.io. Let's take a look at the data we're pushing here. Okay. So I can see my fields now. Oh, nope.
Form data. There's my answers. Okay. That'll that'll suffice for now. All right.
So let's do these one at a time as well, right? So maybe we give this a const current field idx. We set that to 0. And then, how are we gonna want to display this? Alright.
So we're gonna render each field conditionally. Alright. So let's just wrap this in a template. This will be the what are we gonna do here? So we still need to show the actual field.
V. This could actually be something like this, I think. V if current field current field IDX equals field IDX template. We'll loop for these Fields. Field IDX, inform dot fields key equals field dot field.
Nope. Field.id. Alright. Let's see what we've got here. Oh, don't wanna close.
Let me open this up. Alright. V field dot ID. We don't need a key on that one. V4fieldsfield.
Alright. So now we've got kind of this one field for each. One of the cool utilities that I use a lot is also the auto animate by a group called FormKit. It's, v autoformkit auto animate. One line of code or just a couple lines of code and you've got, like, nice form animations, for, like, list transitions, showing and hiding inputs, etcetera.
And we're only gonna show the button if fields, field idx is equal to form dot fields dot length. Field.ex +1 is equal to form.fields.length. So here we shouldn't be showing that button. Give us a padding here. Cool.
Alright. Now within this, we probably need, like, a previous and next button as well. So let's just do, like, a flexbox, Go to some gap. We'll do U button. Next.
Okay. GitHub Copilot. Alright. So basically, if the current field IDX is greater than 0, we're going to display the previous button. If the current field IDX is not greater than the end of the form, we want to show that.
But we need to fix the actual setup here. You form group. Maybe we wrap this in a div. Okay. So now you could see we could kinda go through each one of these.
And do I have the actual auto enemy applied properly in this case? Via, it should be. It's not actually animating. Let me refresh. Ah, there we go.
Now we're getting some nice animation or animations. Right? So we'll do some margin there. Add justification between these. And we do one of these as variant equals soft.
Is that what it is? There we go. Alright, so this is the primary. Great. There we go.
Cool. Alright. So now I could go through and fill out this form. Alright. Oh, that's actually submitting the form.
I don't wanna do that. Alright. Next. Gillespie. May we change this to button?
Great. Give him my email. Cool. Starting to look something like Typeform in this case. Alright.
So test, test, test. V if field equals fields dot length. Oh, maybe this is the actual code that we need here. Why are we not seeing the so, oh, because it's not in that actual loop. There we go.
So now we should see the submit button. Great. We don't have any type of handler on the submit button. And it's also not doing anything if we actually, were to submit this anyway because we've got, we we don't have anywhere to post it inside Directus. Right?
We've got roughly 20 some odd minutes. Let's make this form actually submit. Right? So if we go back to our setup, right, we've got, a form submission, we've got some answers that are within that. So let's go ahead and set up those collections.
Let's say form submissions. These will be DUID. This will be let's call this submitted, date submitted. That kinda matches what we've got already. Yeah.
Maybe we wanna track the time that it actually user created, date updated, user updated, the status of this submission. You know, you could even like, building your own here, you could certainly, like, track partial submissions and things like that as well if you wanted to. Like, we could submit any time and then update whenever they submit the final one, sort of thing. But let's say we have, like, a date started type of thing. Maybe we wanna, like, store that whenever they start this form submission.
So we could track things like how long it actually took them to do this. For that we want the date time. We're just gonna do time stamp. Cool. Day started.
Date submitted. Let's make sure we show that field. I'm just going to make one of these full width so I can get what I want out of this. Okay. Alright, so the form submission, we've got to link that back to an actual form as well.
So we will do a mini to 1 here. This will be our forms. And let's do forms as the related collection. Now if I open up advanced mode, I can also create the inverse relationship as well. So if I wanted to do something like this where inside forms I've got a relationship back to the submissions, which in this case makes a lot of sense because of probably want to see the submissions.
We could set up that and create that relationship in a single go. So there's our form. And then the next thing that we want to do is create a form, I'm gonna call it form submission answers. It could just be form answers, I guess. Always like to, have like a a common prefix, among these things, especially when you start building projects that have a ton of tables in them.
Alright. So there's probably a sort on that specific answer. Do we need any of these additional fields? Probably not, right? So when I think of the answer, we've got a relationship back to the form field.
So we'll just call this field. Let's Create that. There's the form fields collection. And again, I could do the same kind of thing. And setting this up this way, you know, with all the different database tables and the collections inside Directus allows us to, you know, say I wanted to query all the fields or all the answers from a single field on the form.
This makes that a lot easier as well. So if we go in here, let's just add that corresponding one to many relationship as well. Let's call this answers. Great. And then we've got, what, just like a value?
I'm I'm just gonna simplify this. I'm gonna sort everything as text. You know, if you had different field types or like numbers or dates, maybe you wanna store those in the underlying database as that specific data type. You know, you could set up some different fields for that like value date, value text, value number, etcetera. But to keep this easy we're just gonna store everything as a value.
Alright, so now if we just poke around, right, if I were to like manually add a submission here, I could click create. I'm not seeing the actual answers relationship here. Form answers, form submissions. Oh, that that would be why I'm not seeing it because we haven't created it yet. So the last thing that we need to do is link this form answers to the actual submissions.
So we'll go in and on the form submission, this is going to be a one to many relationship, so we'll call this answers. And the submission ID, great. We'll show a link to that item. Just inspect this. It looks great.
We got a sort field for those answers. Cool. Everything should be gravy. Right? So what's helpful sometimes, especially, like, if you're doing CRUD operations from the front end, maybe I wanna go into this form and I add a new submission manually.
Alright. So just say this. Great. Add some answers. Here's our field that we're answering.
Bryant. Create a new one. Last name, Gillespie. And this is a little bit cumbersome, but, again, we're gonna be handling this from the front end. Gmail.com.
How can we help? This is gonna be what? Sales rep. And then some comments. Comments.
Okay. Alright. So now we've got a submission. I can see kind of the answers here, and these are not super helpful again because we haven't adjusted like the display templates for those. So our form answers, maybe we want to show the the field name, then the actual answer.
Great. Let's set that up. For our form submissions, maybe we want to show the, like, the date this was created, submitted. We wanna show the form as well. So we'll just show form dot title.
And let's just edit this. Underneath the hood, this is just much syntax. We can also do dot notation to access the related fields as well. Set a little bullet point. All right, so now if we go into forms we can see the contact us form submission a minute ago.
And now I can see the individual answers here, which is kind of helpful, right? But let's take a look at the structure of this on the other end. So if I wanted to see an individual submission, I'm just gonna pull this up, copy this, we've got items, form submissions. And then I can get the actual submission here. So here's kind of the structure of this, and this is what we would need to post as well, right?
So we've got a form ID, then we have the individual answers. If I do question mark fields, we do just all the root level fields, we grab the answer fields, see what what kind of thing that we need to pass, right? So we got the field ID that we're gonna need to send via the API request when we submit that. And then we've got the value, so what the value of that is. Okay.
So now let's take a look at actually submitting this form inside here. So let's create a new function. Let's call it Async function. We'll just call it Submit Form. Great.
And what are we gonna do here? We're gonna have, like, a transform the form data to the format you need, submit to the Directus API. Alright. So if we look at our actual form data, how do we get this set up? So it's just an array of answers.
I probably could have made this even simpler than that, honestly, and could have done, what, just the the form field ID. Let's just test this out. Right? Form data dot field. Let's do it this way.
Answers. Form data. We still do answers. Just make that an object, and then we can add the ID for that. Async function.
Oh, misspelled function. Just wondering why that wouldn't compile. Colosbybryant@gmail. Great. And now if I just refresh down here, click form, do we see our form data?
There we go. We've got that. Cool. Alright. So when we submit this form, let's, transform this data.
So, we're going to map through the answers. So we will do data. This is a good ID as well. We're gonna need the form ID. So this will be route dot params.form.
Then we have the answers, but we're gonna need to map those first as well. Map answers. Alright. So object what do we want? Object dot values, object dot keys, form data dot answers.
Yeah. There we go. For each. So we're gonna do the data key. Let's just take a look at our structure here.
We've got the answers. So we need an ID. No. We don't need an ID for the actual answer. Directus should create that for us, but we do need the field ID.
Alright. So we've got answers here. This is gonna be an actual array. And then for that, we're going to do answers dot push field dot key dot value. Answer is key.
Great. Hey. We do console dot log just to test this out. Let's Data to be submitted. Save this.
See what we got, Bryant. Oh, got all this selected. Gillespie. Okay. And then let's add submit or at click submit form.
We refresh really quickly. Right. Gillespie. And now if I hit submit, Form data. Oh, that's a value.
That's reactive. So let's do, like, an on that. Bryant Gillespie. Hit submit. Cannot read properties of undefined.
Field uncaught in promise. Object. Keys. Answers.key. Form data answers.
Console dot log, form data. Let's just unref this form data to see what we're getting. Brandt. Form data. Target.
Answers for each key, data dot answers dot push, field key, form data. Oh, duh. Gotta unref that again. Silly sometimes. Great.
So now I can see here's the data to be submitted. There's the field. There's my value, etcetera. Now all we should need to do is actually send this. So, let's do create item from the Directus SDK.
And just the same way we can fetch those, relationships, those related fields in a single call, we can also push responses to the related fields in a single call as well. So we'll do let's do data. Let's just see it this way. I can't remember what's gonna be coming back. The async data call returns reactive values for data.
But we're not gonna use async data here. This will be just like regular fetch. So we'll do await. Actually we can just use the directus SDK here as well. So we'll do directus dot request, create item, and this will be form_ submissions data.
Is there anything specific we want to return from this? Nope. Let's wrap this in a try catch and just console error any errors that we receive. Form underscore submissions with the data. Console dot log response.
Great. Let's see what we got. Alright. So we're just gonna pick on teammates here. We'll do a Matt Minor.
Maddie atexample.com. I need a developer. Help me, please. Alright. So we hit submit.
Do we see an actual network call going out here? Post forbidden. Oh, no. What are we doing wrong? Right?
Where are we at on time? We got 10 minutes left. We're we're in pretty decent shape. What we don't have here is the permissions to actually create items in form answers and submissions. So we go into our public option here.
We can see that, we've got the ability to read form fields and read forms, but we don't have the ability to create form submissions and create answers. Alright? So there's a couple different ways that you might wanna set this up. You know, if you wanted to, like, potentially route submissions through, directly to the Directus API or, you know, through some other, like, server side redirect, inside Nuxt through like a server route or something. Or in this case, we can just give direct public permissions to create these things.
Now one of the other things that you might wanna do on the read side of it, you know, I I might want to use like a custom permission or something like that so that, people can't read all the actual form submissions. So maybe just the, IDs, etcetera. Or I could even leave this off as well. I'm just gonna enable this just while in testing. Just remember to restrict this before you go to production.
So now if we test this form submission again, what do I get? I get a 200 okay. There's our submission. If I go into Directus, we can see we've got our form submission there. There's all of our answers.
That's great. We don't have the date started because I didn't populate that. Right? But what if we were just to do something like this where we've got the date underscore started, And we do new date. Great.
And this, let's say to ISO string. Just to be sure Directus will swallow that down. Alright. Let's test this one more time and maybe we can fix the field IDX, form field dot link, currentfieldidx. That's where we goofed up here.
Okay. So now we've got Bryant. We got Gillespie. We'll just add a bunch of junk here. Email test at example.com.
I need a developer. Oh, I like 35 submit buttons here. Let's go ahead and submit that down. Submit that up and see if we've got that date started field. Why do I not have that?
Didn't populate. Oh, I didn't actually pass that in there. Date started. Current field, IDX. This actually needs to be just out of here, doesn't it?
Alright. Bryant Gillespie test@example.com. Got a developer. Here's some comments. There's our submit.
Great. Take a look at our submissions. There we go. We've got our date started. So now we could actually, like, run calculations on how long it took to fill out this form.
We've got all of our answers in the correct place. We've got, like, 6 minutes left. Did we check all the boxes here? Right? We've got a form.
We've got the fields. We built the form here on the back end. We've rendered and submitted the form on the front end. Amazing. Let's see if we could just take this a step further.
Maybe we wanna create a dashboard for all of our form submissions. Let's see what we can get here. Maybe we do a simple metric. We want to just track the number of form submissions. So that'll be the field ID.
We'll just do like a count of that ID. Total form submissions. Boom, I can see we've got 4, right? One of the other things that I like to do when building these dashboards inside Directus is make this dynamic. So what I can do is, let's say I wanted to see the answers for a specific form.
What I could do is create a global relational variable. We'll call this, like, form ID. So we'll pick the form. Great. Show that out.
Select a form. See what we got here. I'm just gonna move this out of the way. So we can select a form, that variable is named form ID, and then maybe I want to show a list of responses. So let's show the form submissions.
And for the filter here, what I want to do, let's just show the date that that was submitted. Great. Under the filter section, what I can do here is go in and I'm gonna create a filter that uses that, that variable that we set up. So instead of hard coding a form value here, I could just do something like this where I say form underscore ID equals that variable and just wrap that in the mustache syntax. So responses for this form.
Alright, so when I save this, we shouldn't see any responses here. But if I pick our contact us form, we can see those, then I can open each of those up. Or, you know, we could also change this to something like field ID. So if I wanted to see responses for a certain field, so we'll just change this from forms to a form field. We can go in, the display template for this, maybe we want to show the name of the field.
Maybe we want to show the name of the form that it comes from, the title of that form, where are you. There we go. We don't need a filter there. That's gonna be our field ID. How are we doing on time?
We still got 2 minutes for this. We'll change this to select a field. Field. Great. Responses for selected field.
And then we'll just do the same thing here. We're just gonna change this, right? We'll change the collection to form answers. For our displayed template in this actual list, maybe we want to see the value. So we'll just show the value.
And instead of this, we're gonna do the field dot ID equals field underscore ID wrapped in mustache syntax here. Alright, so now if I select First Name I can see a list of all the responses. Great. Looking great. And then maybe we even duplicate this.
And let's say I wanna show those values in like a chart or something, right? So we got our donut chart here. We got our styles. The field that we want to count in that case is gonna be the value. And now I can get a breakdown of all of those responses.
Great. Cool. 1 minute 24 seconds left. Ring the bell. Again, this has been a fun episode.
You know, taking this from here, obviously, like, I would totally improve the styling, add some validation into it, but this would be super handy to have a form builder that you've got direct control over, that you don't have to pay outrageous prices for, well, like 30 submissions or something like that. I don't know. Let's look at the pricing. What do we have on Typeform? I like Typeform a lot.
The pricing is a bit crazy. Alright. $25 a month gets you or $29 a month gets you a 100 responses. Using Directus, get way more than that for less. Amazing.
Alright. That's it for this episode of 100 apps, 100 hours. I hope you've enjoyed it. I sure have. We'll catch you next time.