Routing and state management in the JSS Angular sample app

Abstract

Client-side and server-side routing and state management flow in the JSS Angular sample app

The sample app uses dynamic routing based on the Layout Service (or local route data files in disconnected mode) and uses route/navigation changes to trigger app state changes. Tracing the primary execution flow must begin with the route configuration.

Client-side routing occurs in the web browser. The following describes the client-side routing flow:

  • A route change (or initial load) triggers Angular routing, configured in src/app/routing/routing.module.ts.

  • Most URLs fall through to the JSS catch-all route, which is needed because the local application is not aware of all the potential routes (items/pages) configured in Sitecore.

  • The catch-all route is configured with a matcher rather than a path, specifically the jssRouteMatcher function. This function uses the JssRouteBuilderService to attempt to parse the URL as a Sitecore-formatted route, /[language]/then/the/item/path/.

  • The jssRouteMatcher function returns the language and serverRoute parameters, which are then provided to the configured route resolver, JssRouteResolver.

  • JssRouteResolver first invokes changeRoute on the JssContextService.

  • JssContextService on the client-side retrieves the route from one of the following:

    • If running in Integrated or Headless server-side rendering (SSR) mode immediately following a server render, an attempt is made to obtain route data from the TransferState, which must contain the server-side rendering state. When this occurs, the HTTP call to layout service is skipped.

    • In all other cases, the route data is fetched through an HTTP call to the Sitecore Layout Service.

  • The JssContextService retains the current route state, and returns it to the JssRouteResolver. The route resolver performs routines necessary for Experience Editor support.

  • Finally, the configured route component (defined in routing.module.ts, defaults to app/routing/layout/layout.component.ts) is loaded into the router-outlet defined in src/app/app.component.ts and is provided with the data from the route resolver. This layout component is responsible for:

    • Handling the UI for data fetching errors, such as HTTP 404s and 500s.

    • Updating route-level states, such as the page title or other meta fields.

    • Updating route-level states, such as the page title or other meta fields.

When the Angular app is prerendered by a Node server, it returns HTML to the client in the initial response. This means that the route data flow is similar to the client-side routing but has a few key differences.

The following describes how the server-side route data flow differs from the client-side routing:

  • The first step varies based on application mode:

    • In integrated mode only, Sitecore receives the request, parses the route server-side, and determines whether the requested item is handled by a JSS application, and which bundle to run.

    • In headless mode only, the Node SSR proxy receives a request and passes it on to a Sitecore layout service.

  • The Node host invokes the renderView function in the server.bundle.ts artifact. The function arguments include the route data/Layout Service output.

  • The renderView function uses Angular SSR to render the application, with two key differences in its module initialization:

    • The app uses the AppServerModule that provides server-specific implementations of some services.

    • The initial route state is injected through dependency injection using a JSS_SERVER_TO_SSR injection token.

  • Routing executes server-side and invokes the server-side implementation of JssService.

  • The JssServerService returns the route data from the JSS_SERVER_TO_SSR injection token and also places the data in TransferState for reading on the client-side.

  • Route rendering continues as it does on the client.