LogoLogo
HomeDiscourseBlogDiscord
  • Introduction
  • Introduction
    • Quick start
    • Aurelia for new developers
    • Hello world
      • Creating your first app
      • Your first component - part 1: the view model
      • Your first component - part 2: the view
      • Running our app
      • Next steps
  • Templates
    • Template Syntax
      • Attribute binding
      • Event binding
      • Text interpolation
      • Template promises
      • Template references
      • Template variables
      • Globals
    • Custom attributes
    • Value converters (pipes)
    • Binding behaviors
    • Form Inputs
    • CSS classes and styling
    • Conditional Rendering
    • List Rendering
    • Lambda Expressions
    • Local templates (inline templates)
    • SVG
  • Components
    • Component basics
    • Component lifecycles
    • Bindable properties
    • Styling components
    • Slotted content
    • Scope and context
    • CustomElement API
    • Template compilation
      • processContent
      • Extending templating syntax
      • Modifying template parsing with AttributePattern
      • Extending binding language
      • Using the template compiler
      • Attribute mapping
  • Getting to know Aurelia
    • Routing
      • @aurelia/router
        • Getting Started
        • Creating Routes
        • Routing Lifecycle
        • Viewports
        • Navigating
        • Route hooks
        • Router animation
        • Route Events
        • Router Tutorial
        • Router Recipes
      • @aurelia/router-lite
        • Getting started
        • Router configuration
        • Configuring routes
        • Viewports
        • Navigating
        • Lifecycle hooks
        • Router hooks
        • Router events
        • Navigation model
        • Transition plan
    • App configuration and startup
    • Enhance
    • Template controllers
    • Understanding synchronous binding
    • Dynamic composition
    • Portalling elements
    • Observation
      • Observing property changes with @observable
      • Effect observation
      • HTML observation
      • Using observerLocator
    • Watching data
    • Dependency injection (DI)
    • App Tasks
    • Task Queue
    • Event Aggregator
  • Developer Guides
    • Animation
    • Testing
      • Overview
      • Testing attributes
      • Testing components
      • Testing value converters
      • Working with the fluent API
      • Stubs, mocks & spies
    • Logging
    • Building plugins
    • Web Components
    • UI virtualization
    • Errors
      • 0001 to 0023
      • 0088 to 0723
      • 0901 to 0908
    • Bundlers
    • Recipes
      • Apollo GraphQL integration
      • Auth0 integration
      • Containerizing Aurelia apps with Docker
      • Cordova/Phonegap integration
      • CSS-in-JS with Emotion
      • DOM style injection
      • Firebase integration
      • Markdown integration
      • Multi root
      • Progress Web Apps (PWA's)
      • Securing an app
      • SignalR integration
      • Strongly-typed templates
      • TailwindCSS integration
      • WebSockets Integration
      • Web Workers Integration
    • Playground
      • Binding & Templating
      • Custom Attributes
        • Binding to Element Size
      • Integration
        • Microsoft FAST
        • Ionic
    • Migrating to Aurelia 2
      • For plugin authors
      • Side-by-side comparison
    • Cheat Sheet
  • Aurelia Packages
    • Validation
      • Validation Tutorial
      • Plugin Configuration
      • Defining & Customizing Rules
      • Architecture
      • Tagging Rules
      • Model Based Validation
      • Validation Controller
      • Validate Binding Behavior
      • Displaying Errors
      • I18n Internationalization
      • Migration Guide & Breaking Changes
    • i18n Internationalization
    • Fetch Client
      • Overview
      • Setup and Configuration
      • Response types
      • Working with forms
      • Intercepting responses & requests
      • Advanced
    • Event Aggregator
    • State
    • Store
      • Configuration and Setup
      • Middleware
    • Dialog
  • Tutorials
    • Building a ChatGPT inspired app
    • Building a realtime cryptocurrency price tracker
    • Building a todo application
    • Building a weather application
    • Building a widget-based dashboard
    • React inside Aurelia
    • Svelte inside Aurelia
    • Synthetic view
    • Vue inside Aurelia
  • Community Contribution
    • Joining the community
    • Code of conduct
    • Contributor guide
    • Building and testing aurelia
    • Writing documentation
    • Translating documentation
Powered by GitBook
On this page
  • Strategy
  • Setting up
  • Handling Login and Root Transition
  • Updating the HTML Structure
  • Example
  • Managing Application State
  • Additional Considerations
  • Conclusion

Was this helpful?

Export as PDF
  1. Developer Guides
  2. Recipes

Multi root

In a scenario where you need to manage multiple parts of an application that might not always be active or visible at the same time, you can utilize Aurelia's ability to handle multiple root components. This can be particularly useful for scenarios like switching between a public-facing website and a private application after login, or for loading different parts of an application on demand.

Below is a step-by-step guide on how to create a multi-root Aurelia 2 application, complete with detailed explanations and code examples.

Strategy

The approach uses two independent Aurelia applications, the first is the simple login wall host where the user is initially directed. The login wall application provides just the authentication flow implementation, and publishes an authenticated event using the ĒventAggregator if the user successfully authenticates. At the entry point of the application, the authenticated event is subscribed to and when received, the login wall application is stopped and replaced by a new Aurelia application instance containing the app features.

Setting up

In the src/main.ts entry point, we first set up the login wall application and subscribe to the authenticated event using an AppTask. Inside the event subscription, we stop the Aurelia application that provided the login wall and then call a start() function responsible for starting the main app.

// src/main.ts
import Aurelia from 'aurelia';
import { LoginWall } from './login-wall';
import { MyApp } from './my-app';

const host = document.querySelector<HTMLElement>('login-wall');
const au = new Aurelia();
au.register(
  StandardConfiguration,
  AppTask.hydrated(IEventAggregator, (ea) => {
    ea.subscribeOnce(authenticatedEvent, async () => {
      await au.stop();
      await start();
     });
  })
);
au.app({ host, component: LoginWall });
await au.start();

Starting the main app just requires a new Aurelia instance and host element. It is omitted here, but the authenticated event could have been passed to the start function to provide the application with the users auth token and any other user information received in the login process.

async function start() {
  const host = document.querySelector<HTMLElement>('my-app');
  const au = new Aurelia();
  au.register(StandardConfiguration, RouterConfiguration);
  au.app({ host, component: MyApp });
  await au.start();
}

Handling Login and Root Transition

In src/login-wall.ts, we define the LoginWall class with a login method. This method will start and conduct the authentication flow and then publish the authenticated event which was subscribed to at the entry point of the application.

// src/login-wall.ts
import { customElement, inject, IEventAggregator } from 'aurelia';
import { AppRoot } from './app-root';

@customElement('login-wall')
@inject(IEventAggregator)
export class LoginWall {
  constructor(private _ea: IEventAggregator) {}

  async login() {
    this._ea.publish(authenticatedEvent);
  }
}

Updating the HTML Structure

In your index.html or equivalent, you need to have placeholders for each root component. Make sure to provide unique identifiers for each.

<!DOCTYPE html>
<html>
<head>
  <!-- ... -->
</head>
<body>
  <!-- Placeholder for the LoginWall component -->
  <login-wall></login-wall>

  <!-- Placeholder for the AppRoot component -->
  <my-app></my-app>

  <!-- ... -->
</body>
</html>

Example

The following example shows a working skeleton of the approach described.

Managing Application State

When switching roots, you might need to manage application state, like user sessions, and ensure a smooth transition. Consider using Aurelia's dependency injection, state management libraries, or browser storage mechanisms to maintain state across root transitions.

Additional Considerations

  • Routing: If your application uses routing, you'll need to configure the router for each root component separately.

  • Shared Resources: shared resources like services or custom elements, will need to be registered independently in each application via the app entry point.

  • Cleanup: When stopping an Aurelia app instance, make sure to clean up any event listeners or subscriptions to prevent memory leaks.

Conclusion

Multi-root applications in Aurelia 2 allow for a modular and dynamic approach to managing different parts of your application. By following the steps above, you can create a multi-root setup that can handle complex scenarios, such as a public and private interface transition. Remember that each application is unique, and you may need to adjust this approach to fit your specific requirements.

PreviousMarkdown integrationNextProgress Web Apps (PWA's)

Last updated 2 months ago

Was this helpful?

Logorouter-lite - multi-root POC - StackBlitzStackBlitz