Skip to content

Instantly share code, notes, and snippets.

@FWeinb
Last active August 29, 2015 14:01
Show Gist options
  • Save FWeinb/93d419e38e82caf4bee9 to your computer and use it in GitHub Desktop.
Save FWeinb/93d419e38e82caf4bee9 to your computer and use it in GitHub Desktop.
Routing with Web Components

Basic routing using Web Components

You can see a live demo of this here.

I experimented a little bit with web components and Polymer in the last few days and come up with a routing schema using web components. I would like to know if there are any flaws or shortcomings you can see.

I will start with the basic usage:

demo-app.html

    <!-- Create a new component-router and bind the routeData to the local route variable -->
    <component-router routeData="{{route}}">

      <!-- Define the route(s) this component will be activated on-->
      <component-route route="component/:id:/data/:data:"></component-route>

      <!-- only load component if something is routed. -->
      <template if="{{route && route.id <= 2}}">
        <!--  Dynamicly load a component (using HTMLImports) and pass in custom data -->
        <component-loader path='component-{{route.id}}.html' data="{{route.data}}" ></component-loader>
      </template>

      <!-- Show error -->
      <template if="{{!route || route.id > 2}}">
        <p>Component {{route.id}} not found. There are only two components.</p>
      </template>
    </component-router>

A component-router is to define a space where different routes (component-route) can be defined and are rendered. Each component-router will only be visibel if a containing route is matched.

The component-loader is used to dynamicly load a sub component (which is another custom element) all attributes except the path are passed to the loaded component and can be used there.

Example of a component: component-1.html

<polymer-element name="component-1" attributes="data" noscript>
  <template>
    <h1>Component - 1</h1>
    <span>Show some data: {{data}}</span>
  </template>
</polymer-element>
@addyosmani
Copy link

If I've understood correctly, this setup is optimized for pages with a large amount of dynamic content that you only want to load up if a user navigates to a particular route. Using it, you would define one or more component-route elements inside your page, each with a number of child component-routes identifying which routes the component is activated on. I assume that if I have multiple component-routes on my page with one or more of the same routes that they could work in isolation without this being a problem, right? :)

How are you performing the loading mechanism in the component-loader?. Are you just using core-ajax or something else? It probably makes sense to use Polymer.import for this (if you aren't already doing so) per http://addyosmani.github.io/webcomponent-samples/polymer/modules/. This allows you to support inline HTML import definitions being in component-1.html as you would probably hope to use at some point.

The only other piece of feedback I can think of is that you seem to have an amount of boilerplate in your element around here:

<template if="{{route && route.id <= 2}}">
   <component-loader path='component-{{route.id}}.html' data="{{route.data}}" ></component-loader>
 </template>

<template if="{{route && route.id == 3}}">
   <component-loader path='component-{{route.id}}.html' data="{{route.data}}" ></component-loader>
</template>

I wonder if this could be generalized down into a conditional-loader element which extends component-loader. This would allow you to do something like <conditional-loader if="{{route && route.id <= 2}}" path='component-{{route.id}}.html' data="{{route.data}}" ></conditional-loader> where you could try handling the template portion behind the scenes. Just a suggestion.

@addyosmani
Copy link

Some more notes:

This approach should work quite well for dynamic elements, but you probably know that it's going to introduce an overhead of network requests (and dependency resolution) for each element you try to load in. You could probably try reducing the cost of this by vulcanizing anything you're loading in with your component-loader.

An alternative to dynamic loading would be including all of your elements in the page upfront where they are either inert or hidden and then switching what id displayed based on the route you are on. It really depends on what you're doing here though.

Some other routing efforts:

https://github.com/PolymerLabs/flatiron-director
https://github.com/ahuth/app-router
https://github.com/kvnlnt/polymerApp/tree/master/app/elements
https://github.com/polymerjs-tw/polymer-simple-router

@FWeinb
Copy link
Author

FWeinb commented May 11, 2014

Thanks your for the notes. You are right that there is a overhead in doing it this way. Why I choose to implement it like this is that only the things that are needed to display the routed component are loaded and subsequently cached. This will make the initial page load faster.

I think it really depends on the use case as you noted.

On thing that comes to mind regarding this technique is that componentes are just removed from render-tree but the javascript object are all kept in memory. It would be great to explore a way to destroy a custom element and reinitialise it on request afterwards, to keep the memory footprint as low as possible.

@FWeinb
Copy link
Author

FWeinb commented May 11, 2014

The component-loader is using Polymer.import. You are right about the boilerplate code for loading routes and using an extended component-loader for that would be a good idea. I think that the component-loader could be interesting on its own.

I will setup a repo and than all work regarding the component-loader can be gathered there.

Another thing to think about is how to pass down attributes to the loaded component, do you expect the component-loader to have a attribute like data that expects an object like:

<component-loader path="component.html" data="{ 'attr' : 'value' }" />

which will result in the attribute 'attr' to be set to 'value' on the loaded component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment