npm package: @impartner/angular-apps
Description: This package contains [Angular](https://angular.io/) components, services, and typings to facilitate development and integration of Angular web components written for Impartner host applications.
Author: Impartner
Latest version: 4.0.0

# `@impartner/angular-apps`

This package contains [Angular](https://angular.io/) components, services, and typings to facilitate development and integration of Angular web components written for Impartner host applications.

## Dependencies

In addition to core dependencies on Angular and RxJS, the package also depends on [`@impartner/angular-sdk`](https://www.npmjs.com/package/@impartner/angular-sdk/), [`@impartner/design-components`](https://www.npmjs.com/package/@impartner/design-components/), [`i18next`](https://www.npmjs.com/package/i18next/), and [`angular-i18next`](https://www.npmjs.com/package/angular-i18next/). These peer dependencies may or may not be optional, depending on which package modules and entrypoints are used. Please refer to the below table to see which versions are supported or targeted. (Note: Not all versions of `@impartner/angular-apps` are listed - only those with changes to package peer dependencies.)

| @impartner/angular-apps | Angular  | @impartner/angular-sdk | @impartner/design-components<sup>1</sup> | i18next<sup>2</sup> | angular-i18next<sup>2</sup> |
| ----------------------- | -------- | ---------------------- | ---------------------------------------- | ------------------- | --------------------------- |
| 1.1.0                   | ^14.2.0  | ^1.0.0                 | ^1.0.0                                   | ^21.10.0            | ^14.2.0                     |
| 1.2.1                   | ^14.2.0  | ^1.1.0                 | ^1.0.0                                   | ^21.10.0            | ^14.2.0                     |
| 1.2.2                   | ^14.2.0  | ^1.2.0                 | ^1.1.0                                   | ^21.10.0            | ^14.2.0                     |
| 2.0.0                   | >=17.0.4 | ^2.0.0                 | ^2.0.0                                   | ^23.7.0             | ^17.0.0                     |
| 3.0.0                   | >=18.2.0 | ^3.0.0                 | ^3.0.0                                   | ^23.7.0             | ^18.0.0                     |
| 4.0.0                   | >=20.2.4 | ^4.0.0                 | ^4.0.0                                   | ^25.4.0             | ^20.0.0                     |

Notes:

1. `@impartner/design-components` is only required when importing from the `@impartner/angular-apps/local-dev` entrypoint.
2. `i18next` and `angular-i18next` are only required when importing from the `@impartner/angular-apps/i18n` entrypoint.

## Installation

1. Add the `@impartner/angular-sdk` and `@impartner/angular-apps` dependencies from npm.
2. Optional: Install optional peer dependencies now, if desired:
   - If using elements from the `@impartner/angular-apps/local-dev` entrypoint, add [`@impartner/design-components`](https://www.npmjs.com/package/@impartner/design-components/) from npm, including its own peer dependencies; refer to that package's documentation for further details.
   - If using elements from the `@impartner/angular-apps/i18n` entrypoint, add [`i18next`](https://www.npmjs.com/package/i18next/), and [`angular-i18next`](https://www.npmjs.com/package/angular-i18next/) from npm, including their own peer dependencies, if any.

## Contents

This package includes various TypeScript and Angular code elements to assist with different aspects of developing and integrating Angular-based web components with Impartner host applications, and has separated those elements into discrete package entrypoints and modules.

- [Entrypoint: `@impartner/angular-apps/widget`](#entrypoint-impartnerangular-appswidget)
- [Entrypoint: `@impartner/angular-apps/mfe`](#entrypoint-impartnerangular-appsmfe)
- [Entrypoint: `@impartner/angular-apps/i18n`](#entrypoint-impartnerangular-appsi18n)
- [Entrypoint: `@impartner/angular-apps/local-dev`](#entrypoint-impartnerangular-appslocal-dev)

## Entrypoint: `@impartner/angular-apps/widget`

This entrypoint exposes injection tokens, providers, and the root/application `NgModule`s that should be used for Angular-based widget applications running in Impartner host portal applications.

### `AbstractImpartnerWidgetAppModule`

Widget applications must have the root application module ("`AppModule`" by default) extend this abstract class, which is responsible for running appropriate application bootstrapping behavior when importing the [`ImpartnerWidgetModule`](#impartnerwidgetmodule) and [`LocalImpartnerWidgetModule`](#localimpartnerwidgetmodule) modules.

### `ImpartnerWidgetModule`

This module should be imported in the Angular application's **root NgModule** using the `ImpartnerWidgetModule.forRoot(...)` static function, passing the project's `environment` constant and a [`IWidgetAppOptions`](#iwidgetappoptions) value as the required arguments. Once imported, the module will register providers and services appropriate for the specified configuration.

### `IWidgetAppOptions`

| Name                | Description                                                                                                                                                                                                          |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isCustom`          | A boolean value indicating whether or not the MFE is a custom MFE for Impartner host applications.                                                                                                                   |
| `widgetDefinition`  | A singular [`IWidgetDefinition`](#iwidgetdefinition) object declaring the name, type, and Angular components of a widget. **Only provide when `isCustom` is `true`.**                                                |
| `widgetDefinitions` | An array of [`IWidgetDefinition`](#iwidgetdefinition) objects declaring the name, type, and Angular components for a set of widgets that will all be packaged together. **Only provide when `isCustom` is `false`.** |

### `IWidgetDefinition`

| Name             | Description                                                                                                                                                                                                                |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`           | The displayed ("friendly") name of the widget.                                                                                                                                                                             |
| `type`           | A unique type key or API name for the widget.                                                                                                                                                                              |
| `style`          | The particular Impartner stylesheet/theme that should be applied to the widget. This should almost always be `StyleType.ImpartnerHex`.                                                                                     |
| `modeComponents` | Mappings from Impartner portal application modes (`view`, `edit`) to their corresponding Angular component classes and custom element tags when converted to web components (see: [`IWidgetComponent`](#iwidgetcomponent)) |
| `ngModuleType`   | The `NgModule` that exports the Angular components mapped in `modeComponents`.                                                                                                                                             |

### `IWidgetComponent`

| Name              | Description                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `componentType`   | The type reference to an Angular component.                                                           |
| `webComponentTag` | The desired custom element tag to be used when the Angular component is converted to a web component. |

### `BaseWidgetComponent<TConfig, TData = never>`

`BaseWidgetComponent` is a abstract class intended to be extended when developing new widget web components for Impartner portal applications, where `TConfig` is the typing of the widget's configuration object.

This class already has a defined constructor, and as such any subclasses extending it will need to invoke the `super` constructor with the appropriate arguments, including a number of services imported from `@impartner/angular-sdk`, as well as a default value for widget configuration.

Example:

```typescript
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
import { BaseWidgetComponent } from '@impartner/angular-apps';
import {
  IImpartnerLogger,
  IImpartnerRouter,
  IMPARTNER_LOGGER_TOKEN,
  IMPARTNER_ROUTER_TOKEN,
  ImpartnerConfigService
} from '@impartner/angular-sdk';

interface IWidgetConfig {
  ...
}

const DEFAULT_WIDGET_CONFIG: IWidgetConfig = { ... };

@Component({ ... })
export class ExampleWidgetComponent extends BaseWidgetComponent<IWidgetConfig> {
  constructor(
    impartnerConfig: ImpartnerConfigService,
    @Inject(IMPARTNER_LOGGER_TOKEN) impartnerLogger: IImpartnerLogger,
    changeDetectorRef: ChangeDetectorRef
  ) {
    super(
      impartnerConfig,
      impartnerLogger,
      changeDetectorRef,
      DEFAULT_WIDGET_CONFIG
    );
  }
}
```

Components that extend `BaseWidgetComponent` will inherit a number of public and protected properties and methods.

#### Properties

| Name                   | Access         | Description                                                                                                                                                                                                                                                                                                                 |
| ---------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | public (Input) | The unique identifier of the widget. <br/><br/> This input is set by the Impartner host application and should not be modified by component code. <br/><br/> _Type:_ `string \| number`                                                                                                                                     |
| `widgetConfig`         | public (Input) | The value object containing the widget's configuration. <br/> New values set to this property are **merged** on top of the default value provided in the constructor. <br/><br/> This input is set by the Impartner host application and _generally_ should not be modified by component code. <br/><br/> _Type:_ `TConfig` |
| `data`                 | public (Input) | Optional additional information or configuration belonging to the widget. <br/><br/> This input is set by the Impartner host application and _generally_ should not be modified by component code. <br/><br/> _Type:_ `TData \| undefined`                                                                                  |
| `localeCode`           | public (Input) | The current locale code at the time of the widget's initial rendering. <br/><br/> This input is set by the Impartner host application and should not be modified by component code. <br/><br/> _Type:_ `string \| undefined`                                                                                                |
| `revision`             | public (Input) | The numbered revision or iteration of the rendered widget and its surrounding page. <br/><br/> This input is set by the Impartner host application and should not be modified by component code. <br/><br/> _Type:_ `number \| undefined`                                                                                   |
| `isDraft`              | public (Input) | The draft state of the rendered widget and its surrounding page. <br/><br/> This input is set by the Impartner host application and should not be modified by component code. <br/><br/> _Type:_ `boolean \| undefined`                                                                                                     |
| `localization`         | public (Input) | A key-value map of locale codes to key-value maps of localization tokens and corresponding text, generally configured during page editing. <br/><br/> This input is set by the Impartner host application and should _generally_ not be modified by component code. <br/><br/> _Type:_ `ILocalesMap \| undefined`           |
| `onDestroy$`           | protected      | An observable that will emit and complete during component destruction. <br/><br/> _Type:_ `Observable<void>`                                                                                                                                                                                                               |
| `_impartnerConfig`     | protected      | An instance of `ImpartnerConfigService`. <br/><br/> _Type:_ `ImpartnerConfigService`                                                                                                                                                                                                                                        |
| `_impartnerLogger`     | protected      | An instance of `IImpartnerLogger`. <br/><br/> _Type:_ `IImpartnerLogger`                                                                                                                                                                                                                                                    |
| `_changeDetectorRef`   | protected      | An instance of `ChangeDetectorRef`. <br/><br/> _Type:_ `ChangeDetectorRef`                                                                                                                                                                                                                                                  |
| `_defaultWidgetConfig` | protected      | The default widget configuration. <br/><br/> _Type:_ `TConfig`                                                                                                                                                                                                                                                              |

#### Methods

| Name                 | Access    | Description                                                                                                                                                                                                       |
| -------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_onSetWidgetConfig` | protected | An overrideable method that will be invoked when the `widgetConfig` property setter is successully updates the config value. Override this method if additional logic needs to be run after configuration is set. |

### `BaseWidgetEditComponent<TConfig, TData = never>`

`BaseWidgetEditComponent` is a abstract class intended to be extended when developing the "edit mode" experiences of new widget web components for Impartner portal applications, where `TConfig` is the typing of the widget's configuration object.

This class already has a defined constructor, and as such any subclasses extending it will need to invoke the `super` constructor with the appropriate arguments, including a number of services imported from `@impartner/angular-sdk`, as well as a default value for widget configuration.

Example:

```typescript
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
import { BaseWidgetEditComponent } from '@impartner/angular-apps';
import {
  IImpartnerLogger,
  IImpartnerRouter,
  IMPARTNER_LOGGER_TOKEN,
  IMPARTNER_ROUTER_TOKEN,
  ImpartnerConfigService,
  ImpartnerEventBusService
} from '@impartner/angular-sdk';

interface IWidgetConfig {
  ...
}

const DEFAULT_WIDGET_CONFIG: IWidgetConfig = { ... };

@Component({ ... })
export class ExampleWidgetEditComponent extends BaseWidgetEditComponent<IWidgetConfig> {
  constructor(
    impartnerEventBus: ImpartnerEventBusService,
    impartnerConfig: ImpartnerConfigService,
    @Inject(IMPARTNER_LOGGER_TOKEN) impartnerLogger: IImpartnerLogger,
    changeDetectorRef: ChangeDetectorRef
  ) {
    super(
      impartnerEventBus,
      impartnerConfig,
      impartnerLogger,
      changeDetectorRef,
      DEFAULT_WIDGET_CONFIG
    );
  }
}
```

Components that extend `BaseWidgetEditComponent` will inherit a number of public and protected properties and methods, including all those inherited from the base class `BaseWidgetComponent`.

#### Methods

| Name                           | Access | Description                                                                                                                                                                                                                 |
| ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `emitUpdatedWidgetConfigEvent` | public | `emitUpdatedWidgetConfigEvent(newConfig: TConfig) => void` <br/> Invoke this method when the host Impartner portal application should be notified of and save a new configuration value for the widget.                     |
| `emitUpdatedWidgetDataEvent`   | public | `emitUpdatedWidgetDataEvent(newData: TData) => void` <br/> Invoke this method when the host Impartner portal application should be notified of and save a new widget data value for the widget.                             |
| `emitUpdatedLocalizationEvent` | public | `emitUpdatedLocalizationEvent(newLocalization: ILocalesMap) => void` <br/> Inoke this method when the host Impartner portal application should be notified of and save new user-defined localization values for the widget. |

## Entrypoint: `@impartner/angular-apps/mfe`

This entrypoint exposes injection tokens, providers, and the root/application `NgModule`s that should be used for Angular-based micro frontend ("MFE") applications running in Impartner host applications.

### `AbstractImpartnerMicroFrontEndAppModule`

MFE applications must have the root application module ("`AppModule`" by default) extend this abstract class, which is responsible for running appropriate application bootstrapping behavior when importing the [`ImpartnerMicroFrontEndModule`](#impartnermicrofrontendmodule) and [`LocalImpartnerMicroFrontEndModule`](#localimpartnermicrofrontendmodule) modules.

### `ImpartnerMicroFrontEndModule`

This module should be imported in the Angular application's **root NgModule** using the `ImpartnerMicroFrontEndModule.forRoot(...)` static function, passing the project's `environment` constant and an [`IMicroFrontEndAppOptions`](#imicrofrontendappoptions) value as the required arguments. Once imported, the module will register providers and services appropriate for the specified configuration.

### `IMicroFrontEndAppOptions`

| Name               | Description                                                                                        |
| ------------------ | -------------------------------------------------------------------------------------------------- |
| `mfeComponentType` | The type reference for the MFE's main/entry Angular component.                                     |
| `mfeElementTag`    | The desired tag name to be used for the MFE web component's custom browser element.                |
| `isCustom`         | A boolean value indicating whether or not the MFE is a custom MFE for Impartner host applications. |

## Entrypoint: `@impartner/angular-apps/i18n`

This entrypoint exposes a module to provide internationalization ("i18n") capabilities to Angular-based web components running in Impartner host applications.

This entrypoint has peer dependencies that must be present when importing its exposed elements. If not already installed, add [`i18next`](https://www.npmjs.com/package/i18next/), and [`angular-i18next`](https://www.npmjs.com/package/angular-i18next/) from npm with the versions listed in the [Dependencies section](#dependencies), including their own peer dependencies, if any.

### `ImpartnerI18NextModule`

The `ImpartnerI18NextModule` provides Angular directives and services for performing internationalization through [`i18next`](https://i18next.com) and the [`angular-i18next`](https://github.com/Romanchuk/angular-i18next#readme) Angular library. Actual i18n work within Angular projects should use the directives, pipes, and services offered from `angular-i18next`, and full configuration of `i18next` is still allowed, including the usage of plugin modules and settings for aspects like translation sources (eg. local files vs remote HTTP-based services).

`ImpartnerI18NextModule` can be imported as-is to an `NgModule` to import pipes and directives for usage inside other directives and components. In order to setup necessary services and their DI providers, `ImpartnerI18NextModule.forRoot(...)` must be imported in the application's **root NgModule**. `ImpartnerI18NextModule.forRoot(...)` supports all of the configuration options available on `i18next`'s `InitOptions` type, and also accepts providing a collection of [`i18next` plugin modules](https://www.i18next.com/principles/plugins).

In the below example, `ImpartnerI18NextModule` is imported to the application root module, and provides translations from an imported constant `MY_TRANSLATIONS`.

```typescript
import { ImpartnerI18NextModule } from '@impartner/angular-apps/i18n';
import { MY_TRANSLATIONS } from './my-translations';

@NgModule({
  ...
  imports: [
    ...
    ImpartnerI18NextModule.forRoot({
      resources: MY_TRANSLATIONS
    }),
    ...
  ],
  ...
})
export class AppModule { ... }
```

Once imported, `ImpartnerI18NextModule` will initialize `i18next` during application startup, including setting up automatic resolution of rendered language from the host Impartner application.

## Entrypoint: `@impartner/angular-apps/local-dev`

This entrypoint and primary module expose components and services for assisting with the local development and interactive testing of Angular-based widgets and micro frontends ("MFEs") for Impartner host applications, including capabilities for quickly testing different user locale settings, widget configurations, branding colors, and other context normally managed by the Impartner host application.

This entrypoint has peer dependencies that must be present when importing its exposed elements. If not already installed, add [`@impartner/design-components`](https://www.npmjs.com/package/@impartner/design-components/) from npm, including its own peer dependencies; refer to that package's documentation for further details.

### `ImpartnerLocalAppDevModule`

This module should be imported in the Angular application's **root NgModule** using the `ImpartnerLocalAppDevModule.forRoot(...)` static function, passing the project's `environment` constant as the only required argument. Once imported, the module will expose harness components and their necessary services when running in non-production builds.

This module is automatically imported when importing [`LocalImpartnerWidgetModule`](#localimpartnerwidgetmodule) or [`LocalImpartnerMicroFrontEndModule`](#localimpartnermicrofrontendmodule), and it is preferred to use those modules instead of loading this one directly.

```typescript
import { ImpartnerLocalAppDevModule } from '@impartner/angular-apps/local-dev';

@NgModule({
  ...
  imports: [
    ...
    ImpartnerLocalAppDevModule.forRoot(environment)
    ...
  ],
  ...
})
export class AppModule { ... }
```

### `LocalImpartnerWidgetModule`

This is a purpose-made module for facilitating local development of widgets for Impartner portal applications and should be imported in the Angular application's **root NgModule** using the `LocalImpartnerWidgetModule.forRoot(...)` function, passing the project's `environment` constant and optionally passing an [`ILocalDevOptions`](#ilocaldevoptions) value. Once imported, the module will register providers and services appropriate for the specified configuration, including bootstrapping behavior for the local development/testing harness. `LocalImpartnerWidgetModule.forRoot(...)` will also handle importing [`ImpartnerLocalAppDevModule`](#impartnerlocalappdevmodule), so there is no need to manually import that module. Most importantly, the module should only be imported in local development (non-production) builds. As such, a widget application should have a root `AppModule` definition that looks roughly like thus:

```typescript
import { LocalImpartnerWidgetModule } from '@impartner/angular-apps/local-dev';
import { AbstractImpartnerWidgetAppModule, ImpartnerWidgetModule } from '@impartner/angular-apps/widget';

// A IWidgetDefinition value for passing to ImpartnerWidgetModule.forRoot(); specifics will vary by project
import { CUSTOM_WIDGET_DEFINITION } from './custom-widget-definition';

@NgModule({
  declarations: [AppComponent],
  ...
  imports: [
    ...
    ImpartnerWidgetModule.forRoot(environment, {
      isCustom: true,
      widgetDefinition: CUSTOM_WIDGET_DEFINITION
    }),
    environment.production
      ? []
      : LocalImpartnerWidgetModule.forRoot(environment, {
          defaultTenantId: 1,
          languageOptions: [{
            name: 'English',
            display: 'English',
            locale: 'en',
            isDefault: true,
            isActive: true
          }]
        })
    ...
  ],
  ...
})
export class AppModule extends AbstractImpartnerWidgetModule { ... }
```

Once properly imported and configured, update the application's `index.html` file to include the opening and closing tags of the widget harness component inside of the document's `<body>` tags, like below:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- document header tags omitted -->
  </head>
  <body>
    <impartner-widget-demo-harness></impartner-widget-demo-harness>
  </body>
</html>
```

In addition, the `development` configuration for the Angular application will need to include the Impartner Hex stylesheet from `@impartner/design`. See ["Including Necessary Styles for Harnesses"](#including-necessary-styles-for-harnesses) for further instruction.

### `LocalImpartnerMicroFrontEndModule`

This is a purpose-made module for facilitating local development of micro frontends ("MFEs") and should be imported in the Angular application's **root NgModule** using the `LocalImpartnerMicroFrontEndModule.forRoot(...)` function, passing the project's `environment` constant and optionally passing an [`ILocalDevOptions`](#ilocaldevoptions) value. Once imported, the module will register providers and services appropriate for the specified configuration, including bootstrapping behavior for the local development/testing harness. `LocalImpartnerMicroFrontEndModule.forRoot(...)` will also handle importing [`ImpartnerLocalAppDevModule`](#impartnerlocalappdevmodule), so there is no need to import it again. Most importantly, the module should only be imported in local development (non-production) builds. As such, an MFE application should have a root `AppModule` definition that looks roughly like thus:

```typescript
import { LocalImpartnerMicroFrontEndModule } from '@impartner/angular-apps/local-dev';
import { AbstractImpartnerMicroFrontEndAppModule, ImpartnerMicroFrontEndModule } from '@impartner/angular-apps/mfe';

@NgModule({
  declarations: [AppComponent],
  ...
  imports: [
    ...
    ImpartnerMicroFrontEndModule.forRoot(environment, {
      mfeComponentType: AppComponent,
      mfeElementTag: 'um-my-example-app',
      isCustom: true
    }),
    environment.production
      ? []
      : LocalImpartnerMicroFrontEndModule.forRoot(environment, {
          defaultTenantId: 1,
          languageOptions: [{
            name: 'English',
            display: 'English',
            locale: 'en',
            isDefault: true,
            isActive: true
          }]
        })
    ...
  ],
  ...
})
export class AppModule extends AbstractImpartnerMicroFrontEndAppModule { ... }
```

Once properly imported and configured, update the application's `index.html` file to include the opening and closing tags of the harness component inside of the document's `<body>` tags, like below:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- document header tags omitted -->
  </head>
  <body>
    <impartner-mfe-demo-harness></impartner-mfe-demo-harness>
  </body>
</html>
```

In addition, the `development` configuration for the Angular application will need to include the Impartner Hex stylesheet from `@impartner/design`. See ["Including Necessary Styles for Harnesses"](#including-necessary-styles-for-harnesses) for further instruction.

### Including Necessary Styles for Harnesses

In order for the widget and MFE harnesses to display correctly in local/development build scenarios, the `development` configuration for the Angular application will need to include the Impartner Hex stylesheet from `@impartner/design`. To do so, update the project's `angular.json` manifest to include it at build time:

```json
{
  "name": "my-angular-app",
  "projectType": "application",
  ...
  "targets": {
    "build": {
      ...
      "configurations": {
        "production": { ... },
        "development": {
          ...
          "styles": ["node_modules/@impartner/design/css/impartner-hex.css"]
        }
      }
    }
  },
  ...
}
```

It is imperative to **not** import the stylesheet into a component's own stylesheet file - doing so can cause multiple copies of the Impartner Hex stylesheet to be loaded at once when served in the host Impartner application, as it is already the Impartner application's responsibility to load Impartner Hex and other related stylesheet resources.

### `ILocalDevOptions`

| Name              | Description                                                                                                                                                                                                                                                                                                           |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultTenantId` | The pre-populated value of the 'Tenant ID' field in the harness Authentication settings. A number.                                                                                                                                                                                                                    |
| `languageOptions` | The options in the Program Options and Current Language fields in the harness Language settings section. An array of `IAppLanguage`. Overrides default provided languages. If array is empty, default languages are provided. If no default provided in options, the first language in the array becomes the default. |