🕰️ Chapters
- Adding the Create Movie Button
- Defining All Resource Routes for Our Movies
- Planning Our Movie Create Fields
- Querying Select Options
- Defining Our Movie Create Page and Form
- Creating and Defining Our Movie Store Validator
- Creating An Exists Helper Validator Rule
- Finishing Our Movie Store Validator
- Validating Dates and Transforming to Luxon DateTime
- Validating and Storing our Movies
- Testing Our Movie Store Form
Allowing Admins to Create Movies
In this lesson, we'll allow our administrators to create movies via our admin panel. We'll walk through getting the form set up, validated, and our movies created.
- Author
- Tom Gobich
- Published
- Jun 12
- Duration
- 16m 39s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Allowing Admins to Create Movies
-
[MUSIC]
-
For our admin movie actions,
-
let's start by adding the ability to create a new movie inside of our application.
-
So we'll start by adding in a create movie button right over there.
-
So scroll on up to where we have our H1,
-
wrap this inside of a div class flex justify
-
between and add a gap of four there for safety sake.
-
For our H1, and then we'll do a div and add a button into it that goes to an href,
-
and we'll put a pound there for right now because we don't have the route created,
-
and our button, and we'll do create movie,
-
and we'll probably also want this to be items center there as well.
-
Next, let's go ahead and create the route for our create movie page.
-
So let's jump into our routes file,
-
and then let's do router.get/movies create admin movies controller,
-
and we have our create method there as movies create.
-
Now, let's pause here for a second.
-
So if you recall to when we created this controller,
-
we created it as a resourceful controller,
-
and there's also resource routes.
-
It's my personal preference to list out the routes individually,
-
but I know that may not be everybody's preference.
-
So an alternative that we could do to listing them out
-
individually is router.define this as a resource route group.
-
You define the resource name,
-
so that's our movies,
-
and then provide in the controller that handles the resource,
-
which is our admin movies controller,
-
and that takes care of the rest.
-
So we can remove those,
-
and now we have a route defined for each of our resource actions.
-
For example, if we stop our server,
-
clear that out, and do node ace list,
-
there is an actual list command called list routes.
-
I don't think we've taken a look at this quite yet.
-
Maybe we did early on, but let's clear this out.
-
Node ace list routes,
-
hit enter on that, and we're going to get a list of all of our defined application routes.
-
Right down here are all of the routes being defined via
-
that one line where we're doing router.resource movies.
-
It's prefixing all of the defined routes with movies.
-
For our create route, it's doing /create.
-
For our show, edit, update,
-
delete, and destroy routes,
-
it's appending on an ID route parameter,
-
and on edit, it's making it unique by doing /edit there as well.
-
Additionally, you can see each of these get a name too.
-
So we have our admin movies index,
-
the same as we had it before,
-
admin movies create, the same as we had just manually defined it.
-
We also have our store, show, edit,
-
update, and destroy names as well.
-
You can see put and patch get the same route name as they're discerned via their HTTP action.
-
So we can clear that out, boot our server back up,
-
so npm run dev.
-
So we should be done defining our routes for our movies resource actions.
-
Meaning that we can now jump into our movies controller.
-
For our admin section,
-
scroll down to where we have the create method,
-
grab the view, return view,
-
render, pages, admin, movies,
-
and we'll create a create page.
-
We're going to want to provide some things in.
-
So first, let's go ahead and take a look at our movies model
-
to remind ourselves what all we have on here.
-
So we're going to need to provide the status options as a select,
-
so that we can select the status to apply to a movie.
-
In a real-world application,
-
it would be great to just pull this writer and director in as an autocomplete.
-
So as you type out, it will fetch and provide options in.
-
That behavior is not quite manually supported by the browser,
-
and we would need to pull in a third-party package to support that on the browser side.
-
So we're going to bypass that approach here today,
-
and just provide our sinister as a select list,
-
so that we can select our writer and director IDs there.
-
Then we'll have a title, our slug will be auto-generated from the title,
-
summary, abstract, poster URL,
-
release that, and that looks like it.
-
So that we don't have to remember that,
-
what I'm going to do is drag this off to the right-hand side,
-
and we can nudge it in there a little bit to make it smaller,
-
just so that we have the property names here to
-
reference and remind ourselves what we need.
-
So we're going to need the statuses.
-
So const statuses equals await movie status.
-
We can import that model query,
-
order by, let's just order it by the movie status name.
-
Then we'll also want to get our sinist.
-
So sinist equals awaits,
-
import our sinist controller there,
-
query, and let's order them by,
-
we'll just do their last name.
-
That should be all that we need to provide in for our form.
-
So we have our statuses and our sinists.
-
So let's go create our movies create page.
-
So let's scroll on down to where we have our admin movies directories,
-
right-click that movie directory,
-
new file, add in create.edge@layoutadmin,
-
and that layout, do an h1,
-
create a new movie,
-
add a form in, method of post,
-
and an action reaching for a route admin movies store method,
-
and that form out.
-
We're going to want to add in our CSRF field,
-
and let's start with a form,
-
input label will be title,
-
name will be title,
-
the type will be text, which is our default input type.
-
So we'll leave that out.
-
So that should be all that we need for our title input.
-
Can actually go ahead and just collapse that down to a single line there too.
-
So then we have our form.input,
-
the type for this one is going to be select,
-
label will be status,
-
and the name we'll do as movie status ID,
-
matching how we have it defined on the model.
-
We'll end our input and add in our option slot.
-
So do at each status in statuses,
-
go ahead and end our each,
-
add in an option value,
-
status ID, and then the status.name as the display value.
-
Next, we have our writer and director.
-
So we can go ahead and give this select for our status copy,
-
paste it in once,
-
switch status to writer,
-
switch the name to writer ID,
-
and rather than looping over our statuses,
-
we're going to be looping over our synists with a synist there.
-
Give that a copy because it's hard to type and paste that in for the ID,
-
and rather the name that should be named there.
-
Once we have that applied, we can give that a copy once more,
-
paste it in there, and switch writer to our director.
-
So we'll have a director ID,
-
and then the options should remain the same for that.
-
Then we have our summary and abstract.
-
So we can do @forminput type,
-
and I believe we added support for a text area.
-
If not, we'll add that in here momentarily,
-
but I believe we did.
-
We'll have our label of summary and name of summary, just like so.
-
Then we can give that one there a copy as well,
-
paste it in, and switch summary to our abstract.
-
Now, an abstract is something that you would probably want to
-
add a WYSIWYG into your application for,
-
what you see is what you get editor.
-
Those can take time to actually add into an application.
-
We're going to cover how you can go about that in a separate series later on,
-
but for now, we're just going to leave this here as a text area.
-
Then it looks like we have our release that as the last field that we'll need.
-
Let's go and scroll up and put that underneath the title.
-
So we can use the native browser input for that.
-
So we can do @forminput type,
-
and it looks like we have this as a date time,
-
but let's just worry about the date in terms of actually setting up a value.
-
So name, give that a name of released at.
-
Again, we're just naming all of these fields to
-
match how we have them defined in the model,
-
just to simplify taking our form data,
-
validating it, and passing it directly into our movie model as the property values.
-
We need a label on this one here as well.
-
So label and we'll do release date there.
-
Let's scroll on down to the end and give ourselves a submit button.
-
So @button, type, submit,
-
end our button, and create movie there as the action.
-
We do also have that poster URL.
-
Take care of that here in the next lesson.
-
Let's first just see what we get.
-
So let's jump into our create movie page.
-
Oops, forgot to break up the route.
-
Let's go break that up real quick.
-
Jump into our movies index page right there,
-
route, admin, movies, create.
-
There we go. So now we should be able to jump into our browser and hit create movie.
-
There we go. Could use some spacing,
-
but we do indeed get our form here.
-
We have our date input right here.
-
For browsers, you can still click on the little calendar icon
-
and get a nice little date selector right there.
-
So that's nice.
-
For our statuses, we have casting, post-production,
-
production, released, and writing.
-
For our writers and directors,
-
we have a list of all of our cinests, just like so.
-
So everything there seems to be working A-okay.
-
Let's go ahead and minimize that back away.
-
Scroll up to our form.
-
And to add some spacing in here,
-
I think what we'll do is we'll just do class, flex, flex, call, and gap of form.
-
So we'll just use flex gap there to add spacing
-
in between each of our little form groups there.
-
Okay, cool.
-
So next we need to do our validator
-
and then actually create our movie.
-
So we do already have a movie validator file.
-
We could reuse this here if we wanted to,
-
or we could create a brand new file
-
specifically for our admin movie section.
-
What would probably make the most sense
-
is to rename this validator file to movie filter validator,
-
since this is specifically for our movie filters.
-
So I think what we'll do is we'll right-click this file,
-
rename, and append in filter to the end of that file name.
-
And Visual Studio Code's gonna ask us
-
whether or not we want to update the existing imports
-
for this file to match what we've renamed this file to.
-
Go ahead and hit yes for that
-
so that we don't have to worry about it.
-
The only thing it doesn't do that I wish it would do
-
is automatically save for us.
-
So you can see movie service right up here,
-
just switch to needing to be saved.
-
So we can jump into here.
-
This may be the only file where we were using it
-
since we normalized everything into this service.
-
So we can go ahead and give that a save, close that back out,
-
which should now give us room to do command control P,
-
make validator, and we'll create a brand new movie validator.
-
So now we have a validator for our movie filters
-
and a validator specifically for our movie itself.
-
So let's export const movie store validator
-
equals vine compile, and we'll do vine object.
-
We're gonna have a title of type vine string,
-
and let's just roll through and put the types in first,
-
and then we'll add in additional checks.
-
So let's scroll on up to make sure we get everything here.
-
We'll leave slug out because that's gonna be auto-generated
-
by our model, have our summary type vine string,
-
our abstract as type vine string,
-
our writer ID as type vine number,
-
director ID of type vine number,
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!