Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

3.1 Building a Better List

I want to improve the user list so that an HTTP request isn't sent if the logged-in user tries to edit it themselves. We'll convert the view into a component in order to achieve that.

3.1 Building a Better List

In this and the next lesson, we are going to finally get away from forms, and instead we're going to turn our attention to this page. And the reason why is because whenever we click on our user, which we are logged in as admin. It's going to make a round trip and it's going to say that you cannot edit yourself. Now I want that check in place. Everything that we are doing, I want to leave the server application running as close to how it is as possible, because the server is our last line of defense. Anything on the client's can be gotten around. So if we end up having a savvy user who tries to get around the things in the client, well the server is still there to keep them from doing what we don't want them to do. What I want to do then is turn this table into a component so that we can keep track of the currently logged in user. And whenever they click on their user all we have to do is just display a message, you can't do it. That's going to eliminate that http request, which is really nice actually. So, let's get started. Let's start by go ahead and creating that component, just so that we can get that out of the way. So we want to go to resources > assets > js > components > admin. And inside of admin we want to create a new folder called users, and inside of users we will create a new file called UserListComponent.vue. Let's go ahead and type the template and the script so that we have that stuff there. But let's register this with our application. So let's go to app.js. Let's copy what we did for the pages-form, and then just change it to user-list. Of course we need to change the path for that so that it says users, and the, user-list. So as far as the view is concerned, let's go to views > admin > users and then index. That's were this table is, and we are pretty much going to take everything that we have here and put inside of our component. Now we are going to do that with our status message, but we're also going to leave this one here. Just so that if the server does need to send a message, I say send. If it needs to set a message, then it can at least still do that. But everything else is going to go away. And this is using pagination. Now we can't really see that here because we only have two users, and I think the page is set to 20. But that's something that we will probably need to address at some point as well. So let's just paste in that template, and let's get rid of everything except for the status area and for the links. And we can go ahead and use our component. So user-list, and really we need two pieces of information here. The first is going to be the currently logged in user, so let's call that current-user-id. And we will set that to the currently logged in user's id. So we will use Auth, get the user and the id. Now the second thing is the model, which is very much like what we have been doing. We're going to take the model that was passed to our Vue and we are going to json_encode it and pass that to the component as well. So that will take care of that. And then we just need to add those prompts to our component. So inside of our script let's go ahead and add our props. And the first will be model, the second will be currentUserId. So we have that done. Now let's just make this all nice and JavaScripty instead of PHP. This div element for the status. We're going to use v-if. And we're going to just check the status. Now this is going to be a property, but it's going to be kind of an internal property. We're going to refer to this as data. And I'll show you how we do that here in a few moments. But for now if we don't have a status then this isn't going to be shown, but if we do then it of course will be. So we have that, but we also need to wrap everything with an element. So we'll just use a div and do that there. Okay, so moving on, we go to after the head of the table. Now we do need a table body, that is for styling. So let's go ahead and add that. And then we will get rid of the blade for each, and we're going to add our own for each for view inside of the tr element. So we're going to use that v-for attribute, and for each user in model, but the model is actually a pagination object. That's what was passed to the view, so it's not just a list of users. However, it does have the list of users as the property of data. So for each user in model.data, we also need a key here, and we will just use the user.id, makes sense to do that. Now as far as the URL, we're going to have to do this inside of JavaScript. But we are losing access to the route function. Which was nice, but you know what? Our URL is very straightforward, so we don't really have to worry about that. Of course if we ever did change our URL scheme then we would have to come in here and make that change, but that's not going to be that big of a deal. And for right now let's just put link here for the placeholder. As far as the email, we just need to convert this from PHP to JavaScript which is just a couple of deletes and a dot. There we go. And for the roles whenever I did this I did it incorrectly, because I did not include the roles with the query before the data was sent to the view. So this of course is going to have to be done inside of JavaScript, but it's going to be very simple, and we will do that here in a few moments. So let's just put some placeholder there to signify that there are some roles and let's see if this works. Let's go to the browser. Let's refresh. And failed to execute set attribute on element, although if we keep scrolling up, property or method status is not defined. Well okay, so we're gonna talk about the data now. So far we have passed data to our component to be done so as Props. So you can think of those as properties, or you can also think of them as passing data to a constructor. But then there are other times that our component is going to have internal data that it needs to keep track of. And so we're going to have another item to our export here, but this is going to be a function that is going to return an object that has all of the data that we want to keep track of. And we can initialize our data, well, this needs to be status. We can initialize our status as null because we don't have anything to display as a status. So our data is a function that returns an object that has all of the properties or the values that we want to use within the component itself. This is going to cause that error to go away. So that whenever we refresh the page, now we just have this other one. And since it has a comma here, let's go to the view. And yes, I put a comma there separating the two attributes. Yeah, okay. So now let's refresh, and we see our table. So, that's great. We have a starting point at least. So let's go back and let's add the code for building the URL. And we're going to do that with a method. Because to me that makes sense to do. So we're going to have our methods. And the first method let's just call getUserUrl. We'll pass in the user, and we are simply going to return a hard-coded string of /admin/users/, but we're going to include the user.id. And I'm using the new string interpolation features so that we don't have to concatenate and things like that, and then edit. And that will be our URL, so that's pretty straightforward. So where it says link here, we will add an a element. We are going to bind the href so that we can say getUserUrl. We will pass in the user. Then let's also have the user's name here. We have the email address, now we want the user's name. So whenever we go to the browser and refresh, there we can see the users. The URLs look like that they are going to the correct place and they work, so that's nice. So now let's get the roles. Okay, so I mentioned that I initially did the roles incorrectly. So what we want to do is go to our controller. So that is inside of controllers > admin and then UsersController. And instead of saying just user paginate, we're going to do this. $users equals, and we will say User::with('roles'), and then we will paginate. That is the correct way to do it. And then we will simply pass our users to the view, which will then get passed to our component. Which will give us access to our roles. So inside of our component we can write another method that is going to getUserRoles. Once again, we will pass in our user. And it would be great if we had a method for plucking a single property out of an array of objects, but this is going to be simple enough anyway. We are going to say user.roles, and we are going to call the map method. Now for each item in this array, we simply want the name. Because what we end up with is the roles are of course objects, and one of the properties of this object is name. So we are simply going to return the name, and then now that we have just the roles we can join them into a string and each one will be separated by a comma. Or we could choose whatever character or string of characters that we wanted, but a comma is what we were doing before. So now where we say roles here, we can just output the getUserRoles. We will pass in user, and we will have our roles. So let's refresh the page. And now we have our roles. So the final thing to do is now add in the check. So that if we click on our user, then we just immediately say nope and then go on from there. So we have our current user ID. So whenever we click on this link we can add an onClick event, and we can write the code that's going to then check to see if the users match up. And if so then we will set the status. So we're going to say @click, kind of like what we did with our Submit button. And let's just call this checkUser for the lack of a better term. And we also need to know what the current user ID is for the user being displayed here. So let's create a data attribute, data–user-id. And we will set that to user.id. So now we just need this checkUser, which is going to be another method. So let's add that there. This is an event, so we're going to have our event object. And the first thing, let's get the event target. Because we are going to have to get the value of that id attribute. So we'll say target and then getAttribute. And that was called data-user-id I believe. I just typed it, I should remember what that is. Now, here's something that we need to be aware of. Whenever we have set current-user-id equals and then we have specified a value here, this is a string value. Now if we used the binding syntax, then it will take whatever type of data this is and use that type of data. So if this is a number, it's going to be a number. Now, I'm going to leave it as a string, because the value that we are getting from our custom attribute, from that data-user-id, is a string as well. So if we have two strings we could just compare the two strings, and then we will be happy. So we'll say if the id from the element is equal to this.currentUserId, well then it's the same ID so we want to prevent the link from taking the user to whatever was specified in the href. And we're going to say this.status. Now even though that this is part of the data we don't have to say this.data or anything like that. We just say this.status and You cannot edit yourself. So now with this in place we can go back, let's refresh the page. And whenever we click on ourself it won't make a request to the server, it's just an immediate boom. You cannot edit yourself. And that's what I wanted. We have eliminated that HTTP request. Now of course if we click on Joe, then everything is still going to work fine. But as long as we click on ourselves, we get immediate results. And we don't have to wait for a request and a response from the server. So in the next lesson, we are going to still look at our user list, but we're going to try to make the pagination work. I mean, it's going to work as it is right now, but wouldn't it be nice if we made it work without reloading the page? Well we can, and we will do that in the next lesson.

Back to the top