Vue Router Live Workshop
Laurie Barth: [00:00] William, are you still running into issues? Are you seeing stuff?
William: [00:06] Yeah, I'm still seeing stuff. Did that show up? All right. Hold on. The home page works.
Laurie: [00:24] You're doing the just one child path version, right?
William: [00:29] Mm-hmm.
Laurie: [00:30] Where are you trying to navigate to? What you want to navigate to, because you have that slash in front of guest, is to just go to /guest. Tyler found that, too. If you remove that slash, then you'd go to blog/1234/guest. You do need a slash between blog and your colon ID.
William: [01:03] I need a slash between blog and colon ID?
Laurie: [01:05] Yeah. What Tyler just posted there. Tyler, I'm hiring you as my teaching assistant.
William: [01:20] What'd you say the...
Laurie: [01:23] Sorry, one second. Lucas, your issue is that you want it to say "components" inside your children because you have your named path. See this, "components"? Once you have more than one, that's what you need. William, what'd you say?
William: [01:42] What'd you say the path should say?
Laurie: [01:45] If you have that version, you just need to do /guest, so localhost/guest. You won't need any of the blog stuff. If you want to change your path to just say guest without the slash, then it would be blog/1234, whatever you want to put there, /guest after that.
[02:10] The slash here on your path is overriding the path in your parent component and allowing you to navigate directly, which is great.
[02:21] Lucas, you got it working? The component versus components is a very tricky, little thing. It's awesome, but it'll catch you. Definitely caught me a few times. Oops. Making all the things. William, how we doing?
William: [02:46] It's working now.
Laurie: [02:47] Awesome. We're back in business. The next thing we're going to do is, if you noticed, we did a lot of different things where we would get empty screens, because we weren't matching paths exactly. We are going to make a wild card route, a catch all route, a default route, or whatever you want to call it. There's lots of different terms for it.
[03:13] We're going to do it a few different ways, because I want to show you not so great ways to do it and better ways to do it. The first thing we're going to do is import what I call page not found, component/pagenotfound.
[03:33] We are going to add a new route. We're going to add it all the way up here, which doesn't make sense, but it will in a second. We're going to set a path to /star. Our component is going to be page not found. As you can see, because this comes early, we tried to go to blog and we hit a route that we didn't know. That's fine.
[04:21] We tried to go to blog 1234 and we hit a route that we didn't know. /star is going to override every path that follows it. Do not do this. If you do, put it all the way at the bottom. There are better ways to do this. Know that this will work, and that the first time I built a router, I did it this way.
[04:51] It caused all sorts of problems, so don't do it. The other option, which is a cleaner way to do it is instead of the slash, you just have a star which will work the way we want it to. What it means is that we haven't actually defined a path for page not found, so we can't access it directly. We can only access it through random things that we shouldn't be accessing it through.
[05:22] A somewhat nicer way to do this is to make page not found our path and set it to an alias of asterisk.
[05:40] My typing is really good right now. What that's going to do is it's going to do both things at the same time. It allows us to go to any potential wild card path that we would want to go to and end up on this page, but it also gives us the ability to go directly to page not found, if we want to.
[06:05] We will see with programmatic routing, which we're going to cover at the end, why we want a page that we can access directly that's some kind of 404 or similar. Page not found is basically our 404, but I made it a little bit prettier. This, as you can tell, because it's an alias, it doesn't change the URL.
[06:30] We've shown up at page not found, but it still says theme. If you want to do a redirect, which is a similar concept, where we try and go to page not found and we end up somewhere else, there is a redirect keyword, and you can send yourself somewhere else, but then you'd have to know all of the potential places that you might go by accident, and then send you to page not found.
[06:59] Redirect is not a great use case for your 404. Redirect might be if you have some...People who make docs want to do that a lot, where they want to send people from the deprecated docs to the new docs, that kind of thing. Know that redirect is another keyword and another option.
[07:15] We're not going to go in depth on redirect today, because alias is our common 404 use case. Redirect tends to come up a little bit more in legacy applications, at least in my experience. I would like everyone to make a 404 page, page not found page, whatever you want to call it. Then I want you to try and go wherever you want to go.
[07:39] You're not going to get there. You're not going to get an empty screen or an empty page, because that's not a problem anymore, which is nice. You can do it either the alias way or the path asterisk way. Again, slash asterisk is not what we want to do. Give me a thumbs up or a note in the chat when you have that working.
[08:10] [pause]
Man: [08:21] What is so bad about the slash star?
Laurie: [08:25] There's a couple things that are bad about it. One, if anyone comes into your application and doesn't notice that you've done slash star, and puts a new route at the bottom, no one will ever be able to get there. If you have a route record that follows your slash star, then no one will be able to navigate to it, because slash star will override it.
[08:45] The other thing is that the star is meant to do anything on your route path. If you, within your own application, change your route path for vanity reasons, even if it's all in the same project code base, then it won't work as cleanly.
[09:04] There are also some other edge cases. It's not considered best practices, just because you can run into problems where you override yourself or you mess up how clean the URL appears in your quest for, "I want you to access everything."
[09:26] Mostly you can do what I did, which is accidentally put it earlier and override the rest of your routes, which is really the primary use case there. You can't do that with the direct asterisk. You can put that anywhere in here and it won't override, because slash is propended to every other route that we have here.
[09:59] [pause]
Laurie: [10:03] Path star. Anywhere in your paths? What do you mean anywhere in your path? Oh, you mean this one? Like if I did this and I made it star and I got rid of it, could I still get to blog/1234? Yes, I can.
[10:27] That's what I was just saying about the slash. The slash appears before all of our other routes, which means this doesn't actually match. It's when you add the slash to the star that all of a sudden it's a wild card for everything that follows here.
[10:44] This is built into Vue as a wild card that acts differently at the root of your URL. Using it as a wild card, as with slashes in other URLs, is not what you want to do.
[11:02] So star can come as a separate...Yes, Brian. If you wanted to, say, put star here, you would no longer be able to access your ID, but anything that came after blog would navigate you to this route.
[11:24] It is a wild card character. You can use it as such, but you shouldn't. Almost always, if you have reasons for navigating to different sub-routes, you want to know why and how you got there. There are better ways to do it even if you don't intend on using ID or whatever other parameter you have here.
[11:47] It's recommended because using a wild card is basically making a bunch of stuff invisible to you. It's almost like a silent error case, where you might not want to access it but you at least want the option to instead of just saying, "Send everyone here. We don't know how we got here" kind of situation.
[12:10] There's very few circumstances in which you would just want to send people somewhere for blanket reasons in sub-paths, but it is technically possible. Everyone good to go?
[12:26] The next thing I want you to know is that the route records themselves are actually pretty powerful. They allow you to add whatever you want. There is a meta object that is available. We're going to start with requiresAuth as the information we want to put in there.
[12:50] We're going to make it false for one of our routes. We're going to make it true for another. We're going to leave it off the other ones entirely. You'll see why in a little bit. It can be false or non-existent. Right now, it existing means nothing. All it means is that we can access it.
[13:12] Just like we did with the this.route.params, we're going to do this.route.meta and then whatever our key is, which in this case is requiresAuth. I'm going to send us to the Egghead page, where I just put that in. We see true.
[13:33] You can access this information if you want to send metadata information for anything. If you want to say "This is the colors I want this path to use," or some other random stuff that you would for some reason want to send through navigation, you can do that. We can access it just like we did for the other parameters.
[13:54] Again, once you introduce it in one place, it's not required everywhere. It's metadata. It can be Boolean. It can be strings. It can be numbers. It can be an object. As long as it's a valid variable, it could even be a function if you wanted it to be.
[14:13] You could pass a callback or something like that. We're going with the more building block-level use cases because it allows us to see the patterns. Then we can extend them in another places.
[14:28] Is meta a special word, or is it just...Meta is a special word. Meta is defined in Vue Router as where you put any additional information. It knows how to pass through navigation and be accessible in all of your different routes. Meta is not need me-defined. Meta is Vue-Router-defined.
[15:00] I know this because I made it metadata once and I couldn't access anything. See, all things Laurie learns by making mistakes. In this case -- I should have mentioned this -- I do want you to add exactly these use cases with the requiresAuth false and requiresAuth true because it's going to matter in just a little bit. Let me know when we're done with that.
[15:34] We're about to get to my favorite part. The best part of routing and Vue is coming next. Hang on to your hats, everybody. It's going to be a not bumpy ride, which is the best part. I was on a couple planes this week. They're like, "It's going to be a bumpy ride." I was like, "That's fun. Thanks for the warning." Everyone good?
William: [16:07] One question. Do I have to do an import for the meta? I don't know if I missed that or not.
Laurie: [16:11] Nope. No import necessary. You are just defining a key-value pair here. It's just a name and then whatever your value is. It's not a component or anything like that. It's just information to carry on the route itself.
William: [16:28] Thank you.
Laurie: [16:29] Yeah. We are going to talk about navigation guards. We are going to do a few different examples of one type of navigation guard. Then I'm going to give you a bit of a narrative spiel about other types of navigation guards.
[16:46] Navigation guards are a really, really, really big topic. It's one of those things where you can do this or this or this or this. We're not going to do all the examples because they are a little bit more involved.
[17:01] We are going to import our final amazing component, failedAuth. In reality failedAuth is essentially what your login page would be. It's where you want to send people when they failed auth.
[17:19] Components failedAuth. Whoops. That was fun. We've imported that. I want to give us another path that will send people to failedAuth. We're just going to make it failed. Then component is going to be failedAuth.
[17:46] This is similar to how we've done all of our other routes. I just wanted us to have this place to go because it's nice and scary and red. It'll tell us whether we were successful or not in what we're about to try and do.
[18:00] Navigation guards are there to determine whether the navigation that a user is attempting to do is valid. I don't mean "valid" as in they are going to a URL that exists. I mean, whether they specifically are allowed to go there.
[18:20] The most often use case that you can think of off the top of your head is trying to go to a page when you're unauthenticated. In most applications, there's a workflow. You have to click on a bunch of buttons.
[18:32] Theoretically, if a user knew that they wanted to go to Egghead and they weren't allowed to go there yet, but they tried to type it in the URL, are you blocking them or not? You could show them nothing, or you could just say, "No, I'm going to send you to a login page, or a failed off page."
[18:51] That's what we're going to build, because in Vue Router it is delightfully beautiful. OK, so the first thing I want us to make is a function that's going to decide whether or not we are authenticated. All that's going to be is cheating, because you'll find out in a second, but we can't hard code it directly in our nav guard.
[19:19] I'm just going to return false, for the moment. It's authenticated, we are not. Now, I have a vs code snippet that makes my life a little bit easier. But I'm going to walk us through what we're doing, and we can type this at the same time.
[19:49] We're taking our router, which means this entire set of logic needs to come after our router is initially defined. Keep that in mind if it tries to go up top it won't work, because it can't see router yet. There isn't function hoisting in this particular case.
[20:06] We're using the before each navigation guard. Think of this as a life-cycle hook that is outside of our component. What it's saying is, before any of the pages that I route to, I want you to check.
[20:24] There are three parameters that gets passed into the before each hook. Two, which is the place our user's trying to go, the path they're trying to go from, where they came from, and next. Next is a function. I'm going to talk about it more in detail in just a second.
[20:46] The first thing we want to do is add an if statement that's looking at the place our user wants to go to and matched. Matched is interesting because it is how we access the information on our route. This is how we're matching the metadata right now.
[21:13] Two matched. It's saying if some...We're basically saying if any of the routes or sub-routes...For example, if we had stuff inside here, we don't want you to be able to get to stuff that's a sub-route that requires authentication just because you went to the parent.
[21:30] If to.match.some, we're going to pass that record, and we're going to only return record.meta.requiresAuth. We're saying we're looking at things that require auth, which means anything that doesn't have the requiresAuth metadata is going to pass right through this and it means that requiresAuth false for our home page is also going to pass right through this.
[21:58] If you pass right through this, you hit the next function. The next function without anything inside of the function just says complete this hook. That's saying completing this hook in this case is going to send you where you want to go.
[22:18] If you put a path inside next, it will send you there. If you put a Boolean, like false, inside next, it'll send you to from. If you don't know where you're coming from and you want to go back to where you went from, you put false in here. It has different alternatives.
[22:41] The most important piece about next and what I actually had them add to the routing documents a couple of weeks ago -- yay, fun times -- next should only ever be called once in any given path pass through a navigation guard.
[23:02] Discrete logic, you can have next multiple times in here as long as you can't hit it more than once each time you go through this function. If you can, you're going to run into some weird edge cases and errors. You should only hit next in any of its versions.
[23:18] Whether it has nothing being passed into it, a Boolean being passed into it, or another path being passed into it, you should only hit it once when you go through this function.
[23:29] With all of that, we're going to insert logic. We know if we don't require auth, then we're just going to go next. We're going to say if it is authenticated, then you can go to next. We can go where we want to go. Otherwise, we're going to send you to failed.
[24:23] I'm going to go home. Nothing bad is going to happen. isAuthenticated is false. Oops. What did I do? Oh, I switched these.
William: [24:46] Do you have to call isAuthenticated?
Laurie: [24:52] You mean with a function?
William: [24:54] Yeah.
Laurie: [24:54] Like that? Like you should actually do things correctly? Yeah. You might want to do that. I was like, "Why isn't this working?" Hold on. If isAuthenticated...I'm realizing I have a mistake in my notes, which was unintentional. Egghead.
[25:15] OK, cool. If we're authenticated, then we can go to next. Otherwise, we have to go to failed. We're trying to go to Egghead right now. We can't do it because we're failing this check. If we set this to true and try and go to Egghead again, we can get there.
[25:39] Note that you have a bunch of if-else statements here because we're not allowing you to hit next more than once. Next is the last thing that happens, no matter which version of it it is. There's a bunch of different refactored ways of doing these functions. You can refactor it however way you want.
[26:02] I have a whole post on this, if you want to look at it, where there's a bunch of different versions of this, but they all have to be discrete logical paths. I'm going to give you a second to do this, but before you do, this is going to be my narrative spiel about navigation guards.
[26:24] This beforeEach is considered a global navigation guard. It is operating on the entire router. No matter where you try and go, it will always run. You have a similar hook called beforeEnter that can be a function you define directly in a specific route.
[26:52] This is a different type of navigation guard. This applies only to the route in which it's defined. Finally, inside your components, we could do beforeRouteLeave, which is a navigation guard that's inside a component and only applies to this component.
[27:25] The best way I can show this to you is this. There is a flow that tells you which one will run when. There are, I believe, three global navigation guards, three in-component navigation guards, and three in-route navigation guards.
[28:00] Because beforeRouteLeave, beforeEach, beforeRouteUpdate, and beforeEnter are all similar, there is an ordering. Having multiple, where one's in the component, one's on the route, and one's global, means that you need to know which one will fire first.
[28:19] You have all the potential use cases you should want, but for now we're going to make this one, which is just moving through an authentication case globally for every navigation we go into.
[28:35] Actually, this is...No. That's the same thing. Never mind. Ignore me. I thought there was a way to access the full...Oh yeah. Here it is. That's the bottom. That's where it has the full navigation flow. It's tethered to that point. I will keep this up so that people can look at it.
[29:13] I know this one will take a little bit longer. Just make note in the chat when you're done.
Man: [29:21] Besides forEach, which one do you find yourself using the most?
Laurie: [29:27] BeforeResolve. Because that's a really good place to check to make sure you have a current user so that you don't run into a bunch of gnarly situations where you have errors because you're missing a current user.
[29:46] There's also a way to do that in computed components too. Honestly, beforeEach is probably my most often used because the other stuff has a lot of redundancy. I will link to this as well. If you look at this post, which I will also put in the chat, you will see other people in the comments who do things differently. There is redundancy here. There are other ways to do it.
[30:21] I don't like doing beforeEnter directly in each of the components because I think it ends up being duplicate code. I think if you're going to do beforeEnter in most of your routes, you should just do beforeEach, but that is a personal opinion. Not everyone agrees. It depends on what your constraints are.
[30:43] If you have major resource constraints and you don't want this to get called because only three or four of your routes actually care and most of the other ones don't ever need to check, then that's a compelling case in which to you something else. Except for the fact that you're only checking if it even has that metadata field, which is a pretty non-resource intensive check.
[31:08] We're not doing anything else, if it's authenticated, it's obviously going to be more complicated in a real world scenario.
[31:15] We are not checking that, in less we require auth. Right now, we only have one route that does. There are trade offs and it's about what resources you want to use. How often do you want to call this logic and to a certain extent which life cycle hook you feel more comfortable with. Did that answer the question?
Man: [31:42] Yeah, definitely. Is there a pattern matching solution? Can you have different meta attributes that you have to find and you want to check, like three of them?
Laurie: [31:59] Oh yeah, absolutely. If you had a bunch of different meta attributes so you could do ands or ors, or you could say, "I need you to require auth." Then if you require auth, you could branch off and say, "OK if this other meta attribute does this, go this way. If this different meta attribute does this, go this way. Everything else fall to next."
[32:26] That kind of thinking. You can embed this as deep as you want to go if you have really particular situations. That's what's so nice about this and why it's so extensible. All it's doing is saying, "I am looking for a self-defined key that tells me whether I care." Then all the rest of the logic is defined by you.
[32:48] This is saying, "I want you to run this," each time we try and navigate elsewhere. This is why I like the router, because it's opinionated and it works well while reusing the same patterns for embedded use cases, non-embedded use cases, etc. How are people doing with the nav guard? Still taking people. OK, awesome Lucas. Cool. Chris, Brian, you good?
[33:46] Good here, OK, awesome, yay. That was supposed to be a hard one so I'm glad everybody got that. Now we are actually going to leave our happy, main JS file. We'll do a couple of other things here. Now we are going to talk about routing inside our components themselves. As you can imagine it's nice to be able to type things into the URL.
[34:14] We also want to be able to navigate from page to page. I love you because they've made this nice and straight forward for us. The first option is that we define ourselves a button and we say the on. This is view stuff, click and we're going to use a function that says go to Egghead. We'll give it words so we can actually see it.
[34:53] Now we're going to define methods. We're going to make our two Egghead method. Keep in mind, this is one of those where we have a lot of different options. Don't think that you have to do this particular one. This start router, we're accessing our entire router and we're going to send ourselves to /egghead. Let's go home, go elsewhere, egghead.
[35:28] This is programmatically in JavaScript sending us somewhere else. You're pushing a new path onto the router. You'll recognize that this is a simple path. We have paths that are less simple, namely blog. Let's send ourselves to blog this time, and send ourselves with an ID. Now, I'm just going to pass ourselves an ID right here. We're going to go to Home. Oh, oops. Make sure you use back ticks here. If you use quotes it won't work, because we're accessing a variable.
[36:18] Oops, what did I do? ID, oh. Here we go. Sorry, you've got to pass an ID. Go elsewhere. Now, we're going to 1234. This is allowing us to put it directly in our path.
[36:40] Now, an alternative is that path is not the only way we can define our components. We can also give them a name. In this case, I'm going to call it "blog." When we do that, we go back to Home. We find that we want to push an object and we start using keys.
[37:15] Our name is blog. Our params -- sounds familiar -- is a new object where ID is ID, because we're passing an ID here. Now we're going to go back Home, going to go elsewhere. This still works. Cool.
[37:43] That is all of the ways to access it via JavaScript. Now, in a lot of cases, if you're going to the route you've just defined, you actually don't want to have to do any of this. There is an API in Vue Router called "router link."
[38:09] Router link allows us to set the path that we want to go to. I don't want to mess it up. Oh, I always do this. This is kind of weird. You have quotes to define it. Then you have quotes to say that it's a string. I'm going to show you something funny, because I messed this up the other week.
[38:44] Nothing appears, because the router link expands around whatever you put inside of it, and we have nothing inside of it. It's there, it's just invisible. Now it'll show up, and it's a link. It's sending us to where held videos go.
[39:13] Because this is provided to us by view router, there's actually a lot of options that we have. I'm not going to go through all of them. There's things like active class for CSS and some other stuff. But one that's really nice is, you have a tag that you can call "button." All of a sudden, this appears like a button.
[39:36] There's a lot of styling and display things, and accessibility functionality that's available here. The format that I used before for going to blog and setting params -- in this case I'm just going to hard code it, because we're not passing anything in -- is the same.
[40:11] What we did programmatically down here, we would do here if we wanted to follow params on use name, etc. Oops, blog. Oh, sorry. Me and my quotes today are a little off. Save things. There we go. There we go. It's the same format.
[40:43] I went through like six different ways to do this. There's one thing I want to let you know up top. Path and params cannot be used together. You're either doing path with those back ticks we talked about and passing it directly in, or you're using name with params, so this is the key value pair.
[41:08] There's a bunch of different API things that we can do with router link tag. Button is only one of them. But you have four or five options how to do this. I would like you to go to your Home page and figure out a way to get to another page in your application, however which way you want to, and go.
Member comments are a way for members to communicate, interact, and ask questions about a lesson.
The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io
Be on-Topic
Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.
Avoid meta-discussion
Code Problems?
Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context
Details and Context
Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!