Serhii Kulykov

Creating a simple app using Vaadin Router

This guide describes how to create a simple app using Vaadin Router.

We are not assuming any tools, so the app includes the compiled UMD bundle to run in any browser.

1. Setup the Project

First let’s create an index.html file, add some markup and include scripts.

index.html
<base href="/">

<!-- Include the Vaadin.Router library.
     Browsers automatically pick the best of the two options below. -->
<script nomodule src="https://unpkg.com/@vaadin/router/dist/vaadin-router.umd.js"></script>
<script type="module" src="https://unpkg.com/@vaadin/router"></script>

<nav>
  <!-- By default Vaadin.Router intercepts all anchor clicks and
       uses them for in-app navigation -->
  <a href="/">Home</a>
  <a href="/about">About</a>
</nav>

<main id="outlet">
  <!-- Here Vaadin.Router inserts the current page content -->
</main>

<script src="app.js"></script>
app.js
const {Router} = window.Vaadin;

// setup a Router instance
const outlet = document.getElementById('outlet');
const router = new Router(outlet);

Now we loaded the Router and created the router instance. Next we will use it to configure the routes for the app.

2. Basic Route Config

Time to create a config for the first route. The route config maps path to a Web Component. Vaadin.Router goes through the routes until it finds the first match, creates an instance of the route component, and inserts it into the router outlet (replacing any pre-existing outlet content).

The router does not enforce you to use a specific format to define the components, you can write vanilla Custom Elements, or use any library helping to build them, e. g. Polymer, Angular, Vue, SkateJS, Aurelia etc.

Let’s create a vanilla Web Component for the home view. Note the dash in tag name, it is required by spec:

// Extend an HTMLElement or another custom element
class HomeView extends HTMLElement {
	// This is called when our element is attached to the DOM
	connectedCallback() {
		this.innerHTML = `<h1>Welcome home!</h1>`;
	}
}
// Tell the browser to associate the '<home-view>' tag with HomeView class
customElements.define('home-view', HomeView);

And then, tell the router to render <home-view> component for the root URL using setRoutes method:

router.setRoutes([
  {path: '/', component: 'home-view'},
]);

That’s it! Now, we can start a development server and open the page in the browser. Note that Web Components work natively in latest Chrome and Safari.

For other browsers, you will need to install the polyfill and add the script to the page. The polyfill uses feature detection and only loads the needed scripts to make the missing features work.

3. Fallback Route

So far we only have one route defined. But what if we click <a> link heading to a different URL? In that case, the outlet content for previous view will be removed, but no new view rendered. Instead you will see an error in the console saying that page not found.

Let’s add the fallback route to make this scenario more user friendly. In order to do this, we need to add a route with (.*) path at the end of the routes list, and to define another component to show.

The component can look like this. Note we must start tag name with the letter, so <404-view> would not work:

class NotFoundView extends HTMLElement {
	// We are using `route` property, which is defined by the router
	connectedCallback() {
		this.innerHTML = `
			<h1>Page not found</h1>
			The pathname was: ${this.location.pathname}
		`;
	}
}
customElements.define('not-found-view', NotFoundView);

The updated config should now include two route objects:

router.setRoutes([
  {path: '/', component: 'home-view'},
  {path: '(.*)', component: 'not-found-view'}
]);

Note that you can also use getRoutes method and append the route like this:

router.setRoutes([
  ...router.getRoutes(),
  {path: '(.*)', component: 'not-found-view'}
]);

4. Route Parameters

Let’s add one more route to the app. This time we will update the router config to render the <user-profile-view> component for any URL that starts with /user/, and has a user id as a parameter (e.g. /users/1). To define route parameters, we use the express-like syntax:

router.setRoutes([
  {path: '/user/:id', component: 'user-profile-view'}
]);

There is a named id parameter in the URL. When the router renders the component, it adds the values for all of the route params to the params property of the location object, so we can access them the same way, as we did for the pathname in the above example. This property is configured before component gets added to the DOM, so you can always be sure it is available by the time connectedCallback gets invoked.

5. Unconditional Redirects

Sometimes we need to unconditionally redirect the user, so that when a page changes its URL, the old URL would still work. Vaadin Router supports this via redirect property on the route object. The valid values are path string in the same format, as used for the path property:

router.setRoutes([
  {path: '/team', redirect: '/company/team'}
]);

The redirected URL is not stored as the window.history entry and cannot be reached by pressing "Back" browser button. Unconditional redirects work for routes both with and without parameters.

6. Ambiguous Matches

URL matching rules can be ambiguous, so that several routes would match the same URL. In that case, the order in which the rules are defined, from top to bottom, determines the matching route. The first matching route will be loaded.

Always place any exactly matching route objects at the top of the list, and the wildcard route, if any, should come after them. Otherwise, in the example below the <x-user-profile> component will be rendered for the /users URL:

router.setRoutes([
  {path: '/users', component: 'x-user-list'},
  {path: '/:user', component: 'x-user-profile'}
]);

7. Server configuration

Finally, we need a simple web server to run our application. Vaadin Router is designed for Single Page Applications (SPA) which typically only utilise one index.html file and respond with it to any URL requested by the web browsers. Navigation in the application is then handled by the Router itself after the application loads in the web browser. The URL in the browser is updated without causing any additional network requests, with the help of the HTML5 History API.

Assuming that Node.js is installed, we can start a simple development web server using the serve npm packge:

$ npx serve --single

The general idea of SPA configuration—rewriting all the GET requests which accept text/html, except direct file requests, to the single index.html file—is also doable with other servers like nginx. Note that Vaadin framework supports this out of the box, without requiring any extra configuration.

Vaadin is an open-source framework offering the fastest way to build web apps on Java backends
GET STARTED

Comments (6)

David Chisholm
2 years ago Feb 16, 2020 8:32pm
David Chisholm
2 years ago Feb 16, 2020 8:38pm
David Chisholm
2 years ago Feb 20, 2020 2:31pm
Marcus Hellberg
3 years ago Jan 15, 2019 3:03pm