I would like to know the best practice for routing in LWC. I mean, how to show a specific component on a specific URL, how to go to another route from a component, etc. If you can show me an example I would be grateful. Thanks!
2 Answers
There's a demo up on GitHub from the TDX session on using LWC outside of Salesforce.
That uses Navigo for routing in the app module. Here's a slimmed down version of the routing from that example with some comments from my own experience trying to implement this:
import { LightningElement, createElement, track } from 'lwc';
import Navigo from 'navigo'; // import Navigo
export default class App extends LightningElement {
// instantiate the router class
router = new Navigo(location.origin, false);
constructor() {
super();
// define your routes. The await functions are for use with chunking but you could remove them and just do a normal import if all of your scripts are loaded at once
this.router.on({
'/podcasts': async () => {
const { default: ViewPodcasts } = await import(/* webpackChunkName: "view-podcasts" */ 'view/podcasts');
this.setPage('view-podcasts', ViewPodcasts);
},
'/podcasts/:id': async ({ id }) => {
const { default: ViewPodcast } = await import(/* webpackChunkName: "view-podcast" */ 'view/podcast');
this.setPage('view-podcast', ViewPodcast, {
podcastId: parseInt(id, 10),
});
},
'/discover': async () => {
const { default: ViewDiscover } = await import(/* webpackChunkName: "view-discover" */ 'view/discover');
this.setPage('view-discover', ViewDiscover);
},
'/categories/:id': async ({ id }) => {
const { default: PodcastList } = await import(/* webpackChunkName: "view-category" */ 'view/category');
this.setPage('view-category', PodcastList, {
categoryId: parseInt(id, 10),
});
},
});
const navigateToDefault = () => {
this.router.navigate('/podcasts');
};
this.router.notFound(navigateToDefault);
this.router.on(navigateToDefault);
}
renderedCallback() {
// Resolve the current view only after the container has rendered
if (!this.isRendered) {
this.isRendered = true;
this.router.resolve();
}
}
setPage(tagName, component, props = {}) {
// when a route is called, create the related component and insert it into the DOM in whatever container you want
const el = createElement(tagName, {
is: component,
fallback: false,
});
Object.assign(el, props);
// Remove previous components from the container if necessary
const container = this.template.querySelector('.container');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
container.appendChild(el);
}
}
-
Thanks John. When 'setPage' function is called there is an error: DOMException: Failed to execute 'attachShadow' on 'Element'. The component argument seems to be ok. Do you know why this happens? Thanks! Commented Jun 21, 2019 at 14:46
-
It sounds like maybe the element that you're trying to append to doesn't exist. You should try updating
const container = this.template.querySelector('.container');
so it looks for an element in your template or add a div with a class of 'container' to your template. Commented Jun 21, 2019 at 14:53 -
Yes, I did it, but it fails on the first line. On the 'createElement' call, before the query. Commented Jun 21, 2019 at 14:55
-
1I fixed it! The problem was a bad tagName. Thanks! Commented Jun 21, 2019 at 15:23
I have some question regarding on this. Since LWC doesn't support createElement we can't use navigo to implement the routing?