App as a Web Component

1. Generating the Web Component

Generating a web component is almost the same as generating a regular journey. To turn a regular journey into a web component you need to pass the option --target=webcomponent during the generation of the journey. The generated journey will then include all the necessary changes to be bundled and used as a web component.

As with a regular journey, there are two scenarios:

1.1. Generate a Journey as Web Component Inside of an Nx Workspace

In case you want to generate the web component inside an existing Nx workspace like the itmp-frontend-workspace you can use the journey-src generator provided by the package @allianz/taly-nx. If that's not installed in your workspace, you can add it with:

yarn add @allianz/taly-nx
# or
npm install @allianz/taly-nx

Generate the Application

npx nx generate journey-src \
    --project=<the-name-of-your-project> \
    --target=webcomponent

The generated app will include the necessary changes to turn it into a web component.

By default, TALY will infer the deploy URL at runtime, allowing the web component's assets like images to load properly. For this to work, images need to use the talyNormalizeUrl pipe. Note that this feature of automatically detecting the deploy url does not work for the url() function in CSS. If a used Building Block relies on url() in its styles, you need to explicitly pass the --deploy-url of the web component (make sure it ends with a slash) to the nx generate command.

Build the Generated Application

To now turn this generated app into a web component you need to first build it:

npx nx build-generated-app <the-name-of-your-project> --configuration=webcomponent

The generator call added the webcomponent configuration. This is needed to support a web component build in addition to the default standalone build. Here are some details about its content:

  • zone.js must be provided as a separate bundle so that the web component can lazy-load it if necessary. If the hosting application or another web component on the same page already provides a Zone then the web component will use that one.
  • deploy-url needs to match the value passed through the generator parameter --deploy-url, in case this option is passed to the generator at all. This configuration is required by the Angular build to properly hardcode the paths to the lazily loaded bundles.
  • vendorChunk needs to be turned off. This is automatically disabled and recommended being turned off for production build by Angular.
  • outputHashing needs to be none. It is an Angular default configuration to produce simple file names for the bundler to deal with (like vendor.js instead of vendor-cb243bcb53.js).
  • If no deploy-url is given then inlineCritical optimization needs to be turned off to make sure that the application contains all the necessary styles. Angular 12 activated the inlineCritical optimization by default. The effect of this optimization is, that critical CSS gets directly inlined into the index.html file. As the content of this file is not used, the CSS from there would be lost.
  • Enable localized builds by setting localize to true or to an array of a subset of the previously defined locale identifiers to build a separate distributable copy of the application for each locale.
  • Adding necessary assets:
    • AllianzNeo and Allianz-Icons fonts are added to the build assets. This is necessary for the web component to automatically load the fonts and icons it needs in case the parent application does not provide them, or when the web component is consumed as a standalone app.
    • For the standalone use case of a web component, it is necessary to overwrite certain styles globally. To do this, normalize.css of ng-aquila is added to the assets.

Bundle the Built Application

The generator call will also create a webcomponent-bundle target in your project configuration. This target can now be used to bundle the built application into a single web component file:

npx nx webcomponent-bundle <the-name-of-your-project>

This will produce a webcomponent-bundle.js file for every locale that got built by the build-generated-app command. This file contains the code that is required to render the web component. To serve the web component(s), you need to "serve" the locale-specific folder in the dist folder of your journey (e.g. ./dist/my-journey/en-US) with a server of your choice. Note that the above command did not remove the generated {main,polyfills,runtime,scripts,styles}.js and index.html files. This allows you to serve the dist/[locale] folder and be able to load the journey as a standalone application through the index.html file, while also being able to load it as a web component from /webcomponent-bundle.js.

1.2. Generate a Journey as Web Component Outside of an Nx Workspace

To generate a journey that exists outside of an Nx workspace as a web component, you can use functions and CLI commands provided by the package @allianz/taly-sdk. Install it like so:

yarn add @allianz/taly-sdk
# or
npm install @allianz/taly-sdk

Afterwards you can use the SDK and the CLI like described in Generate a Journey Outside of an Nx workspace Using the TALY SDK.

Generating the Journey

To generate a journey as a web component with the TALY CLI, pass the --target=webcomponent flag, like so:

npx taly generate-journey --name="My customer journey" --target=webcomponent

To generate a web component with the generateJourney SDK function, you can pass the option target: 'webcomponent', like so:

import { generateJourney } from '@allianz/taly-sdk/node';

for await (const progress of generateJourney({
  name: 'My customer journey',
  target: 'webcomponent'
})) {
  // do something with the progress
}

The app will be generated with the dependencies and the changes required for the web component.

By default, TALY will infer the deploy URL at runtime, allowing the web component's assets like images to load properly. You can override this behavior by passing the future deployUrl/--deploy-url of the web component (make sure it ends with a slash). In both cases, for local development or tests this will most likely be some localhost URL.

Build the Generated Journey With the webcomponent Configuration

The generated workspace will include an Nx project with your new journey. You can build that project in the generated workspace with this command (note the --configuration webcomponent):

cd <path/to/your/generated/workspace>
npx nx build-generated-app <name-of-your-journey> --configuration webcomponent

You now need to bundle all of the produced files in the dist folder into a single file to serve it as a web component.

Bundle the Built Journey

To bundle all relevant files in the dist folder of your journey in the generated workspace, you can run this command:

cd <path/to/your/generated/workspace>
npx nx webcomponent-bundle <name-of-your-journey>

This will produce a webcomponent-bundle.js file for every locale that got built by the build-generated-app command. This file contains the code that is required to render the web component. To serve the web component(s), you need to "serve" the locale-specific folder in the dist folder of your generated workspace (e.g. ./generated/apps/my-journey/dist/en-US) with a server of your choice. Note that the above command did not remove the generated {main,polyfills,runtime,scripts,styles}.js and index.html files. This allows you to serve the dist/[locale] folder and be able to load the journey as a standalone application through the index.html file, while also being able to load it as a web component from /webcomponent-bundle.js.

2. Integrating the Web Component

2.1. General Requirements for the Hosting Application

The idea of web components is to have elements that you can easily use anywhere on any page and they are expected to "just work". While this is mostly true, web components and the underlying technologies are still a fairly young trend and browsers still lack some functionality to make web components as pleasant as they sound.

💡 If your application is hosted in oneMarketing you don't need to worry about these requirements. oneMarketing provides the necessary environment to run TALY-generated web components.

Font "Allianz Neo"

If you want to integrate a TALY web component into a parent application, the host should import @allianz/ngx-ndbx/css/ndbx-base.css so that the TALY web component and other web components can access the font definitions. If the parent application does not provide the required fonts, TALY will load them automatically. For this purpose, make sure that the build options contain the required assets.

💡 A TALY web component only loads fonts that the host doesn't provide and will never load a font that is already provided by the host.

Relative Font Sizes

A lot of the available NDBX components rely on 1rem to equal 10px. This can be achieved by setting the font-size for the html element to 10px or 62.5%. Hosting applications that don't explicitly set this property might lead to web components that contain NDBX components that look broken. Setting this property can either be done manually or by importing the ndbx-base.css styles, like in the requirement for the "Allianz Neo" font family. This of course affects the entire application so it's advised to apply this style as soon as possible in the development process of the hosting application.

Example of a manual approach:

html {
  font-size: 62.5%;
}

2.2. Angular Host Application

TALY does not provide any utility to integrate the generated web component into the parent app. You can use already existing third party libraries like Angular Extensions Elements or your own script to load the web component in the host.

🧩 A full example setup can be found in the webcomponent-integration recipe

2.3. Non-Angular Host Application

Integrating the generated web component in a Non-Angular web application is very straightforward.

  • Include the webcomponent-bundle.js file in your scripts
  • Use the web component selector in the HTML

💡 The actual selector is the name of the project. If you generated a project called my-custom-journey, then use <my-custom-journey></my-custom-journey>. Note, that if the name of the project is not a valid name for a web component, TALY tries to make it valid. To verify the selector, check your generated app's AppModule for the value of the WEB_COMPONENT_ID injection token:

{ provide: WEB_COMPONENT_ID, useValue: 'my-custom-journey' }
<script src="https://your-server.com/webcomponent-bundle.js"></script>
...
<my-custom-journey></my-custom-journey>

💡 Note that it's important to not import the web component bundle as type="module" since this will break the dynamic detection of the web component's deploy URL.

3. Location Strategy in Generated Web Components

A "Location Strategy" in Angular determines the way that the routing in an application affects the URL.

3.1. Web Component Location Strategy

We provide a location strategy for Angular called WebComponentLocationStrategy that uses a special syntax to allow web component routing that is reflected in the URL without interfering with the hosting app's routing - assuming that it is not using hash based routing. This location strategy is the default for TALY-generated web components.

URL Format

Given a WEB_COMPONENT_ID of "my-web-component" and a the route /internalPath in that web component, the WebComponentLocationStrategy will produce paths like this:

.../some/host/path/#(my-web-component:/internalPath)

Given there are multiple web components on the same page that use this location strategy they will neatly live alongside each other and produce paths like so:

.../path/#(my-web-component:/internalPath,other-web-component:/other/path)

Beware Potential URL Conflicts

⚠️ This location strategy changes the hash of the URL.

This location strategy works fine if there are multiple web components on the same page that use this location strategy.

Scenarios exist where it might not be a good idea to take control over or change the URL's hash. This is a (probably incomplete) list of scenarios where you would want to avoid using this location strategy:

  • Fragment scrolling
    The WebComponentLocationStrategy is not meant to be used on pages that use fragments as part of their URLs. If a page some/path#overview contains a web component that uses this location strategy it will lead to paths like some/path#overview(some-web-component:/some-path). This new URL will break the browser-built-in fragment-scrolling.

  • Hash based routing in host application
    If the host application of your web component is using a hash based location strategy (like Angular's built-in HashLocationStrategy) then the WebComponentLocationStrategy cannot be used since it would interfere with the host application's routing. In this case it is advised to use the NoopLocationStrategy (see below) for your web component that doesn't change the URL at all. Another solution would be to ask the host application to change to a path based location strategy.

  • Someone else owns the hash
    If the web component that uses the WebComponentLocationStrategy lives on the same page with another element that wants to take control over the hash (e.g. another web component that uses a different strategy or some other element/script) then they might get in each other's way. In this case it's better to use the NoopLocationStrategy in your web component (see below).

3.2. Noop Location Strategy

Apart from the WebComponentLocationStrategy, we also provide another location strategy called NoopLocationStrategy that does not change the URL at all. This is useful if you find that the WebComponentLocationStrategy leads to conflicts with the host application of your web component.

If you want to use the NoopLocationStrategy you can pass the flag --use-noop-location-strategy to your generator call. Alternatively, you can also set the useNoopLocationStrategy flag in the executor options of your project.json:

{
  "...": "...",
  "options": {
    "useNoopLocationStrategy": true
  }
}

4. How to Deal with Assets in Building Blocks

Building Blocks that include assets (e.g. images) need to use the talyNormalizeUrl pipe (documentation) in order to work properly inside a web component. Otherwise, the browser will try to load the assets from the hosting application instead of the web component server.

If you notice missing assets in your web component, make sure that the used Building Blocks are using the talyNormalizeUrl pipe to normalize their asset URLs.

💡 This feature is only supported for Retail journeys.

TALY provides the ability to link back to another page from two different places throughout the journey. It is possible to display a back link in the upper part of the TALY Frame stage and/or to navigate to the same URL when clicking on the "Next" button on the last page of the journey. This feature is mostly intended to navigate back to an external link from which the journey was started, but it could be used for any other purpose.

To enable this feature, the host application needs to provide the value(s) to use for the back links. See the below subsection for an AEM integration example. If you are using a TALY generated web component without AEM and need to configure back links, please reach out to us.

For the back link in the TALY Frame stage, the link can be disabled on the page level using the hideBackLink flag inside the page configuration for the journey:

// Page configuration
{
  "id": "my-page-c",
  "blocks": [{ "...": "..." }],
  "title": {
    "headline": "Page C is good",
    "showAsStage": true,
    "subline": "Really good",
    "hideBackLink": true
  }
}

Additionally, and likewise only applicably to the stage back link, a PFE Service Activator can be executed when clicking on the back link, before redirecting. TALY will prevent the redirect if the Service Activator call fails. Here is an example of how to configure this in your journey configuration:

{
  "...": "...",
  "frame": {
    "stage": {
      "backLink": {
        "onClickServiceActivator": "users"
      }
    },
    "...": "..."
  },
  "...": "..."
}

5.1. AEM Integration

For this feature to work with AEM pages, the back link configuration needs to be added to the customconfiguration object via the AEM user interface. More precisely, a key called backLinkConfig needs to be set to a value that implements the BackLinkConfiguration interface defined in TALY. This is an example of this value (note the use of double quotes preceded by a backslash, this is required for the data to be extracted from customconfiguration at runtime).

{\"backLinks\": [ {\"path\": \"dashboard\", \"stageLinklabel\": \"Go Back to Dashboard\", \"nextButtonLabel\": \"Go to Dashboard\"}, {\"path\": \"localhost:4000\", \"stageLinkLabel\": \"Back to example app\"} ], \"default\": {\"path\": \"https://allianz.com\", \"stageLinkLabel\": \"Default\" }}

TALY reads the data from the root element and processes it. The functionality is based on the value of document.referrer. In a nutshell, it does the following:

  • If the referrer matches one of the items provided in backLinks via customconfiguration, that item is used for the back link.
  • If the referrer is empty, or it does not match any of the configuration backLinks, if provided it takes the default entry from customconfiguration.
  • If no entry applies, the back link feature is fully disabled.
  • If an entry applies, depending on the content of that entry, any of the two parts of the back link feature can be disabled for the whole journey. If the entry does not provide a value for the stageLinkLabel field, the back link will not be displayed in the TALY Frame stage. The same applies to the "Next" button on the last page of the journey. If the field nextButtonLabel is not provided, the back link feature is disabled for that button, and the button will be hidden unless it is explicitly configured to be shown in the PFE configuration.

The host application needs to pass the configuration data to the web component in a way that allows the corresponding adapter to read it. An example is the AEM integration, explained in the previous section.

6. Web Component State API

TALY-based customer journey web components provide the possibility to get and restore their state from outside.

6.1. Getting the Current State of a Customer Journey

The current PFE state can be retrieved via the getState() method provided in the web component element. For example:

const webComponent = // get the element reference from the DOM, for example by the tag name
const currentState = webComponent.getState();

6.2. Initializing a Customer Journey with a State

The host application can provide an initial state for the customer journey. This state is then restored when the customer journey starts up and the journey continues where it left off.

The journey can be initialized with a state like this:

<my-taly-app initial-state='{"state": "value"}'> </my-taly-app>

For Angular hosts, the initial state can alternatively be passed to the journey via dynamic binding:

// Component class

// Imports and component decorator...

export class AppComponent {
  webComponentInitialState = '{ "state": "value" }';
}
<!-- Component template -->
<my-taly-app [initialState]="webComponentInitialState"> </my-taly-app>

In this case, the bound property can be a JSON string or a promise that eventually resolves to a JSON string.

💡 Keep in mind that this feature is incompatible with other PFE state initialization strategies, like web component inputs added to the journey configuration or PFE state updates performed by TALY plugin modules during their initialization. This is the intended behavior, since the initial state feature is meant to fully restore the PFE state from a previous session, and no other PFE state initializations should happen in parallel to that.

6.3. More Fine-Grained Web Component Inputs

Instead of providing the entire state as shown above, TALY-generated web components can be configured to receive individual values from their host application. This has to be configured ahead of generating the web component in the pages.json file, like so:

// pages.jsonc
{
  // other configuration
  "webcomponent": {
    "inputs": [
      {
        // name of the input that will be available on the web component
        "name": "customer-name",
        // the path where the received value will be stored in the web component's PFE store
        "storeExpression": "$.fromHost.customerName"
      }
    ]
  }
}

The hosting application can then provide values for these inputs via regular HTML attributes, like so:

<my-web-component customer-name="John Doe"></my-web-component>

results matching ""

    No results matching ""