top of page

#15 Learning Vue Forms & Router

  • Aaron
  • Dec 6, 2020
  • 5 min read

Updated: Dec 10, 2020

The Vue learning journey continues! Here are some learning notes about Forms & Router. Routing is something essential to a SPA, and forms (with its validation) are very often needed.


Forms in Vue.js

Summary

  • How to use v-model to get user input and how to manipulate that user input (e.g. to reset it)

  • First look at validating user input.

  • How to show an error message before form submit

  • Look at different inputs, different ways of using v-model (v-model.trim v-model.number)

  • Using v-model with selects, checkboxes (groups & single), radio buttons

  • How to build your own control on which you can use v-model because of a special prop and special event, which v-model uses under the hood (if you use it on a custom component)


to force a number = v-model.number

to not update with every keystroke = v-model.lazy


When using v-model on checkboxes

Don’t forget to add value=”valueOfCheckbox” or else they will all get selected and deselected. Add pass the original value in your data() as an [] empty array.


Basic Validation

  • @blur=”” event listener (when input element loses focus)

  • in your data() {userNameValidity: “pending”} // change to “valid”/”invalid” in a method

  • then show/hide with v-if and style with classes :class={: invalid: userNameValidity === “invalid”)}

  • v-model = shorthand for @input=”” :value=””

v-model will automatically set a modelValue prop on your own custom components. (Using v-model on a custom component is like manually binding the :model-value="" prop - & listening to the @update:modelValue custom event)

There is also a special event emitted, the ["update:ModelValue"]



Routing

There was quite a lot of learning material I had to go through...

Summary

  • How to set up routing

  • Register routes (& routes config options: redirects, paths, names, metadata, multiple components that should be loaded, nested routes with children)

  • control the browser’s URL (incl shareable ones)

  • How to work with dynamic path segments (:id), to use route parameters which we can extract in the loaded components, and how we can pass those route parameters as props into the to-be-loaded components.

  • Navigation guards

  • Controlling the scroll behavior

  • Navigate with <router-link> or programmatically (with $router.push())

  • Describe the location we want to go to (by string path, or an object using the name, adding params and possibly adding a query parameter)


Install Vue router (for Vue 3)

  • yarn add vue-router@next

  • import {createRouter} from vue-router


Basic usage

const router = createRouter({
 history: createWebHistory(),
 routes: [],
});

Pass path in routes

routes: [{ path: “/path” , component }]

Use router in your app

app.use(router)

We also need to let the router know where these components should be rendered. In your <template>:

<router-view> 

Router-link

  • goodbye buttons/links => welcome <router-link to=””> a special anchor tag-like tag which will actually not load a different page and reload the entire app (which would make you lose your current state), but loads the appropriate component and updates the URL

  • router will automatically add router-link-active class on the active link

  • Router gives you two classes: router-link-active & router-link-exact-active. router-link-active would also be active on /activepath/id whereas router-link-exact-active would only be applied to the navigation item if it's fully matched by the current path. router-link-active will be applied to any navigation item which contains a part of the currently active route.

  • (you can also change these default classes if you want, in your router options: linkActiveClass: “className”)

Trigger navigation programmatically

  • Trigger navigation from inside js code: this.$router

  • for navigating programmatically: use this.$router.push(); to push a new route onto the routing history. To add a new route to the routing memory the browser keeps.

  • You can also emulate the browser's back/forward buttons with this.$router.back() or this.$router.forward()

Dynamic routes (Dynamic paths & segments)

  • Dynamic routes need a route parameter. Use path: "/pathName/:yourParameter", component

  • Load dynamic route data in the created() lifecycle hook (created() will be called when the component is created before it’s shown on the screen, but once all the data is available)

  • $router gives us access to the overall router

  • $route gives us access to various pieces of info (like the path that loaded the page, or the params with the path /: )

  • $this.route.params.yourParam (e.g. "domain/user/:yourParam")

  • you can v-bind to => :to=” ’path/‘ + id ” so you pass your router-link’s dynamically

  • You can also use computed: so you have less js logic in your <template>

Potential problems

  • If there is on the page that was loaded for a given parameter another router-link for the same page with a different parameter, the URL will update but the content won’t change. Because Vue router does not destroy and rebuild the components that were loaded when you navigate around, Vue caches it. Hence if you are on the page, which you want to load again, but with different data, different parameters, by default, the Vue router will do nothing. Use $route (that always holds the latest information about the loaded route, and will update when the URL changes) in a watcher to check for value changes.

watch: {
 $route(newRoute) {
 this.yourMethodOnLoad(newRoute);
 }

Now it's only loadable through routing though. Because in the code we rely on $route.


Passing Params with props

Use a prop instead of $route

watch: {
    passedProp(newRoute) {
    this.yourMethodOnLoad(newRoute);
    }
}

router by default doesn't add any props: add props option to your router config

routes: [{ path: “/path” , component: yourComponent, props:true }]

Redirecting & catch-all routes

next to a default "/" route, you can also redirect with the redirect:"/path" option

or use an alias: alias: "/" (but then the URL won't change like with a redirect)

add a notFound route: (any other URL will go activate this) path "/:notFound(.*) (.* is a regular expression that means any character combination) place it as your last route, so you don't overwrite your valid routes.


Using nested routes

add nested routes by going to the route where you want to nest routes inside and add the children option on the route config. (Children takes an array of routes)

Nested routes can be a really useful feature for building complex user interfaces, where you want to load different parts, maybe nested in different components. based on different URLs en paths.


Named routes & location Objects

Routing on a bigger application where you have lots of routes, some routes deeply nested in other routes (who might also be nested) makes constructing links (where you always have to add the full path) quite a hassle.

Thankfully Vue has two very useful features

  • returning a path object when to is v-binded (:to)

  • named routes (we can assign a name to every route which we have, by adding a name property to the route config)

Query Parameters

A queryParameter = something you see in some URLs after the ? (e.g. Like search=item)

It's basically an optional route parameter that is not needed to find and load a component but may be used to pass extra info into that component.

Add to your Vue component with query:{ key: "value"} get access to it with this.$route.query (Note: query parameters are not provided as props, because they are optional)


Rendering multiple routes with named router views

component => components: { default: Component, routeViewName: Component}


Controlling scroll behavior

If you want to scroll up automatically (when new content is loaded for example)

scrollBehavior() is a method that will be called by the Vue router whenever your page changes.

scrollBehavior will automatically receive 3 arguments (to, from, savedPosition)

savedPosition will return the previous scroll position (accessible if the browser uses back)


Navigation guards

router.beforeEach() is a built-in method that wants a function as an argument.

that function will be called by the Vue router whenever we navigate from page to page. Before each navigation action, this function will be called. It will receive 3 args (to, from, next) next is a function we have to call to either confirm or cancel this navigationAction. (E.g. great for authentication and not allowing non-registered users to access a page)


More about next()


Diving deeper into navigation guards

Order: 1. Global, 2. Route config, 3. Component level


You can also put navigation guards on single routes instead of the entire app, use beforeEnter(to, from, next) in the route config (or beforeRouteEnter() method hook inside a component)

2 other guards (before entering a route):

  • component level: beforeRouteUpdate() guard, which you call directly inside of a component that is reused. Vue will call this method whenever this component is about to be reused with new data because the route changed.

  • router level: afterEach() guard also gets the to and from argument, but not next() because afterEach() will only run once a navigation has been confirmed. (could be useful for analytics)

One other guard for leaving a route: Put protection guard so the user can’t leave the page:

  • beforeRouteLeave(to, from, next) guard:

    • router will call this first, before calling all the beforeEach() and beforeEnter() (guards



Happy routing!

Comments


  • iconmonstr-github-1-240

©2020

bottom of page