diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..654981cb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{java,xml}] +indent_size = 4 + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.eslintrc.json b/.eslintrc.json index 11926505..f20f7bdc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,9 +2,9 @@ "extends": [ "vaadin/typescript-requiring-type-checking", "vaadin/imports-typescript", + "vaadin/lit", "vaadin/prettier", - "vaadin/testing", - "plugin:oxlint/recommended" + "vaadin/testing" ], "parserOptions": { "project": "./tsconfig.json" diff --git a/README.md b/README.md index 59d0d1db..d90ab61f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ # Vaadin Router -[API documentation](https://vaadin.github.io/router/) +[Live demo](https://vaadin.github.io/router/index.html) +| [API documentation](https://vaadin.github.io/router/API/index.html) Vaadin Router is a small and powerful client-side router JS library. It uses the widely adopted express.js syntax for routes (`/users/:id`) to map URLs to Web Component views. All features one might expect from a modern router are supported: async route resolution, animated transitions, navigation guards, redirects, and more. It is framework-agnostic and works equally well with all Web Components regardless of how they are created (Polymer / SkateJS / Stencil / Angular / Vue / etc). @@ -52,24 +53,19 @@ Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https ## Running demos and tests in the browser -1. Fork the `vaadin-router` repository and clone it locally. +1. Fork the `vaadin/router` GitHub repository and clone it locally. 1. Make sure you have [npm](https://www.npmjs.com/) installed. -1. When in the `vaadin-router` directory, run `npm install` and then `npm run install:dependencies` to install dependencies. +1. In the router directory, run `npm install` to install dependencies. -1. Run `npm start`, and open [http://127.0.0.1:8000/components/vaadin-router](http://127.0.0.1:8000/components/vaadin-router) in your browser to see the component API documentation. - -1. You can also open demo or in-browser tests by adding **demo** or **test** to the URL, for example: - - - [http://127.0.0.1:8000/components/vaadin-router/demo](http://127.0.0.1:8000/components/vaadin-router/demo) - - Public API tests: [http://127.0.0.1:8000/components/vaadin-router/test](http://127.0.0.1:8000/components/vaadin-router/test) - - Unit tests: [http://127.0.0.1:8000/components/vaadin-router/test/index.html](http://127.0.0.1:8000/components/vaadin-router/test/index.html) +1. Run `npm run build` to build the library. +1. Run `npm start`, and open [http://localhost:4173](http://127.0.0.1:8000/components/vaadin-router) in your browser to see the component live demos and API documentation. ## Running tests from the command line -1. When in the `vaadin-router` directory, run `npm test` +1. In the router directory, run `npm test` ## Following the coding style diff --git a/demo/.eslintrc.json b/demo/.eslintrc.json index a616cff3..024aab45 100644 --- a/demo/.eslintrc.json +++ b/demo/.eslintrc.json @@ -1,15 +1,10 @@ { - "rules": { - }, - "globals": { - "ElementDemo": false, - "DemoReadyEventEmitter": false, - "Router": false + "extends": ["../.eslintrc.json"], + "root": true, + "parserOptions": { + "project": "./tsconfig.json" }, - "overrides": [{ - "files": ["vaadin-router-code-splitting-demos.html"], - "parserOptions": { - "ecmaVersion": 2017 - } - }] + "rules": { + "@typescript-eslint/unbound-method": "off" + } } diff --git a/demo/@debug/index.html b/demo/@debug/index.html new file mode 100644 index 00000000..e9bf1a5a --- /dev/null +++ b/demo/@debug/index.html @@ -0,0 +1,12 @@ + + +
+${full}`
+ : map(snippets, (snippet) => html`${snippet}`)}
+ View not found
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'x-not-found-view': NotFoundView; + } +} diff --git a/demo/@helpers/x-profile-view.ts b/demo/@helpers/x-profile-view.ts new file mode 100644 index 00000000..72495c9c --- /dev/null +++ b/demo/@helpers/x-profile-view.ts @@ -0,0 +1,21 @@ +import { LitElement, html, type TemplateResult } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import css from './common.css?ctr'; +import type { RouterLocation } from '@vaadin/router'; + +declare global { + interface HTMLElementTagNameMap { + 'x-profile-view': ProfileView; + } +} + +@customElement('x-profile-view') +export default class ProfileView extends LitElement { + static override styles = [css]; + @property({ type: Object }) accessor location: RouterLocation | undefined; + + override render(): TemplateResult { + return html`User ID: ${this.location?.params.id ?? 'unknown'}/user or /users: ${this.location?.params[0] ?? 'unknown'}`;
+ }
+}
diff --git a/demo/@helpers/x-user-list.ts b/demo/@helpers/x-user-list.ts
new file mode 100644
index 00000000..0de63477
--- /dev/null
+++ b/demo/@helpers/x-user-list.ts
@@ -0,0 +1,22 @@
+import { LitElement, html, type TemplateResult } from 'lit';
+import { customElement } from 'lit/decorators.js';
+import css from './common.css?ctr';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'x-user-list': UserList;
+ }
+}
+
+@customElement('x-user-list')
+export default class UserList extends LitElement {
+ static override styles = css;
+ override render(): TemplateResult {
+ return html`You've come to ${this.location?.pathname}, but alas, there is nothing there.
ID: ${this.location?.params[0] ?? 'unknown'}
`; + } +} diff --git a/demo/@helpers/x-user-profile.ts b/demo/@helpers/x-user-profile.ts new file mode 100644 index 00000000..f893264c --- /dev/null +++ b/demo/@helpers/x-user-profile.ts @@ -0,0 +1,22 @@ +import { LitElement, html, type TemplateResult } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import css from './common.css?ctr'; +import type { RouterLocation } from '@vaadin/router'; + +declare global { + interface HTMLElementTagNameMap { + 'x-user-profile': UserProfile; + } +} + +@customElement('x-user-profile') +export default class UserProfile extends LitElement { + static override styles = css; + + @property({ attribute: false }) accessor location: RouterLocation | undefined; + + override render(): TemplateResult { + return html`Name: ${this.location?.params.user ?? 'unknown'}
`; + } +} diff --git a/demo/animated-transitions/d1/iframe.html b/demo/animated-transitions/d1/iframe.html new file mode 100644 index 00000000..96512f58 --- /dev/null +++ b/demo/animated-transitions/d1/iframe.html @@ -0,0 +1,16 @@ + + + ++ Vaadin Router allows you to animate transitions between routes. In order to add an animation, do the next steps: +
+animate property set to true@keyframes animations, either in the view Web Component styles or in outside CSS.leaving and .entering classes to use the animations
+ The demo below illustrates how to add the transition between all the routes in the same group. You might also
+ add the transition for the specific routes only, by setting the animate
+ property on the corresponding route config objects.
+
To run the animated transition, Vaadin Router performs the actions in the following order:
+entering CSS class on the new view componentleaving CSS class on the old view component, if any@keyframes animation applies, and wait for it to complete
+ In the basic use case, using single type of the animated transition could be enough to make the web app looking
+ great, but often we need to configure it depending on the route. Vaadin Router supports this feature by setting
+ object value to animate property, with the enter and leave string keys.
+ Their values are used for setting CSS classes to be set on the views.
+
+ Note that you can first configure animated transition for the group of routes, and then override it for the + single route. In particular, you can switch back to using default CSS classes, as shown in the demo below. +
+User id: ${this.location?.params.id}. This view was loaded using JS bundle.
`; + } +} +// end::snippet[] diff --git a/demo/code-splitting/d2/iframe.html b/demo/code-splitting/d2/iframe.html new file mode 100644 index 00000000..3ea59ba0 --- /dev/null +++ b/demo/code-splitting/d2/iframe.html @@ -0,0 +1,14 @@ + + + ++ Vaadin Router allows you to implement your own loading mechanism for bundles using custom + Route Actions. In that case, you can use + dynamic imports. +
++ Note: If the dynamically loaded route has lifecycle callbacks, the action should return a promise that resolves + only when the route component is loaded (like in the example below). Otherwise the lifecycle callbacks on the + dynamically loaded route's web component are not called. +
++ If dynamic imports are used both for parent and child routes, then the example above may possibly slow down + rendering because router would not start importing a child component until its parent is imported. +
+ ++ Vaadin Router supports splitting the routes configuration object into parts and lazily loading them on-demand, + enabling developers to create non-monolithic app structures. This might be useful for implementing a distributed + sub routes configuration within a big project, so that multiple teams working on different parts of the app no + longer have to merge their changes into the same file. +
+
+ The children property on the route config object can be set to a function, which returns an array
+ of the route objects. It may return a Promise, which allows to dynamically import the configuration file, and return the children array exported from it.
+
+ See the API documentation for detailed description of the
+ children callback function.
+
User id: [[location.params.id]]. This view was loaded using HTML bundle.
- -User id: [[location.params.id]]. This view was loaded using JS bundle.
- `; - return tpl; - } - } - - customElements.define(XUserJsBundleView.is, XUserJsBundleView); -})(); diff --git a/demo/demo-elements/users-routes.js b/demo/demo-elements/users-routes.js deleted file mode 100644 index 1b43034e..00000000 --- a/demo/demo-elements/users-routes.js +++ /dev/null @@ -1,14 +0,0 @@ -(() => { - window.Vaadin = window.Vaadin || {}; - Vaadin.Demo = Vaadin.Demo || {}; - Vaadin.Demo.moduleStorage = Vaadin.Demo.moduleStorage || []; - - const usersRoutes = [ - {path: '/', component: 'x-user-home'}, - {path: '/:user', component: 'x-user-profile'}, - ]; - - Vaadin.Demo.moduleStorage.push({ - default: usersRoutes - }); -})(); diff --git a/demo/demo-elements/x-breadcrumbs.html b/demo/demo-elements/x-breadcrumbs.html deleted file mode 100644 index 8b214910..00000000 --- a/demo/demo-elements/x-breadcrumbs.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - -View not found
- - -/user or /users: [[location.params.0]]
-
-
-You've come to [[location.pathname]], but alas, there is
- nothing there.
ID: [[location.params.0]]
- - -Name: [[location.params.user]]
- - -Router class
+ The Router class is the only thing you need to get started with Vaadin Router. Depending on your
+ project setup, there are several ways to access it.
+
+ In modern browsers that support ES modules the Router class can be imported
+ directly into a script tag on a page:
+
+ In Vite / Webpack / Rollup projects the Router class can be imported from the
+ @vaadin/router npm package:
+
+ Vaadin Router automatically listens to navigation events and asynchronously renders a matching Web Component
+ into the given DOM node (a.k.a. the router outlet). By default, navigation events are triggered by
+ popstate events on the window, and by click events on
+ <a> elements on the page.
+
+ The routes config maps URL paths to Web Components. 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). For details on the route path syntax see the + Route Parameters demos. +
++ Route components can be any Web Components regardless of how they are built: vanilla JavaScript, Lit, Stencil, + SkateJS, Angular, Vue, etc. +
++ Vaadin Router follows the lifecycle callbacks convention described in + WebComponentInterface: if a route component defines any + of these callback methods, Vaadin Router will call them at the appropriate points in the navigation lifecycle. + See the Lifecycle Callbacks section for more details. +
+
+ In addition to that Vaadin Router also sets a
+ location property on every route Web Component so
+ that you could access the current location details via an instance property (e.g.
+ this.location.pathname).
+
this.location
+ For LitElement and TypeScript a declaration in the component is required. Declare the
+ location property in the class and initialize it from the router Vaadin Router
+ instance:
+
This property is automatically updated on navigation.
+ +
+ If Vaadin Router does not find a matching route, the promise returned from the render() method gets
+ rejected, and any content in the router outlet is removed. In order to show a user-friendly 'page not found'
+ view, a fallback route with a wildcard '(.*)' path can be added to the end of the
+ routes list.
+
+ There can be different fallbacks for different route prefixes, but since the route resolution is based on the + first match, the fallback route should always be after other alternatives. +
+
+ The path that leads to the fallback route is available to the route component via the
+ location.pathname property.
+
+ Vaadin Router manages the lifecycle of all route Web Components. + Lifecycle callbacks allow you to add custom logic to any point of this lifecycle: +
+
+
+ onBeforeEnter(location, commands, router): Promise | Prevent | Redirect | void
+
+
+ onAfterEnter(location, commands, router): void
+
+
+ onBeforeLeave(location, commands, router): Promise | Prevent | void
+
+
+
+ onAfterLeave(location, commands, router): void
+ 'vaadin-router-location-changed' / 'vaadin-router-error' events on the
+ window
+
+ Vaadin Router lifecycle callbacks can be defined as methods on the route Web Component
+ class definition
+ in a similar way as the native custom element callbacks (like disconnectedCallback()).
+
onBeforeEnter(location, commands, router)+ The component's route has matched the current path, an instance of the component has been created and is about + to be inserted into the DOM. Use this callback to create a route guard (e.g. redirect to the login page if the + user is not logged in). +
++ At this point there is yet + no guarantee that the navigation into this view will actually happen because another route's + callback may interfere. +
+
+ This callback may return a redirect (return commands.redirect('/new/path')) or a
+ prevent (return commands.prevent()) router command. If it returns a promise, the router
+ waits until the promise is resolved before proceeding with the navigation.
+
+ See the + API documentation for more details. +
+
+ Note: Navigating to the same route also triggers this callback, e.g., click on the same link
+ multiple times will trigger the onBeforeEnter
+ callback on each click.
+
onAfterEnter(location, commands, router)+ The component's route has matched the current path and an instance of the component has been rendered into the + DOM. At this point it is certain that navigation won't be prevented or redirected. Use this callback to process + route params and initialize the view so that it's ready for user interactions. +
+
+ NOTE: When navigating between views the onAfterEnter callback on the new view's component is called
+ before the onAfterLeave callback on the previous view's component (which is being
+ removed). At some point both the new and the old view components are present in the DOM to allow
+ animating the transition (you can listen to the
+ animationend event to detect when it is over).
+
+ Any value returned from this callback is ignored. See the + API documentation for more details. +
+onBeforeLeave(location, commands, router)+ The component's route does not match the current path anymore and the component is about to be removed from the + DOM. Use this callback to prevent the navigation if necessary like in the demo below. Note that the user is + still able to copy and open that URL manually in the browser. +
++ Even if this callback does not prevent the navigation, at this point there is yet + no guarantee that the navigation away from this view will actually happen because another + route's callback may also interfere. +
+
+ This callback may return a prevent (return commands.prevent()) router command. If it
+ returns a promise, the router waits until the promise is resolved before proceeding with the navigation.
+
+ See the + API documentation for more details. +
+
+ Note: Navigating to the same route also triggers this callback, e.g., click on the same link
+ multiple times will trigger the onBeforeLeave
+ callback on each click.
+
onAfterLeave(location, commands, router)+ The component's route does not match the current path anymore and the component's removal from the DOM has been + started (it will be removed after a transition animation, if any). At this point it is certain that navigation + won't be prevented. Use this callback to clean-up and perform any custom actions that leaving a view should + trigger. For example, the demo below auto-saves any unsaved changes when the user navigates away from the view. +
+
+ NOTE: When navigating between views the onAfterEnter callback on the new view's component is called
+ before the onAfterLeave callback on the previous view's component (which is being
+ removed). At some point both the new and the old view components are present in the DOM to allow
+ animating the transition (you can listen to the
+ animationend event to detect when it is over).
+
+ Any value returned from this callback is ignored. See the + API documentation for more details. +
+
+ In order to react to route changes in other parts of the app (outside of route components), you can add an event
+ listener for the vaadin-router-location-changed events on the window. Vaadin Router
+ dispatches such events every time after navigating to a new path.
+
+ In case if navigation fails for any reason (e.g. if no route matched the given pathname), instead of the
+ vaadin-router-location-changed event Vaadin Router dispatches vaadin-router-error and
+ attaches the error object to the event as event.detail.error.
+
+ When handling Vaadin Router events, you can access the router instance via
+ event.detail.router, and the current location via event.detail.location (which is a
+ shorthand for event.detail.router.location). The
+ location
+ object has all details about the current router state. For example,
+ location.routes is a read-only list of routes that correspond to the last completed navigation,
+ which may be useful for example when creating a breadcrumbs component to visualize the current in-app location.
+
+ The router configuration allows you to add any custom properties to route objects. The example above uses that
+ to set a custom xBreadcrumb property on the routes that we want to show up in breadcrumbs. That
+ property is used later when processing the vaadin-router-location-changed events.
+
+ For using with components defined as TypeScript classes, the following interfaces are available for + implementing: +
+
+ BeforeEnterObserver
+
+ AfterEnterObserver
+
+ BeforeLeaveObserver
+
+ AfterLeaveObserver
+
This feature is for advanced use cases. Please make sure to read the documentation carefully.
+
+ There are several events that can trigger in-app navigation with Vaadin Router: popstate events, clicks on the
+ <a> elements, imperative navigation triggered by JavaScript. In order to make a flexible
+ solution that can be tweaked to particular app needs and remain efficient, Vaadin Router has a concept of
+ pluggable Navigation Triggers that listen to specific browser events and convert them into the Vaadin
+ Router navigation events.
+
+ The @vaadin/router package comes with two Navigation Triggers bundled by default:
+ POPSTATE and CLICK.
+
+ Developers can define and use additional Navigation Triggers that are specific to their application. A
+ Navigation Trigger object must have two methods: activate() to start listening on some UI events,
+ and inactivate() to stop.
+
NavigationTrigger.POPSTATE
+ The default POPSTATE navigation trigger for Vaadin Router listens to popstate events
+ on the current window and for each of them dispatches a navigation event for Vaadin Router using
+ the current window.location.pathname as the navigation target. This allows using the browser
+ Forward and Back buttons for in-app navigation.
+
+ In the demo below the popstate events are dispatched at 3 seconds intervals. Before dispatching an
+ event the global location.pathname is toggled between '/' and '/users'.
+
+ Please note that when using the window.history.pushState() or
+ window.history.replaceState() methods, you need to dispatch the popstate event
+ manually—these methods do not do that by themselves (see
+ MDN
+ for details).
+
NavigationTrigger.CLICK
+ The CLICK navigation trigger intercepts clicks on <a> elements on the the page
+ and converts them into navigation events for Vaadin Router if they refer to a location within the app. That
+ allows using regular <a> link elements for in-app navigation. You can use
+ router-ignore
+ attribute to have the router ignore the link.
+
+ The set of default navigation triggers can be changed using the Router.setTriggers() static
+ method. It accepts zero, one or more NavigationTriggers.
+
+ This demo shows how to disable the CLICK navigation trigger. It may be useful when the app has an
+ own custom element for in-app links instead of using the regular <a> elements for that
+ purpose. The demo also shows a very basic version of a custom in-app link element based on a list element that
+ fires popstate events when clicked.
+
+ Note: if the default Navigation Triggers are not used by the app, they can be excluded from the app bundle to
+ avoid sending unnecessary code to the users. See src/router-config.js for details.
+
+ Each Vaadin Router instance is automatically subscribed to navigation events upon creation. Sometimes it might
+ be necessary to cancel this subscription so that the router would re-render only in response to the explicit
+ render() method calls. Use the unsubscribe() method to cancel this automatic
+ subscription and the subscribe() method to re-subscribe.
+
+ Vaadin Router supports the redirect property on the route
+ objects, allowing to unconditionally redirect users from one path to
+ another. The valid values are a path string or a pattern in the same
+ format as used for the path property.
+
+ The original path is not stored as the window.history entry
+ and cannot be reached by pressing the "Back" browser button. Unconditional
+ redirects work for routes both with and without parameters.
+
+ The original path is available to route Web Components as the
+
+ location.redirectFrom string property, and to custom
+ route actions –
+ as context.redirectFrom.
+
+ Note: If a route has both the redirect and action
+ properties, action is executed first and if it does not
+ return a result Vaadin Router proceeds to check the redirect
+ property. Other route properties (if any) would be ignored. In that case
+ Vaadin Router would also log a warning to the browser console.
+
+ Vaadin Router allows redirecting to another path dynamically based on
+ a condition evaluated at the run time. In order to do that,
+ return commands.redirect('/new/path') from the
+ onBeforeEnter() lifecycle
+ callback of the route Web Component.
+
+ It is also possible to redirect from a custom route action. The demo below
+ has an example of that in the /logout route action. See the
+ Route Actions section for
+ more details.
+
+ If you want to send users to another path in response to a user
+ action (outside of a lifecycle callback), you can do that by using the
+ static
+ Router.go('/to/path') method on the Vaadin.Router class.
+
+ You can optionally pass search query string and hash to the method, either + as in-app URL string: +
+
+ NOTE: the same effect can be achieved by dispatching a
+ vaadin-router-go custom event on the window. The
+ target path should be provided as event.detail.pathname,
+ the search and hash strings can be optionally provided
+ with event.detail.search and event.detail.hash
+ properties respectively.
+
This feature is for advanced use cases. Please make sure to read the documentation carefully.
+
+ Route resolution is an async operation started by a navigation event, or by an explicit
+ render() method call. In that process Vaadin Router goes through the routes config and tries to
+ resolve each matching route from the root onwards. The default route resolution rule is to create and
+ return an instance of the route's component (see the API docs for the
+ setRoutes() method for details on other route properties and how they affect the route resolution).
+
+ Vaadin Router provides a flexible API to customize the default route resolution rule. Each route may have an
+ action functional property that defines how exactly that route is resolved. An
+ action function can return a result either directly, or within a Promise resolving to
+ the result. If the action result is an HTMLElement instance, a
+ commands.component(name) result, a commands.redirect(path) result, or a
+ context.next() result, the resolution pass, and the returned value is what gets rendered.
+ Otherwise, the resolution process continues to check the other properties of the route and apply the default
+ resolution rules, and then further to check other matching routes.
+
+ The action(context, commands) function receives a context
+ parameter with the following properties:
+
context.pathname [string] the pathname being resolvedcontext.search [string] the search query stringcontext.hash [string] the hash stringcontext.params [object] the route parameterscontext.route [object] the route that is currently being renderedcontext.next() [function] function for asynchronously getting the next route contents from the
+ resolution chain (if any)
+ The commands is a helper object with methods to create return values for the action:
return commands.redirect('/new/path') create and return a redirect command for the specified
+ path. This command should be returned from the action to perform an actual redirect.
+ return commands.prevent() create and return a prevent command. This command should be returned
+ from the action
+ to instruct router to stop the current navigation and remain at the previous location.
+ return commands.component('tag-name') create and return a new HTMLElement that will
+ be rendered into the router outlet. Using the component command ensures that the created
+ component is initialized as a Vaadin Router view (i.e. the location property is set according to
+ the current router context.
+ component route property: the action result will be rendered, if the action is in a child route,
+ the result will be rendered as light dom child of the component from a parent route.
+
+ This demo shows how to use the custom action property to collect visit statistics for each route.
+
+ Since route resolution is async, the action() callback may be async as well and return a promise.
+ One use case for that is to create a custom route action that makes a remote API call to fetch the data
+ necessary to render the route component, before navigating to a route.
+
+ Note: If a route has both the component and action properties, action is
+ executed first and if it does not return a result Vaadin.Router proceeds to check the
+ component property.
+
This demo shows a way to perform async tasks before navigating to any route under /users.
+ action() can return a command created using the commands parameter methods to affect
+ the route resolution result. The first demo had demonstrated the context.next() usage, this demo
+ demonstrates using commands.redirect(path) to redirect to any other defined route by using its
+ path. All the parameters in current context will be passed to the redirect target.
+
+ Note: If you need only to redirect to another route, defining an action might be an overkill. More convenient + way is described in Redirects section. +
+
+ Another command available to a custom action() is commands.component('tag-name'). It
+ is useful to create a custom element with current context. All the parameters in current context will be passed
+ to the rendered element.
+
+ Note: If the only thing your action does is custom element creation, it can be replaced with
+ component property of the route. See
+ Getting Started
+ section for examples.
+
+ Route action function can access context.search and context.hash URL parts, even
+ though they are not involved in matching route paths.
+
+ For example, an action can change the route behavior depending on a search parameter, and optionally render, + skip to next route or redirect. +
+ID: ${this.location?.params.id ?? 'unknown'}
+/project or /projects: ${this.location?.params[0] ?? 'unknown'}`;
+ }
+}
+// end::snippet[]
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'x-project-view': ProjectView;
+ }
+}
diff --git a/demo/route-parameters/d3/iframe.html b/demo/route-parameters/d3/iframe.html
new file mode 100644
index 00000000..af90762b
--- /dev/null
+++ b/demo/route-parameters/d3/iframe.html
@@ -0,0 +1,15 @@
+
+
+
+ Route parameters are useful when the same Web Component should be
+ rendered for a number of paths, where a part of the path is static, and
+ another part contains a parameter value. E.g. for both /user/1
+ and /user/42 paths it's the same Web Component that
+ renders the content, the /user/ part is static, and 1
+ and 42 are the parameter values.
Route parameters are defined using an express.js-like syntax. The + implementation is based on the path-to-regexp library that is commonly + used in modern front-end libraries and frameworks. All features are + supported: +
+/profile/:user/:size/:color?/kb/:path*/kb/:path+/image-:size(\d+)px/(user[s]?)/:id
+ Route parameters are bound to the location.params property of
+ the route Web Component
+ (location
+ is set on the route components by Vaadin Router).
+
location.params.id or location.params['id']location.params[0]The example below shows how to access route parameters:
++ Route matching rules can be ambiguous, so that several routes would match + the same path. In that case, the order in which the routes are defined is + important. The first route matching the path gets rendered (starting from + the top of the list / root of the tree).
+
+ The default route matching is exact, i.e. a
+ '/user' route (if it does not have children) matches only the
+ '/user' path, but not '/users' nor
+ '/user/42'. Trailing slashes are not significant in paths,
+ but are significant in routes, i.e. a '/user' route matches
+ both '/user' the '/user/', but a
+ '/user/' route matches only the '/user/' path.
+
Prefix matching is used for routes with children, or if
+ the route explicitly indicates that trailing content is expected (e.g.
+ a '/users/(*.)' route matches any path starting with
+ '/users/').
+
+ Always place more specific routes before less specific: +
+{path: '/user/new', ...} - matches only
+ '/user/new'{path: '/user/:user', ...} - matches
+ '/user/42', but not '/user/42/edit'{path: '/user/(.*)', ...} - matches anything starting
+ with '/user/'
+ The route can be configured so that only specific characters are accepted for a parameter value.
+ Other characters would not meet the check and the route resolution would continue to other routes.
+ You only can use unnamed parameters in this case, as it can only be achieved using the custom RegExp.
+ One possible alternative is to use Route Actions
+ and check the context.params.
+ The search query string (?example) URL part is considered
+ separate from the pathname. Hence, it does not participate in matching
+ the route path, and location.params does not
+ contain search query string parameters.
+
+ Use location.search to access the raw search query string.
+ Use location.searchParams to get the URLSearchParams wrapper of the search query string.
+
+ Likewise with the search query, the hash string (#example)
+ is separate from the pathname as well. Use location.hash
+ to access the hash string in the view component.
+
router.urlForName method
+ Vaadin Router supports referring to routes using string names. You can assign a name to a route using the
+ name property of a route object, then generate URLs for that route using the
+
+ router.urlForName(name, parameters)
+
+ helper instance method.
+
Arguments:
+name — the route nameparameters — optional object with parameters for substitution in the route path
+ If the component property is specified on the route object, the name property could be
+ omitted. In that case, the component name could be used in the router.urlForName().
+
router.urlForPath method
+
+ router.urlForPath(path, parameters)
+
+ is a helper method that generates a URL for the given route path, optionally performing substitution of
+ parameters.
+
Arguments:
+path — a string route path defined in express.js syntaxparameters — optional object with parameters for path substitutionlocation.getUrl method
+
+ location.getUrl(params)
+
+ is a method that returns a URL corresponding to the location. When given the params argument, it does parameter
+ substitution in the location’s chain of routes.
+
Arguments:
+params — optional object with parameters to override the location parametersWhen base URL is set, the URL generation helpers return absolute pathnames, including the base.
++ At the moment, Vaadin Router does not provide URL generation APIs for appending search query parameters or hash + strings to the generated URLs. However, you could append those with string concatenation. +
+
+ For serialising parameters into a query string, use the native
+ URLSearchParams API.
+
- Vaadin Router allows you to animate transitions between routes. In order to add an animation, do the next steps: -
-animate property set to true@keyframes animations, either in the view Web Component styles or in outside CSS.leaving and .entering classes to use the animations
- The demo below illustrates how to add the transition between all the routes in the same group.
- You might also add the transition for the specific routes only, by setting the animate
- property on the corresponding route config objects.
-
- To run the animated transition, Vaadin Router performs the actions in the following order: -
-entering CSS class on the new view componentleaving CSS class on the old view component, if any@keyframes animation applies, and wait for it to complete
- In the basic use case, using single type of the animated transition could be enough to make the web app
- looking great, but often we need to configure it depending on the route. Vaadin Router supports this feature
- by setting object value to animate property, with the enter and
- leave string keys. Their values are used for setting CSS classes to be set on the views.
-
- Note that you can first configure animated transition for the group of routes, and then override it for - the single route. In particular, you can switch back to using default CSS classes, as shown in the demo below. -
-- Vaadin Router allows you to implement your own loading mechanism for bundles using - custom Route Actions. In that case, - you can use dynamic imports and a module bundler to make the code work in browsers - not supporting them natively. Both Webpack and Polymer CLI support dynamic imports for lazy - loading ES modules, and transform them for the older browsers. -
-- Note: If the dynamically loaded route has lifecycle callbacks, the action - should return a promise that resolves only when the route component is - loaded (like in the example below). Otherwise the lifecycle callbacks on - the dynamically loaded route's web component are not called. -
-- If dynamic imports are used both for parent and child routes, then the - example above may possibly slow down rendering because router would not - start importing a child component until its parent is imported. -
- -- Vaadin Router supports splitting the routes configuration object into parts and lazily loading them on-demand, - enabling developers to create non-monolithic app structures. This might be useful for implementing a distributed - sub routes configuration within a big project, so that multiple teams working on different parts of the app - no longer have to merge their changes into the same file. -
-
- The children property on the route config object can be set to a function, which returns an
- array of the route objects. It may return a Promise, which allows to dynamically import
- the configuration file, and return the children array exported from it.
-
- See the API documentation
- for detailed description of the children callback function.
-
- In cases when loading .js and .mjs is not
- enough—most notably, when using HTML imports in Polymer-based
- apps—the lazy loading feature can be implemented with a custom route
- action (for more details see
- Route Actions).
-
- This demo shows a way to lazily add an HTML import. The user.bundle.html
- file contains entire Polymer 2 component definition including a template, a class,
- and a script that defines a custom element.
-
Router classThe Router class is the only thing you need to get started
- with Vaadin Router. Depending on your project setup, there are several
- ways to access it.
-
In modern browsers that support ES modules the
- Router class can be imported directly into a script tag on a page:
-
<script type="module">
- import {Router} from 'https://unpkg.com/@vaadin/router';
-</script>
- In Webpack / Rollup / Polymer CLI projects the Router class can
- be imported from the @vaadin/router npm package:
-
import {Router} from '@vaadin/router';
- In older browsers without the ES modules support the
- Router class is exposed as a member of the Vaadin
- namespace after the vaadin-router UMD bundle is loaded:
-
<script src="https://unpkg.com/@vaadin/router/dist/vaadin-router.umd.min.js"></script>
-<script>
- var Router = Vaadin.Router;
-</script>
-
- Vaadin Router automatically listens to navigation events and
- asynchronously renders a matching Web Component into the given DOM node
- (a.k.a. the router outlet). By default, navigation events are
- triggered by popstate events on the window, and
- by click events on <a> elements on the
- page.
The routes config maps URL paths to Web Components. 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). For details on the route path syntax - see the Route Parameters - demos. -
-- Route components can be any Web Components regardless of how they are - built: vanilla JavaScript, Polymer, Stencil, SkateJS, Angular, Vue, etc. -
-- Vaadin Router follows the lifecycle callbacks convention described in - WebComponentInterface: - if a route component defines any of these callback methods, Vaadin Router - will call them at the appropriate points in the navigation lifecycle. - See the Lifecycle - Callbacks section for more details. -
-
- In addition to that Vaadin Router also sets a
- location
- property on every route Web Component so that you could access the
- current location details via an instance property (e.g.
- this.location.pathname).
-
this.location
- If you use Polymer and JavaScript to build your view components,
- the location property does not require a declaration.
- It is recommended to add it to the properties of your
- component for consistency, though:
-
static get properties() {
- return {
- // ...
- location: Object
- };
-}
-
- For LitElement and TypeScript a declaration in the component is required.
- Declare the location property in the class and initialize it
- from the router Vaadin Router instance:
-
import {router} from './index';
-import {customElement, html, LitElement, property} from 'lit-element';
-
-@customElement('my-view')
-class MyViewElement extends LitElement {
- @property({type: Object}) location = router.location;
-
- render() {
- return html`
- Current location URL: ${this.location.getUrl()}
- `;
- }
-}
- This property is automatically updated on navigation.
- -If Vaadin Router does not find a matching route, the promise returned
- from the render() method gets rejected, and any content in
- the router outlet is removed. In order to show a user-friendly 'page not
- found' view, a fallback route with a wildcard '(.*)' path can
- be added to the end of the routes list.
There can be different fallbacks for different route prefixes, but since - the route resolution is based on the first match, the fallback route - should always be after other alternatives.
-The path that leads to the fallback route is available to the route
- component via the location.pathname property.
Each route can have child routes, which makes it easier to group related - routes together under a common parent. This is optional, i.e. the same - routes config can be expressed as a flat list, or as a parent-children - tree. The routes config in the example below is effectively the same as in - the "Getting Started" example above.
-The leading '/' in child route paths is optional—they
- are always relative to the path of the parent route.
- In certain cases, for instance when creating a navigation bar shown on certain application pages,
- it is useful to define a common layout and reuse it. Vaadin Router supports this by specifying
- the component property both in parent and child route objects.
-
In this case child route's component will be rendered as a light DOM child of parent route's component.
-
- When using Web Components, in order to display the children rendered by Vaadin Router, parent component should contain
- the <slot>
- tag in its Shadow DOM. The parent layout component stays in the DOM when you switch between the child routes.
-
Vaadin Router supports cases when the app is deployed to a subpath, for
- example, example.com/shop/. The
-
- baseUrl property
- defines a common prefix for all URLs handled by a router instance.
-
The <base href="..."> tag in
- the <head>of the document is used to set the base URL
- globally. Alternatively, the base URL can be configured on the router
- instance using with the constructor option.
-
When the base URL is set, only the links matching the base URL are - handled by the router. Links that do no match the base URL are considered - external, clicking such a link will result in a regular navigation. -
-When some <a> links are external for the app, Vaadin
- Router can be configured to ignore them and let the browser handle these
- links in the default way:
-
- <a href="/users" router-ignore>Users</a>
When an large set of URLs needs to be ignored (e.g. all URLs starting
- with /external), it may be impractical to add the
- router-ignore attribute to each link separately.
- For such cases a more practical approach would be to add a special route
- to the top of the router config:
-
- Vaadin Router manages the lifecycle of all route Web Components. - Lifecycle callbacks allow you to add custom logic to any point of - this lifecycle: -
-
- onBeforeEnter(location, commands, router): Promise | Prevent | Redirect |
- void
-
-
- onAfterEnter(location, commands, router): void
-
-
- onBeforeLeave(location, commands, router): Promise | Prevent | void
-
-
-
- onAfterLeave(location, commands, router): void
- 'vaadin-router-location-changed' /
- 'vaadin-router-error' events on the window
- disconnectedCallback()).
-
-
- onBeforeEnter(location, commands, router)- The component's route has matched the current path, an instance of the - component has been created and is about to be inserted into the DOM. Use - this callback to create a route guard (e.g. redirect to the login page - if the user is not logged in). -
-- At this point there is yet no guarantee that the navigation into - this view will actually happen because another route's callback - may interfere. -
-
- This callback may return a redirect (return
- commands.redirect('/new/path')) or a prevent (return
- commands.prevent()) router command. If it returns a promise, the
- router waits until the promise is resolved before proceeding with the
- navigation.
-
- See the - API documentation for more details. -
-
- Note: Navigating to the same route also triggers this callback,
- e.g., click on the same link multiple times will trigger the onBeforeEnter
- callback on each click.
-
onAfterEnter(location, commands, router)- The component's route has matched the current path and an instance of the - component has been rendered into the DOM. At this point it is certain that - navigation won't be prevented or redirected. Use this callback to - process route params and initialize the view so that it's ready for user - interactions. -
-
- NOTE: When navigating between views the onAfterEnter
- callback on the new view's component is called before the
- onAfterLeave callback on the previous view's component (which
- is being removed). At some point both the new and the old view components
- are present in the DOM to allow
- animating the
- transition (you can listen to the animationend event to
- detect when it is over).
-
- Any value returned from this callback is ignored. - See the - API documentation for more details. -
-onBeforeLeave(location, commands, router)- The component's route does not match the current path anymore and the - component is about to be removed from the DOM. Use this callback to - prevent the navigation if necessary like in the demo below. Note that the - user is still able to copy and open that URL manually in the browser. -
-- Even if this callback does not prevent the navigation, at this point there - is yet no guarantee that the navigation away from this view will - actually happen because another route's callback may also - interfere. -
-
- This callback may return a prevent (return
- commands.prevent()) router command. If it returns a promise, the
- router waits until the promise is resolved before proceeding with the
- navigation.
-
- See the - API documentation for more details. -
-
- Note: Navigating to the same route also triggers this callback,
- e.g., click on the same link multiple times will trigger the onBeforeLeave
- callback on each click.
-
User name: [[location.params.user]]
- Delete user - -onAfterLeave(location, commands, router)- The component's route does not match the current path anymore and the - component's removal from the DOM has been started (it will be removed - after a transition animation, if any). At this point it is certain that - navigation won't be prevented. Use this callback to clean-up and perform - any custom actions that leaving a view should trigger. For example, the - demo below auto-saves any unsaved changes when the user navigates away - from the view. -
-
- NOTE: When navigating between views the onAfterEnter
- callback on the new view's component is called before the
- onAfterLeave callback on the previous view's component (which
- is being removed). At some point both the new and the old view components
- are present in the DOM to allow
- animating the
- transition (you can listen to the animationend event to
- detect when it is over).
-
- Any value returned from this callback is ignored. - See the - API documentation for more details. -
-
- In order to react to route changes in other parts of the app (outside of
- route components), you can add an event listener for the
- vaadin-router-location-changed events on the window.
- Vaadin Router dispatches such events every time after navigating to a
- new path.
-
- In case if navigation fails for any reason (e.g. if no route matched the
- given pathname), instead of the vaadin-router-location-changed
- event Vaadin Router dispatches vaadin-router-error and
- attaches the error object to the event as event.detail.error.
-
- When handling Vaadin Router events, you can access the router instance via
- event.detail.router, and the current location via
- event.detail.location (which is a shorthand for
- event.detail.router.location). The
- location
- object has all details about the current router state. For example,
- location.routes is a read-only list of routes that correspond
- to the last completed navigation, which may be useful for example when
- creating a breadcrumbs component to visualize the current in-app location.
-
- The router configuration allows you to add any custom properties to route
- objects. The example above uses that to set a custom xBreadcrumb
- property on the routes that we want to show up in breadcrumbs. That
- property is used later when processing the vaadin-router-location-changed
- events.
-
- For using with components defined as TypeScript classes, the following - interfaces are available for implementing: -
-BeforeEnterObserver
import {
- BeforeEnterObserver,
- PreventAndRedirectCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-before-enter')
-class MyViewWithBeforeEnter extends LitElement implements BeforeEnterObserver {
- onBeforeEnter(
- location: RouterLocation,
- commands: PreventAndRedirectCommands,
- router: Router) {
- // ...
- }
-}
- AfterEnterObserver
import {
- AfterEnterObserver,
- EmptyCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-after-enter')
-class MyViewWithAfterEnter extends LitElement implements AfterEnterObserver {
- onAfterEnter(
- location: RouterLocation,
- commands: EmptyCommands,
- router: Router) {
- // ...
- }
-}
- BeforeLeaveObserver
import {
- BeforeLeaveObserver,
- PreventCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-before-leave')
-class MyViewWithBeforeLeave extends LitElement implements BeforeLeaveObserver {
- onBeforeLeave(
- location: RouterLocation,
- commands: PreventCommands,
- router: Router) {
- // ...
- }
-}
- AfterLeaveObserver
import {
- AfterLeaveObserver,
- EmptyCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-after-leave')
-class MyViewWithAfterLeave extends LitElement implements AfterLeaveObserver {
- onAfterLeave(
- location: RouterLocation,
- commands: EmptyCommands,
- router: Router) {
- // ...
- }
-}
- - This feature is for advanced use cases. Please make sure to read the - documentation carefully. -
-
- There are several events that can trigger in-app navigation with
- Vaadin Router: popstate events, clicks on the <a>
- elements, imperative navigation triggered by JavaScript. In order to make
- a flexible solution that can be tweaked to particular app needs and remain
- efficient, Vaadin Router has a concept of pluggable Navigation
- Triggers that listen to specific browser events and convert them into
- the Vaadin Router navigation events.
-
- The @vaadin/router package comes with two Navigation
- Triggers bundled by default: POPSTATE and CLICK.
-
- Developers can define and use additional Navigation Triggers that are
- specific to their application. A Navigation Trigger object must have
- two methods: activate() to start listening on some UI events,
- and inactivate() to stop.
-
NavigationTrigger.POPSTATE
- The default POPSTATE navigation trigger for Vaadin Router
- listens to popstate events on the current window
- and for each of them dispatches a navigation event for Vaadin Router
- using the current window.location.pathname as the navigation
- target. This allows using the browser Forward and Back buttons for in-app
- navigation.
-
- In the demo below the popstate events are dispatched at 3
- seconds intervals. Before dispatching an event the global
- location.pathname is toggled between '/' and '/users'.
-
- Please note that when using the window.history.pushState() or
- window.history.replaceState() methods, you need to dispatch
- the popstate event manually—these methods do not do
- that by themselves (see MDN for details).
-
NavigationTrigger.CLICK
- The CLICK navigation trigger intercepts clicks on
- <a> elements on the the page and converts them into
- navigation events for Vaadin Router if they refer to a
- location within the app. That allows using regular <a>
- link elements for in-app navigation. You can use router-ignore
- attribute to have the router ignore the link.
-
- The set of default navigation triggers can be changed using the
- Router.setTriggers() static method. It accepts zero, one or more
- NavigationTriggers.
-
- This demo shows how to disable the CLICK navigation trigger.
- It may be useful when the app has an own custom element for in-app links
- instead of using the regular <a> elements for that
- purpose. The demo also shows a very basic version of a custom in-app link
- element based on a list element that fires popstate events
- when clicked.
-
- Note: if the default Navigation Triggers are not used by the app, they can
- be excluded from the app bundle to avoid sending unnecessary code to the
- users. See src/router-config.js for details.
-
- Each Vaadin Router instance is automatically subscribed to navigation
- events upon creation. Sometimes it might be necessary to cancel this
- subscription so that the router would re-render only in response to the
- explicit render() method calls. Use the unsubscribe()
- method to cancel this automatic subscription and the
- subscribe() method to re-subscribe.
-
- Vaadin Router supports the redirect property on the route
- objects, allowing to unconditionally redirect users from one path to
- another. The valid values are a path string or a pattern in the same
- format as used for the path property.
-
- The original path is not stored as the window.history entry
- and cannot be reached by pressing the "Back" browser button. Unconditional
- redirects work for routes both with and without parameters.
-
- The original path is available to route Web Components as the
-
- location.redirectFrom string property, and to custom
- route actions –
- as context.redirectFrom.
-
- Note: If a route has both the redirect and action
- properties, action is executed first and if it does not
- return a result Vaadin Router proceeds to check the redirect
- property. Other route properties (if any) would be ignored. In that case
- Vaadin Router would also log a warning to the browser console.
-
- Vaadin Router allows redirecting to another path dynamically based on
- a condition evaluated at the run time. In order to do that,
- return commands.redirect('/new/path') from the
- onBeforeEnter()
- lifecycle callback of the route Web Component.
-
- It is also possible to redirect from a custom route action. The demo below
- has an example of that in the /logout route action. See the
- Route Actions section for
- more details.
-
- If you want to send users to another path in response to a user
- action (outside of a lifecycle callback), you can do that by using the
- static
- Router.go('/to/path') method on the Vaadin.Router class.
-
- You can optionally pass search query string and hash to the method, either - as in-app URL string: -
-
- NOTE: the same effect can be achieved by dispatching a
- vaadin-router-go custom event on the window. The
- target path should be provided as event.detail.pathname,
- the search and hash strings can be optionally provided
- with event.detail.search and event.detail.hash
- properties respectively.
-
- This feature is for advanced use cases. Please make sure to read the - documentation carefully. -
-
- Route resolution is an async operation started by a navigation event, or
- by an explicit render() method call. In that process
- Vaadin Router goes through the routes config and tries to resolve
- each matching route from the root onwards. The default route resolution
- rule is to create and return an instance of the route's component
- (see the API docs for the setRoutes() method for
- details on other route properties and how they affect the route resolution).
-
- Vaadin Router provides a flexible API to customize the default route
- resolution rule. Each route may have an action functional
- property that defines how exactly that route is resolved. An action
- function can return a result either directly, or within
- a Promise resolving to the result. If the action result
- is an HTMLElement instance,
- a commands.component(name) result,
- a commands.redirect(path) result,
- or a context.next() result, the resolution pass, and
- the returned value is what gets rendered. Otherwise, the resolution
- process continues to check the other properties of the route and apply
- the default resolution rules, and then further to check other
- matching routes.
-
- The action(context, commands) function receives a context
- parameter with the following properties:
-
context.pathname [string] the pathname being resolved
- context.search [string] the search query stringcontext.hash [string] the hash stringcontext.params [object] the route parameterscontext.route [object] the route that is currently being renderedcontext.next() [function] function for asynchronously getting the next route contents from the resolution chain (if any)commands is a helper object with methods to create return
- values for the action:
- return commands.redirect('/new/path') create and return a
- redirect command for the specified path. This command should be
- returned from the action to perform an actual redirect.
- return commands.prevent() create and return a prevent
- command. This command should be returned from the action
- to instruct router to stop the current navigation and remain at the
- previous location.
- return commands.component('tag-name') create and return a
- new HTMLElement that will be rendered into the router
- outlet. Using the component command ensures that the
- created component is initialized as a Vaadin Router view (i.e. the
- location property is set according to the current router
- context.
- component route property: the action result will be
- rendered, if the action is in a child route, the result will be
- rendered as light dom child of the component from a parent route.
-
- This demo shows how to use the custom action property to
- collect visit statistics for each route.
-
- Since route resolution is async, the action() callback may be
- async as well and return a promise. One use case for that is to create
- a custom route action that makes a remote API call to fetch the data
- necessary to render the route component, before navigating to a route.
-
- Note: If a route has both the component and action
- properties, action is executed first and if it does
- not return a result Vaadin.Router proceeds to check the component
- property.
-
- This demo shows a way to perform async tasks before navigating to any
- route under /users.
-
- action() can return a command created using the
- commands parameter methods to affect the route resolution
- result.
- The first demo had demonstrated the context.next() usage,
- this demo demonstrates using commands.redirect(path) to
- redirect to any other defined route by using its path.
- All the parameters in current context will be passed to the redirect target.
-
- Note: If you need only to redirect to another route, defining an action might be an overkill. - More convenient way is described in Redirects section. -
-
- Another command available to a custom action() is
- commands.component('tag-name'). It is useful to create a
- custom element with current context. All the parameters in current context
- will be passed to the rendered element.
-
- Note: If the only thing your action does is custom element creation, it
- can be replaced with component property of the route.
- See Getting Started
- section for examples.
-
- Route action function can access context.search and
- context.hash URL parts, even though they are not involved
- in matching route paths.
-
- For example, an action can change the route behavior depending on - a search parameter, and optionally render, skip to next route or redirect. -
-Route parameters are useful when the same Web Component should be
- rendered for a number of paths, where a part of the path is static, and
- another part contains a parameter value. E.g. for both /user/1
- and /user/42 paths it's the same Web Component that
- renders the content, the /user/ part is static, and 1
- and 42 are the parameter values.
Route parameters are defined using an express.js-like syntax. The - implementation is based on the path-to-regexp library that is commonly - used in modern front-end libraries and frameworks. All features are - supported: -
/profile/:user/:size/:color?/kb/:path*/kb/:path+/image-:size(\d+)px/(user[s]?)/:id
- Route parameters are bound to the location.params property of
- the route Web Component
- (location
- is set on the route components by Vaadin Router).
-
location.params.id or location.params['id']location.params[0]The example below shows how to access route parameters in a Polymer 2 - based Web Component:
-ID: [[location.params.id]]
-/project or /projects: [[location.params.0]]
-
- - Route matching rules can be ambiguous, so that several routes would match - the same path. In that case, the order in which the routes are defined is - important. The first route matching the path gets rendered (starting from - the top of the list / root of the tree).
-
- The default route matching is exact, i.e. a
- '/user' route (if it does not have children) matches only the
- '/user' path, but not '/users' nor
- '/user/42'. Trailing slashes are not significant in paths,
- but are significant in routes, i.e. a '/user' route matches
- both '/user' the '/user/', but a
- '/user/' route matches only the '/user/' path.
-
Prefix matching is used for routes with children, or if
- the route explicitly indicates that trailing content is expected (e.g.
- a '/users/(*.)' route matches any path starting with
- '/users/').
-
- Always place more specific routes before less specific: -
{path: '/user/new', ...} - matches only
- '/user/new'{path: '/user/:user', ...} - matches
- '/user/42', but not '/user/42/edit'{path: '/user/(.*)', ...} - matches anything starting
- with '/user/'
- The route can be configured so that only specific characters are accepted for a parameter value.
- Other characters would not meet the check and the route resolution would continue to other routes.
- You only can use unnamed parameters in this case, as it can only be achieved using the custom RegExp.
- One possible alternative is to use Route Actions
- and check the context.params.
- The search query string (?example) URL part is considered
- separate from the pathname. Hence, it does not participate in matching
- the route path, and location.params does not
- contain search query string parameters.
-
- Use location.search to access the raw search query string.
- Use location.searchParams to get the URLSearchParams wrapper of the search query string.
-
- Likewise with the search query, the hash string (#example)
- is separate from the pathname as well. Use location.hash
- to access the hash string in the view component.
-
router.urlForName method
- Vaadin Router supports referring to routes using string names. You can
- assign a name to a route using the name property of a route
- object, then generate URLs for that route using the
-
-
- router.urlForName(name, parameters)
- helper instance method.
-
- Arguments: -
-name — the route nameparameters — optional object with parameters for
- substitution in the route path
- If the component property is specified on the route object,
- the name property could be omitted. In that case,
- the component name could be used in the router.urlForName().
-
router.urlForPath method
-
-
- router.urlForPath(path, parameters)
- is a helper method that generates a URL for
- the given route path, optionally performing substitution of parameters.
-
- Arguments: -
-path — a string route path defined in express.js syntaxparameters — optional object with parameters for
- path substitutionlocation.getUrl method
-
-
- location.getUrl(params)
- is a method that returns a URL corresponding to the location.
- When given the params argument, it does parameter substitution
- in the location’s chain of routes.
-
- Arguments: -
-params — optional object with parameters to override
- the location parameters- When base URL is set, the URL generation helpers return absolute - pathnames, including the base. -
-- At the moment, Vaadin Router does not provide URL generation APIs for - appending search query parameters or hash strings to the generated URLs. - However, you could append those with string concatenation. -
-
- For serialising parameters into a query string, use the native
- URLSearchParams API.
-
[[_privacy]] static [[descriptor.name]](, [[p.name]]: [[p.type]]): [[descriptor.return.type]]Inherited from [[descriptor.inheritedFrom]]
[[descriptor.sourceRange.file]][[item.name]][[_privacy]] [[descriptor.name]]: [[descriptor.type]] = [[descriptor.defaultValue]] notify readOnly reflectToAttributeInherited from [[descriptor.inheritedFrom]]
[[descriptor.summary]]
[[descriptor.path]][[descriptor.summary]]
[[descriptor.path]][[descriptor.summary]]
class [[descriptor.name]] extends [[descriptor.superclass]] with [[item]][[descriptor.path]][[descriptor.summary]]
[[descriptor.path]][[descriptor.summary]]
User id: [[location.params.id]]. This view was loaded using HTML bundle.
User id: [[location.params.id]]. This view was loaded using JS bundle.
\n ";return tpl}}]);return XUserJsBundleView}(Polymer.Element);customElements.define(XUserJsBundleView.is,XUserJsBundleView)})(); \ No newline at end of file diff --git a/docs/vaadin-router/demo/demo-elements/users-routes.js b/docs/vaadin-router/demo/demo-elements/users-routes.js deleted file mode 100644 index a4ef056f..00000000 --- a/docs/vaadin-router/demo/demo-elements/users-routes.js +++ /dev/null @@ -1 +0,0 @@ -(function(){window.Vaadin=window.Vaadin||{};Vaadin.Demo=Vaadin.Demo||{};Vaadin.Demo.moduleStorage=Vaadin.Demo.moduleStorage||[];var usersRoutes=[{path:"/",component:"x-user-home"},{path:"/:user",component:"x-user-profile"}];Vaadin.Demo.moduleStorage.push({default:usersRoutes})})(); \ No newline at end of file diff --git a/docs/vaadin-router/demo/demo-shell.html b/docs/vaadin-router/demo/demo-shell.html deleted file mode 100644 index e114810b..00000000 --- a/docs/vaadin-router/demo/demo-shell.html +++ /dev/null @@ -1,7705 +0,0 @@ -Name: [[location.params.user]]
View not found
/user or /users: [[location.params.0]]ID: [[location.params.0]]
You've come to [[location.pathname]], but alas, there is nothing there.
- Vaadin Router allows you to animate transitions between routes. In order to add an animation, do the next steps: -
-animate property set to true@keyframes animations, either in the view Web Component styles or in outside CSS.leaving and .entering classes to use the animations
- The demo below illustrates how to add the transition between all the routes in the same group.
- You might also add the transition for the specific routes only, by setting the animate
- property on the corresponding route config objects.
-
- To run the animated transition, Vaadin Router performs the actions in the following order: -
-entering CSS class on the new view componentleaving CSS class on the old view component, if any@keyframes animation applies, and wait for it to complete
- In the basic use case, using single type of the animated transition could be enough to make the web app
- looking great, but often we need to configure it depending on the route. Vaadin Router supports this feature
- by setting object value to animate property, with the enter and
- leave string keys. Their values are used for setting CSS classes to be set on the views.
-
- Note that you can first configure animated transition for the group of routes, and then override it for - the single route. In particular, you can switch back to using default CSS classes, as shown in the demo below. -
-- Vaadin Router allows you to implement your own loading mechanism for bundles using - custom Route Actions. In that case, - you can use dynamic imports and a module bundler to make the code work in browsers - not supporting them natively. Both Webpack and Polymer CLI support dynamic imports for lazy - loading ES modules, and transform them for the older browsers. -
-- Note: If the dynamically loaded route has lifecycle callbacks, the action - should return a promise that resolves only when the route component is - loaded (like in the example below). Otherwise the lifecycle callbacks on - the dynamically loaded route's web component are not called. -
-- If dynamic imports are used both for parent and child routes, then the - example above may possibly slow down rendering because router would not - start importing a child component until its parent is imported. -
- -- Vaadin Router supports splitting the routes configuration object into parts and lazily loading them on-demand, - enabling developers to create non-monolithic app structures. This might be useful for implementing a distributed - sub routes configuration within a big project, so that multiple teams working on different parts of the app - no longer have to merge their changes into the same file. -
-
- The children property on the route config object can be set to a function, which returns an
- array of the route objects. It may return a Promise, which allows to dynamically import
- the configuration file, and return the children array exported from it.
-
- See the API documentation
- for detailed description of the children callback function.
-
- In cases when loading .js and .mjs is not
- enough—most notably, when using HTML imports in Polymer-based
- apps—the lazy loading feature can be implemented with a custom route
- action (for more details see
- Route Actions).
-
- This demo shows a way to lazily add an HTML import. The user.bundle.html
- file contains entire Polymer 2 component definition including a template, a class,
- and a script that defines a custom element.
-
Router classThe Router class is the only thing you need to get started
- with Vaadin Router. Depending on your project setup, there are several
- ways to access it.
-
In modern browsers that support ES modules the
- Router class can be imported directly into a script tag on a page:
-
<script type="module">
- import {Router} from 'https://unpkg.com/@vaadin/router';
-</script>
- In Webpack / Rollup / Polymer CLI projects the Router class can
- be imported from the @vaadin/router npm package:
-
import {Router} from '@vaadin/router';
- In older browsers without the ES modules support the
- Router class is exposed as a member of the Vaadin
- namespace after the vaadin-router UMD bundle is loaded:
-
<script src="https://unpkg.com/@vaadin/router/dist/vaadin-router.umd.min.js"></script>
-<script>
- var Router = Vaadin.Router;
-</script>
-
- Vaadin Router automatically listens to navigation events and
- asynchronously renders a matching Web Component into the given DOM node
- (a.k.a. the router outlet). By default, navigation events are
- triggered by popstate events on the window, and
- by click events on <a> elements on the
- page.
The routes config maps URL paths to Web Components. 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). For details on the route path syntax - see the Route Parameters - demos. -
-- Route components can be any Web Components regardless of how they are - built: vanilla JavaScript, Polymer, Stencil, SkateJS, Angular, Vue, etc. -
-- Vaadin Router follows the lifecycle callbacks convention described in - WebComponentInterface: - if a route component defines any of these callback methods, Vaadin Router - will call them at the appropriate points in the navigation lifecycle. - See the Lifecycle - Callbacks section for more details. -
-
- In addition to that Vaadin Router also sets a
- location
- property on every route Web Component so that you could access the
- current location details via an instance property (e.g.
- this.location.pathname).
-
this.location
- If you use Polymer and JavaScript to build your view components,
- the location property does not require a declaration.
- It is recommended to add it to the properties of your
- component for consistency, though:
-
static get properties() {
- return {
- // ...
- location: Object
- };
-}
-
- For LitElement and TypeScript a declaration in the component is required.
- Declare the location property in the class and initialize it
- from the router Vaadin Router instance:
-
import {router} from './index';
-import {customElement, html, LitElement, property} from 'lit-element';
-
-@customElement('my-view')
-class MyViewElement extends LitElement {
- @property({type: Object}) location = router.location;
-
- render() {
- return html`
- Current location URL: ${this.location.getUrl()}
- `;
- }
-}
- This property is automatically updated on navigation.
- -If Vaadin Router does not find a matching route, the promise returned
- from the render() method gets rejected, and any content in
- the router outlet is removed. In order to show a user-friendly 'page not
- found' view, a fallback route with a wildcard '(.*)' path can
- be added to the end of the routes list.
There can be different fallbacks for different route prefixes, but since - the route resolution is based on the first match, the fallback route - should always be after other alternatives.
-The path that leads to the fallback route is available to the route
- component via the location.pathname property.
Each route can have child routes, which makes it easier to group related - routes together under a common parent. This is optional, i.e. the same - routes config can be expressed as a flat list, or as a parent-children - tree. The routes config in the example below is effectively the same as in - the "Getting Started" example above.
-The leading '/' in child route paths is optional—they
- are always relative to the path of the parent route.
- In certain cases, for instance when creating a navigation bar shown on certain application pages,
- it is useful to define a common layout and reuse it. Vaadin Router supports this by specifying
- the component property both in parent and child route objects.
-
In this case child route's component will be rendered as a light DOM child of parent route's component.
-
- When using Web Components, in order to display the children rendered by Vaadin Router, parent component should contain
- the <slot>
- tag in its Shadow DOM. The parent layout component stays in the DOM when you switch between the child routes.
-
Vaadin Router supports cases when the app is deployed to a subpath, for
- example, example.com/shop/. The
-
- baseUrl property
- defines a common prefix for all URLs handled by a router instance.
-
The <base href="..."> tag in
- the <head>of the document is used to set the base URL
- globally. Alternatively, the base URL can be configured on the router
- instance using with the constructor option.
-
When the base URL is set, only the links matching the base URL are - handled by the router. Links that do no match the base URL are considered - external, clicking such a link will result in a regular navigation. -
-When some <a> links are external for the app, Vaadin
- Router can be configured to ignore them and let the browser handle these
- links in the default way:
-
<a href="/users" router-ignore>Users</a>
-
- When an large set of URLs needs to be ignored (e.g. all URLs starting
- with /external), it may be impractical to add the
- router-ignore attribute to each link separately.
- For such cases a more practical approach would be to add a special route
- to the top of the router config:
-
- Vaadin Router manages the lifecycle of all route Web Components. - Lifecycle callbacks allow you to add custom logic to any point of - this lifecycle: -
-
- onBeforeEnter(location, commands, router): Promise | Prevent | Redirect |
- void
-
-
- onAfterEnter(location, commands, router): void
-
-
- onBeforeLeave(location, commands, router): Promise | Prevent | void
-
-
-
- onAfterLeave(location, commands, router): void
- 'vaadin-router-location-changed' /
- 'vaadin-router-error' events on the window
- disconnectedCallback()).
-
-
- onBeforeEnter(location, commands, router)- The component's route has matched the current path, an instance of the - component has been created and is about to be inserted into the DOM. Use - this callback to create a route guard (e.g. redirect to the login page - if the user is not logged in). -
-- At this point there is yet no guarantee that the navigation into - this view will actually happen because another route's callback - may interfere. -
-
- This callback may return a redirect (return
- commands.redirect('/new/path')) or a prevent (return
- commands.prevent()) router command. If it returns a promise, the
- router waits until the promise is resolved before proceeding with the
- navigation.
-
- See the - API documentation for more details. -
-
- Note: Navigating to the same route also triggers this callback,
- e.g., click on the same link multiple times will trigger the onBeforeEnter
- callback on each click.
-
onAfterEnter(location, commands, router)- The component's route has matched the current path and an instance of the - component has been rendered into the DOM. At this point it is certain that - navigation won't be prevented or redirected. Use this callback to - process route params and initialize the view so that it's ready for user - interactions. -
-
- NOTE: When navigating between views the onAfterEnter
- callback on the new view's component is called before the
- onAfterLeave callback on the previous view's component (which
- is being removed). At some point both the new and the old view components
- are present in the DOM to allow
- animating the
- transition (you can listen to the animationend event to
- detect when it is over).
-
- Any value returned from this callback is ignored. - See the - API documentation for more details. -
-onBeforeLeave(location, commands, router)- The component's route does not match the current path anymore and the - component is about to be removed from the DOM. Use this callback to - prevent the navigation if necessary like in the demo below. Note that the - user is still able to copy and open that URL manually in the browser. -
-- Even if this callback does not prevent the navigation, at this point there - is yet no guarantee that the navigation away from this view will - actually happen because another route's callback may also - interfere. -
-
- This callback may return a prevent (return
- commands.prevent()) router command. If it returns a promise, the
- router waits until the promise is resolved before proceeding with the
- navigation.
-
- See the - API documentation for more details. -
-
- Note: Navigating to the same route also triggers this callback,
- e.g., click on the same link multiple times will trigger the onBeforeLeave
- callback on each click.
-
User name: [[location.params.user]]
- Delete user - -onAfterLeave(location, commands, router)- The component's route does not match the current path anymore and the - component's removal from the DOM has been started (it will be removed - after a transition animation, if any). At this point it is certain that - navigation won't be prevented. Use this callback to clean-up and perform - any custom actions that leaving a view should trigger. For example, the - demo below auto-saves any unsaved changes when the user navigates away - from the view. -
-
- NOTE: When navigating between views the onAfterEnter
- callback on the new view's component is called before the
- onAfterLeave callback on the previous view's component (which
- is being removed). At some point both the new and the old view components
- are present in the DOM to allow
- animating the
- transition (you can listen to the animationend event to
- detect when it is over).
-
- Any value returned from this callback is ignored. - See the - API documentation for more details. -
-
- In order to react to route changes in other parts of the app (outside of
- route components), you can add an event listener for the
- vaadin-router-location-changed events on the window.
- Vaadin Router dispatches such events every time after navigating to a
- new path.
-
- In case if navigation fails for any reason (e.g. if no route matched the
- given pathname), instead of the vaadin-router-location-changed
- event Vaadin Router dispatches vaadin-router-error and
- attaches the error object to the event as event.detail.error.
-
- When handling Vaadin Router events, you can access the router instance via
- event.detail.router, and the current location via
- event.detail.location (which is a shorthand for
- event.detail.router.location). The
- location
- object has all details about the current router state. For example,
- location.routes is a read-only list of routes that correspond
- to the last completed navigation, which may be useful for example when
- creating a breadcrumbs component to visualize the current in-app location.
-
- The router configuration allows you to add any custom properties to route
- objects. The example above uses that to set a custom xBreadcrumb
- property on the routes that we want to show up in breadcrumbs. That
- property is used later when processing the vaadin-router-location-changed
- events.
-
- For using with components defined as TypeScript classes, the following - interfaces are available for implementing: -
-BeforeEnterObserver
import {
- BeforeEnterObserver,
- PreventAndRedirectCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-before-enter')
-class MyViewWithBeforeEnter extends LitElement implements BeforeEnterObserver {
- onBeforeEnter(
- location: RouterLocation,
- commands: PreventAndRedirectCommands,
- router: Router) {
- // ...
- }
-}
- AfterEnterObserver
import {
- AfterEnterObserver,
- EmptyCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-after-enter')
-class MyViewWithAfterEnter extends LitElement implements AfterEnterObserver {
- onAfterEnter(
- location: RouterLocation,
- commands: EmptyCommands,
- router: Router) {
- // ...
- }
-}
- BeforeLeaveObserver
import {
- BeforeLeaveObserver,
- PreventCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-before-leave')
-class MyViewWithBeforeLeave extends LitElement implements BeforeLeaveObserver {
- onBeforeLeave(
- location: RouterLocation,
- commands: PreventCommands,
- router: Router) {
- // ...
- }
-}
- AfterLeaveObserver
import {
- AfterLeaveObserver,
- EmptyCommands,
- Router,
- RouterLocation
-} from '@vaadin/router';
-
-@customElement('my-view-with-after-leave')
-class MyViewWithAfterLeave extends LitElement implements AfterLeaveObserver {
- onAfterLeave(
- location: RouterLocation,
- commands: EmptyCommands,
- router: Router) {
- // ...
- }
-}
- - This feature is for advanced use cases. Please make sure to read the - documentation carefully. -
-
- There are several events that can trigger in-app navigation with
- Vaadin Router: popstate events, clicks on the <a>
- elements, imperative navigation triggered by JavaScript. In order to make
- a flexible solution that can be tweaked to particular app needs and remain
- efficient, Vaadin Router has a concept of pluggable Navigation
- Triggers that listen to specific browser events and convert them into
- the Vaadin Router navigation events.
-
- The @vaadin/router package comes with two Navigation
- Triggers bundled by default: POPSTATE and CLICK.
-
- Developers can define and use additional Navigation Triggers that are
- specific to their application. A Navigation Trigger object must have
- two methods: activate() to start listening on some UI events,
- and inactivate() to stop.
-
NavigationTrigger.POPSTATE
- The default POPSTATE navigation trigger for Vaadin Router
- listens to popstate events on the current window
- and for each of them dispatches a navigation event for Vaadin Router
- using the current window.location.pathname as the navigation
- target. This allows using the browser Forward and Back buttons for in-app
- navigation.
-
- In the demo below the popstate events are dispatched at 3
- seconds intervals. Before dispatching an event the global
- location.pathname is toggled between '/' and '/users'.
-
- Please note that when using the window.history.pushState() or
- window.history.replaceState() methods, you need to dispatch
- the popstate event manually—these methods do not do
- that by themselves (see MDN for details).
-
NavigationTrigger.CLICK
- The CLICK navigation trigger intercepts clicks on
- <a> elements on the the page and converts them into
- navigation events for Vaadin Router if they refer to a
- location within the app. That allows using regular <a>
- link elements for in-app navigation. You can use router-ignore
- attribute to have the router ignore the link.
-
- The set of default navigation triggers can be changed using the
- Router.setTriggers() static method. It accepts zero, one or more
- NavigationTriggers.
-
- This demo shows how to disable the CLICK navigation trigger.
- It may be useful when the app has an own custom element for in-app links
- instead of using the regular <a> elements for that
- purpose. The demo also shows a very basic version of a custom in-app link
- element based on a list element that fires popstate events
- when clicked.
-
- Note: if the default Navigation Triggers are not used by the app, they can
- be excluded from the app bundle to avoid sending unnecessary code to the
- users. See src/router-config.js for details.
-
- Each Vaadin Router instance is automatically subscribed to navigation
- events upon creation. Sometimes it might be necessary to cancel this
- subscription so that the router would re-render only in response to the
- explicit render() method calls. Use the unsubscribe()
- method to cancel this automatic subscription and the
- subscribe() method to re-subscribe.
-
- Vaadin Router supports the redirect property on the route
- objects, allowing to unconditionally redirect users from one path to
- another. The valid values are a path string or a pattern in the same
- format as used for the path property.
-
- The original path is not stored as the window.history entry
- and cannot be reached by pressing the "Back" browser button. Unconditional
- redirects work for routes both with and without parameters.
-
- The original path is available to route Web Components as the
-
- location.redirectFrom string property, and to custom
- route actions –
- as context.redirectFrom.
-
- Note: If a route has both the redirect and action
- properties, action is executed first and if it does not
- return a result Vaadin Router proceeds to check the redirect
- property. Other route properties (if any) would be ignored. In that case
- Vaadin Router would also log a warning to the browser console.
-
- Vaadin Router allows redirecting to another path dynamically based on
- a condition evaluated at the run time. In order to do that,
- return commands.redirect('/new/path') from the
- onBeforeEnter()
- lifecycle callback of the route Web Component.
-
- It is also possible to redirect from a custom route action. The demo below
- has an example of that in the /logout route action. See the
- Route Actions section for
- more details.
-
- If you want to send users to another path in response to a user
- action (outside of a lifecycle callback), you can do that by using the
- static
- Router.go('/to/path') method on the Vaadin.Router class.
-
- You can optionally pass search query string and hash to the method, either - as in-app URL string: -
-
- NOTE: the same effect can be achieved by dispatching a
- vaadin-router-go custom event on the window. The
- target path should be provided as event.detail.pathname,
- the search and hash strings can be optionally provided
- with event.detail.search and event.detail.hash
- properties respectively.
-
- This feature is for advanced use cases. Please make sure to read the - documentation carefully. -
-
- Route resolution is an async operation started by a navigation event, or
- by an explicit render() method call. In that process
- Vaadin Router goes through the routes config and tries to resolve
- each matching route from the root onwards. The default route resolution
- rule is to create and return an instance of the route's component
- (see the API docs for the setRoutes() method for
- details on other route properties and how they affect the route resolution).
-
- Vaadin Router provides a flexible API to customize the default route
- resolution rule. Each route may have an action functional
- property that defines how exactly that route is resolved. An action
- function can return a result either directly, or within
- a Promise resolving to the result. If the action result
- is an HTMLElement instance,
- a commands.component(name) result,
- a commands.redirect(path) result,
- or a context.next() result, the resolution pass, and
- the returned value is what gets rendered. Otherwise, the resolution
- process continues to check the other properties of the route and apply
- the default resolution rules, and then further to check other
- matching routes.
-
- The action(context, commands) function receives a context
- parameter with the following properties:
-
context.pathname [string] the pathname being resolved
- context.search [string] the search query stringcontext.hash [string] the hash stringcontext.params [object] the route parameterscontext.route [object] the route that is currently being renderedcontext.next() [function] function for asynchronously getting the next route contents from the resolution chain (if any)commands is a helper object with methods to create return
- values for the action:
- return commands.redirect('/new/path') create and return a
- redirect command for the specified path. This command should be
- returned from the action to perform an actual redirect.
- return commands.prevent() create and return a prevent
- command. This command should be returned from the action
- to instruct router to stop the current navigation and remain at the
- previous location.
- return commands.component('tag-name') create and return a
- new HTMLElement that will be rendered into the router
- outlet. Using the component command ensures that the
- created component is initialized as a Vaadin Router view (i.e. the
- location property is set according to the current router
- context.
- component route property: the action result will be
- rendered, if the action is in a child route, the result will be
- rendered as light dom child of the component from a parent route.
-
- This demo shows how to use the custom action property to
- collect visit statistics for each route.
-
- Since route resolution is async, the action() callback may be
- async as well and return a promise. One use case for that is to create
- a custom route action that makes a remote API call to fetch the data
- necessary to render the route component, before navigating to a route.
-
- Note: If a route has both the component and action
- properties, action is executed first and if it does
- not return a result Vaadin.Router proceeds to check the component
- property.
-
- This demo shows a way to perform async tasks before navigating to any
- route under /users.
-
- action() can return a command created using the
- commands parameter methods to affect the route resolution
- result.
- The first demo had demonstrated the context.next() usage,
- this demo demonstrates using commands.redirect(path) to
- redirect to any other defined route by using its path.
- All the parameters in current context will be passed to the redirect target.
-
- Note: If you need only to redirect to another route, defining an action might be an overkill. - More convenient way is described in Redirects section. -
-
- Another command available to a custom action() is
- commands.component('tag-name'). It is useful to create a
- custom element with current context. All the parameters in current context
- will be passed to the rendered element.
-
- Note: If the only thing your action does is custom element creation, it
- can be replaced with component property of the route.
- See Getting Started
- section for examples.
-
- Route action function can access context.search and
- context.hash URL parts, even though they are not involved
- in matching route paths.
-
- For example, an action can change the route behavior depending on - a search parameter, and optionally render, skip to next route or redirect. -
-Route parameters are useful when the same Web Component should be
- rendered for a number of paths, where a part of the path is static, and
- another part contains a parameter value. E.g. for both /user/1
- and /user/42 paths it's the same Web Component that
- renders the content, the /user/ part is static, and 1
- and 42 are the parameter values.
Route parameters are defined using an express.js-like syntax. The - implementation is based on the path-to-regexp library that is commonly - used in modern front-end libraries and frameworks. All features are - supported: -
/profile/:user/:size/:color?/kb/:path*/kb/:path+/image-:size(\d+)px/(user[s]?)/:id
- Route parameters are bound to the location.params property of
- the route Web Component
- (location
- is set on the route components by Vaadin Router).
-
location.params.id or location.params['id']location.params[0]The example below shows how to access route parameters in a Polymer 2 - based Web Component:
-ID: [[location.params.id]]
-/project or /projects: [[location.params.0]]
-
- - Route matching rules can be ambiguous, so that several routes would match - the same path. In that case, the order in which the routes are defined is - important. The first route matching the path gets rendered (starting from - the top of the list / root of the tree).
-
- The default route matching is exact, i.e. a
- '/user' route (if it does not have children) matches only the
- '/user' path, but not '/users' nor
- '/user/42'. Trailing slashes are not significant in paths,
- but are significant in routes, i.e. a '/user' route matches
- both '/user' the '/user/', but a
- '/user/' route matches only the '/user/' path.
-
Prefix matching is used for routes with children, or if
- the route explicitly indicates that trailing content is expected (e.g.
- a '/users/(*.)' route matches any path starting with
- '/users/').
-
- Always place more specific routes before less specific: -
{path: '/user/new', ...} - matches only
- '/user/new'{path: '/user/:user', ...} - matches
- '/user/42', but not '/user/42/edit'{path: '/user/(.*)', ...} - matches anything starting
- with '/user/'
- The route can be configured so that only specific characters are accepted for a parameter value.
- Other characters would not meet the check and the route resolution would continue to other routes.
- You only can use unnamed parameters in this case, as it can only be achieved using the custom RegExp.
- One possible alternative is to use Route Actions
- and check the context.params.
- The search query string (?example) URL part is considered
- separate from the pathname. Hence, it does not participate in matching
- the route path, and location.params does not
- contain search query string parameters.
-
- Use location.search to access the raw search query string.
- Use location.searchParams to get the URLSearchParams wrapper of the search query string.
-
- Likewise with the search query, the hash string (#example)
- is separate from the pathname as well. Use location.hash
- to access the hash string in the view component.
-
router.urlForName method
- Vaadin Router supports referring to routes using string names. You can
- assign a name to a route using the name property of a route
- object, then generate URLs for that route using the
-
-
- router.urlForName(name, parameters)
- helper instance method.
-
- Arguments: -
-name — the route nameparameters — optional object with parameters for
- substitution in the route path
- If the component property is specified on the route object,
- the name property could be omitted. In that case,
- the component name could be used in the router.urlForName().
-
router.urlForPath method
-
-
- router.urlForPath(path, parameters)
- is a helper method that generates a URL for
- the given route path, optionally performing substitution of parameters.
-
- Arguments: -
-path — a string route path defined in express.js syntaxparameters — optional object with parameters for
- path substitutionlocation.getUrl method
-
-
- location.getUrl(params)
- is a method that returns a URL corresponding to the location.
- When given the params argument, it does parameter substitution
- in the location’s chain of routes.
-
- Arguments: -
-params — optional object with parameters to override
- the location parameters- When base URL is set, the URL generation helpers return absolute - pathnames, including the base. -
-- At the moment, Vaadin Router does not provide URL generation APIs for - appending search query parameters or hash strings to the generated URLs. - However, you could append those with string concatenation. -
-
- For serialising parameters into a query string, use the native
- URLSearchParams API.
-