Examples

Autonomous My Single Page App Application

A simple single page application, loading page components into a router component, dependant on route selected. Using attributes to configure the application we can pass in run time requirements as attributes. Bootstraped from a bootstrap file, by importing into a bigger application or direct as html script (ensure you build fallback for IE support).

<my-single-page-app></my-single-page-app>

MySinglePageApp Usage <my-single-page-app>


<!-- Polyfill -->
<script src="/node_modules/promise-polyfill/dist/polyfill.min.js"></script>
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>

<!-- Bootstrap component only, ensure you have built fallback for IE support too (.js)! -->
<script type="module" src="./your/path/my-app.mjs"></script>
<script nomodule src="./your/path/my-app.js"></script>

<!-- Or add your switch import to a bootstrap js file/app using ES6 import and use that instead of the component directly... -->
<script type="module" src="./your/path/index.mjs"></script>
<script nomodule src="./your/path/index.js"></script>

<!-- example basic fouc resolution -->
<style>
	[fouc] { opacity: 0; transition: opacity 200ms ease-in-out; }
	[fouc="loaded"] { opacity: 1; }
</style>

...

<div class="info">
	<div class="class">
		<div class="row" fouc>
			<div class="col-sm-12">
				<my-single-page-app></my-single-page-app>
			</div>
		</div>
	</div>
</div>

...

<!-- fouc for individual components -->
<script> setTimeout(() => document.querySelector('[fouc]').setAttribute('fouc', 'loaded'), 1000); </script>
						

MySinglePageApp Class my-single-page-app.mjs


import { CustomHTMLElement, html } from '../../../node_modules/custom-web-component/index.js';

// CustomWebComponents
import '../Components/my-router.mjs';

/** @ROUTES */ 
import '../Pages/test/page-test-index.mjs';
import '../Pages/test/page-test-one.mjs';
import '../Pages/test/page-test-two.mjs';
import '../Pages/test/page-test-three.mjs';
import '../Pages/test/page-test-four.mjs';
import '../Pages/test/page-test-five.mjs';
import '../Pages/not/page-not-found.mjs';

/**
 * @public @name MySinglePageApp
 * @extends CustomHTMLElement
 * @description Application Web Component, main application gateway, the root web component that starts the application
 * @author Paul Smith <[email protected]>
 * @copyright 2018 Paul Smith (ulsmith.net)
 * @license MIT
 * 
 * @example HTML
 * <my-single-page-app>Loading...</my-single-page-app>
 */
class MySinglePageApp extends CustomHTMLElement {
	/**
	 * @public @constructor @name constructor
	 * @description Process called function triggered when component is instantiated (but not ready or in DOM, must call super() first)
	 */
	constructor() {
		super();

		this._route;
		this._routes = [
			{ component: 'page-test-index', path: 'home', label: 'Home' },
			{ component: 'page-test-one', path: 'one', label: 'One' },
			{ component: 'page-test-two', path: 'two', label: 'Two' },
			{ component: 'page-test-three', path: 'three', label: 'Three' },
			{ component: 'page-test-four', path: 'four', label: 'Four' },
			{ component: 'page-test-five', path: 'five', label: 'Five' },
			{ component: 'page-not-found', path: '404', label: '404', hidden: true }
		];
	}

	/**
	 * @public @name template
	 * @description Template function to return web component HTML template
	 * 
	 * @return {TemplateResult} HTML template result
	 */
	static template() {
		return html`
			<style>
				:host { display: block; width: 100%; height: 100%; }

				ul {
					list-style-type: none;
					margin: 10px 0px;
					padding: 0;
				}

				li {
					display: inline-block;
					background: red;
					padding: 4px 8px;
					margin: 2px;
				}

				a {
					color: white;
					text-decoration: none;
				}

				[active] {
					background: #444;
				}

				.header {
					width: 100%;
					background: orange;
					padding: 20px;
					box-sizing: border-box;
					color: white;
				}

				.footer {
					width: 100%;
					background: #444;
					padding: 20px;
					box-sizing: border-box;
					color: white;
				}
 			</style>

			<div class="header">
				<h1>Header Goes Here</h1>
			</div>		
			${this._route ? html`
				<ul>
					<li ?active="${this._route.path === 'home'}"><a href="#home">Home</a></li>
					<li ?active="${this._route.path === 'one'}"><a href="#one">One</a></li>
					<li ?active="${this._route.path === 'two'}"><a href="#two">Two</a></li>
					<li ?active="${this._route.path === 'three'}"><a href="#three">Three</a></li>
					<li ?active="${this._route.path === 'four'}"><a href="#four">Four</a></li>
					<li ?active="${this._route.path === 'five'}"><a href="#five">Five</a></li>
					<li><a href="#abcxyz">AbcXyz</a></li>
				</ul>
			` : ''}
			<my-router .route="${this._route}" .routes="${this._routes}" default="home" not-found="404" @change="${this._changeRoute.bind(this)}"></my-router>	
			<div class="footer">
				<p>Footer Goes Here</p>
			</div>		
		`;
	}

	/**
	 * @private @name _changeRoute
	 * @description Change the route of the application
	 * 
     * @param {String} path The path of the route
	 */
	_changeRoute(ev) {
		this._route = ev.detail;
		this.updateTemplate();
		window.scrollTo({ top: 0, behavior: 'smooth' });
	}
}

// define the new custom element
customElements.define('my-single-page-app', MySinglePageApp);