🕰️ Chapters
- Defining Our Profile Edit Page
- Adding Textarea Support To Our Form Input Component
- Defining Our Profile Edit Form Fields
- Profiles Update PUT Route Definition
- Defining Our Profiles Update Validator
- Accessing HttpContext Within Our Service Using Dependency Injection
- Injecting Our Service Into Our Controller Using Dependency Injection
- Updating The User's Profile
- Spoofing PUT Request
- Testing Our Profile Update
Transcript
-
[MUSIC] So for our profiles edit page, let's go and use our login or
-
register page as our starting point. As this already has our layout and it has some form of a form inside of it. So we'll go ahead and paste that inside of here.
-
And first thing we'll want to update is the h1. So we'll do something like edit your profile. We don't have an action for this quite yet, so I'm gonna replace that with a hash.
-
And we're not gonna have an invalid credentials error. And each error that we do have should go strictly onto our form input. So we should be able to get rid of this error altogether.
-
And our first input field is going to be for our user's name. And our users use full name for that. So for the label, we'll put full name. And for name, we'll put full name.
-
And the type will just be string, so we can use the default there by getting rid of the type altogether. Then we're gonna want a field for our biography. And for that, we're gonna want to use a text area.
-
So let's jump into our components, form, input. We can add something relatively similar to what we're doing for our select, specifically for a text area.
-
So we can give this a copy, paste it just before our else. Switch the if to an else if, change this type to text area. And we can get rid of that else.
-
And then we'll want to add in our text area with a name of the field's name or an empty string. And then we'll pop the value directly inside or
-
default it to an empty string as well. Keeping no spaces in between the start and end tag of our text area so that no spaces get injected with our value.
-
So let's give that a save, jump back into our edit. And now we can do biography or about you or something like that. I can't quite recall what we actually named this, so let's scroll up to our profiles.
-
Looks like it's description, so let's hide pgAdmin back away. Call this field description and set our type to that new text area that we've now supported inside of our form input.
-
We also need to add the default values into those inputs. Before we do that, though, we will not need our remember me, so we can get rid of that. And let's switch our button text to update profile.
-
Okay, so let's scroll back up and let's take care of the default values. So for our full name, we'll put value and this comes directly off of our auth user, it's not on our profile.
-
So we'll just wanna do auth.user.fullname there. However, our biography does come off of our profile. So we can do value and we've added profile directly onto our state.
-
So we just do profile.description. Let's give that a save and let's go see what we get. So let's jump back into our browser. That's from our last lesson whenever we were adding in that link before it actually existed.
-
Let's give this a refresh. There we go. Now we can click on Edit Profile and we see Edit Your Profile with our full name. Our biography is there, it just doesn't have a border on it.
-
So maybe we'll jump into our text editor. That should be within our CSS, app.css. And right down here where we have our input and select styles,
-
we'll just add text area to those elements there as well. Add that back away, jump back into our browser. And there we go, that looks better. So now we need to add in the action for this form.
-
So let's go do that next. First, let's jump into our routes, create a new route, router. And we'll call this one put as we're strictly just updating information. And we'll do /profiles.
-
Again, since this route is not user facing, we'll keep with the resourceful naming and add the S to the end there.
-
Then we'll do profiles controller update is profiles.update. And we're going to want to restrict this to authenticated users as well. So we can give that a copy and paste it here,
-
or we can create a group and wrap those in a group. Whenever we go to show a profile though, we will not want that to be auth restricted. So I think I'll leave this middleware as is for right now. Give that a save.
-
And now let's jump into our profiles controller where we need to add our update method. We'll use our request, response, and auth HTTP context.
-
All right, we're going to want a validator. So let's hit command or control shift P to open up our command palette. And it looks like make validator was the last one that I used, but if it isn't for you,
-
should be able to do AdonisJS make validator. Since we have the AdonisJS extension added into Visual Studio code, run that, it'll ask for a name.
-
We'll just call this our profile validator. And there we go. Export const profile update validator equals vine.compile, vine.object.
-
We're going to have a full name of vine string. Now we're going to want this to also match exactly what we have inside of our auth validator right here. So we could copy this,
-
but then we'd have to make sure that they always stay in sync if they were to ever change. So what we might do instead is take this validation rule, export const full name rule equals,
-
and just apply that rule directly to this variable and export it so that we can access it within our other validators. And then just apply our full name rule to the full name field here.
-
Give that a save, jump back into our profile validator and switch this to now use our full name rule as well and import that from our auth file.
-
You could also create a new folder or file called shared rules and place all your shareable rules within there. This might be the only shared rule that we have. So we'll leave this as is for us.
-
And then we have our description field. This one will be a vine.string and it'll be optional. Okay, that should do it. Let's jump back into our profiles controller.
-
Const data equals await request validate using our profile update validator and import that from our validator file.
-
Now the full name field goes directly on the user and the description goes on the actual profile. So since we need those to go in two different places, let's extract the full name and the description
-
just directly out of the validated fields. We're then going to want to grab our user's profile, which would look exactly the same as this line right up here. So rather than copying and pasting that,
-
let's show how we can create a service for that. So right click our services, new file, call this profile service.ts, export default class profile service.
-
And we can actually make our HTTP context directly accessible within an instance of our profile service class by injecting it in using dependency injection.
-
For that, what we'll want to do is decorate this class with @inject from the AdonisJS core package. Looks just like so. Add a constructor onto the class.
-
It is a protected property and call this variable ctx for our HTTP context and type hint it as HTTP context.
-
Now, whenever we instantiate a new instance of our profile service, we're going to have the HTTP context directly accessible within this class, thanks to this inject decorator.
-
AdonisJS will spy that we want to use the HTTP context and directly provide it on the class instance, meaning that we can now do async.
-
We'll create a method to get the authenticated user's profile. Since this is our profile service, we can just call this find.
-
We can now do return this.ctx.auth.user, or we could add a getter, so get user,
-
and return this ctx.auth.user to simplify our call there a little bit to just this.user.
-
And then we'll just want to replicate our related profile query first or fail call. And now, since we're using dependency injection
-
to inject our HTTP context directly into this class instance, we no longer need to provide user information into the find method, but we can instead directly access it
-
off of the instance using the HTTP context. Now, adding it this way does hinder the places where we can actually make use of the profile service,
-
since it will now require an HTTP context. So if you were to need this service in something like web sockets, event handlers, model hooks, and the like,
-
you will not or may not have an HTTP context in those environments, meaning that with this approach, you would not be able to use your profile service. If your application just strictly works with HTTP requests,
-
that's not something that you need to worry about, but do keep that in mind. Okay, so we can follow the exact same approach that we did actually with this HTTP context to inject this profile service
-
into our profiles controller. So we'll add the inject decorator from AdonisJS Core onto our profiles controller, add a constructor for protected,
-
call this our profile service, and type in it as our profile service. You can also use this inject decorator at a method level as well.
-
So if you just needed it within edit or update here, you could add inject onto this particular method, and the injected property will come through as the second parameter.
-
So it would be something like profile service here, profile service, and add inject there. We need it in both of ours, so we'll put it at our controller class level.
-
And we can now replace this call with this profile service dot find. And we can now do the exact same thing down here as well.
-
So const profile equals wait this profile service dot find. And we've now removed the need for auth from our HTTP context
-
inside of our controller handler. We can go ahead and give this controller here a save, jump back into our browser, and give this page a refresh just to verify that everything here is actually working.
-
And it looks like everything worked a-okay. Awesome. So now that we have our profile information in our update call, we can either do profile dot description equals description,
-
and then await profile dot save to persist that change to the database. Or we can do profile dot merge, which accepts in an object
-
of any properties that we want to update on the profile itself. And in our case, that would just be our description. It will leave any properties that we do not provide within this object untouched,
-
and only update those that we actually provide. And furthermore, the merge call is actually chainable, so we can chain directly off of it our save call and just await this chain.
-
Then we also need to update our user's profile. And for that, we do need to pull auth back into this method. So we'll want to await auth user exclamation point to assert it.
-
And we could do the exact same thing here. So we can merge in the full name and save that change. Once we've saved those changes, we can return, response, redirect, right on back. Give that a save.
-
Let's jump back into our profile edit page and update our action. So let's see. This is route profiles update, but we also need to spoof it.
-
So we'll do query string underscore method put to spoof this method as a put request. So with that saved, we should now be able to jump back into our browser.
-
Let's do John Doe edit. And this is a little about John Doe. Let's try to update our profile. Okay. And it seems like everything worked.
-
And we can actually verify that because now our logout says John Doe edit rather than just John Doe. We can do a hard refresh and everything here is still populated.
Using Dependency Injection to Update A User's Profile
We'll learn how to allow users to edit their profiles. We'll also cover how we can inject the HttpContext into a service instance using Dependency Injection (DI).

- Created by
- @tomgobich
- Published
Join the Discussion 0 comments
Be the first to comment!