# Angular

Source: https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/angular/index.html

## Overview

The [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library provides functions, modules, and services for the io.Connect JavaScript libraries - [`@interopio/browser`](https://www.npmjs.com/package/@interopio/browser) and [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform), if you are working on an **io.Connect Browser** project, or [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop), if you are working on an **io.Connect Desktop** project.

The following examples use the [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop) library. The [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library enables you to start using io.Connect features in your Angular apps idiomatically in the context of the Angular framework.

## Installation

The following table describes the Angular versions supported by the different major versions of the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library:

| Library Version | Supported Angular Versions |
|-----------------|----------------------------|
| `@interopio/ng` 6.0 | Supports Angular versions 19 and 20. Supports both standalone components and modules. Provides the `provideIoConnect()` function for configuring and initializing the `@interopio/ng` library in Angular apps that use standalone components. |
| `@interopio/ng` 5.0 | Supports all Angular versions up to and including 20. Supports both standalone components and modules. |

This package should be used only in Angular apps. If you have created your app with the Angular CLI, then you don't need to take any additional steps. Otherwise, make sure to install the Angular peer dependencies of `@interopio/ng` described in the `package.json` file of the library.

To install the `@interopio/ng` library, execute the following command:

```cmd
npm install @interopio/ng
```

For the library to operate properly in your interop-enabled app, you must also install the following optional peer dependency:

- The [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop) library.

## Library Features

The [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library exposes the following important features:

| Library Feature | Description |
|-----------------|-------------|
| `IOConnectNg` | Angular module for configuring and initializing the library when using modules. |
| `IOConnectStore` | Angular service that provides access to the io.Connect APIs. |
| `provideIoConnect()` | Function for configuring and initializing the library when using standalone components. This function is available in `@interopio/ng` 6.0 and later. |

> ⚠️ *Note that if the initialization of the `@interopio/ng` library fails for any reason (invalid configuration, missing factory function, connection problems, or initialization timeout), your app will still initialize.*

### Settings

The [`provideIoConnect()`](#library_features-provideioconnect) function and the `forRoot()` method of the [`IOConnectNg`](#library_features-ioconnectng_module) module accept an `IOConnectNgSettings` object for initializing the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library.

The `IOConnectNgSettings` object has the following signature:

```typescript
interface IOConnectNgSettings {
    holdInit?: boolean;
    browser?: {
        factory?: IOConnectBrowserFactoryFunction;
        config?: IOConnectBrowser.Config;
    };
    browserPlatform?: {
        factory?: IOConnectBrowserPlatformFactoryFunction;
        config?: IOConnectBrowserPlatform.Config;
    };
    desktop?: {
        factory?: IODesktopFactoryFunction;
        config?: IOConnectDesktop.Config;
    };
}
```

The following table describes the properties of the `IOConnectNgSettings` object:

| Property | Type | Description |
|----------|------|-------------|
| `browser` | `object` | Object with two properties: `config` and `factory`. The `config` property accepts a configuration object for the [`@interopio/browser`](https://www.npmjs.com/package/@interopio/browser) library. The `factory` property accepts the factory function exposed by the `@interopio/browser` library. You should define this object if your app is a Browser Client app in the context of **io.Connect Browser**. |
| `browserPlatform` | `object` | Object with two properties: `config` and `factory`. The `config` property accepts a configuration object for the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library with a required `licenseKey` property. The `factory` property accepts the factory function exposed by the `@interopio/browser-platform` library. You should define this object if your app is a Main app in the context of **io.Connect Browser**. |
| `desktop` | `object` | Object with two properties: `config` and `factory`. The `config` property accepts a configuration object for the [`@interopio/desktop`](https://www.npmjs.com/package/@interopio/desktop) library used in **io.Connect Desktop**. The `factory` property accepts the factory function exposed by the `@interopio/desktop` library. You should define this object if your app is an **io.Connect Desktop** app. |
| `holdInit` | `boolean` | If `true` (default), Angular will wait for the io.Connect factory function to resolve before bootstrapping your first component. |

> ⚠️ *Note that you can't define a `browser` and `browserPlatform` property at the same time, but you can define one of them together with `desktop`. This is useful if you want your app to have different initialization characteristics in **io.Connect Browser** and **io.Connect Desktop**.*

All properties are optional, but it's recommended that you provide the factory functions explicitly. If no factory functions are provided, the library will try to select the appropriate function injected in the global `window` object.

The initialization of the `@interopio/ng` library is asynchronous and therefore may take anywhere from a few milliseconds to a couple of seconds. There are two main situations in which setting `holdInit` to `true` (default) or `false` will benefit your project:

- `holdInit: false` - If the io.Connect functionalities play only a supporting role in your project, rather than being an essential part of it, it's recommended that you set `holdInit` to `false`. This way, your app won't have to wait for the io.Connect library to initialize in order to be able to function properly. You can use the `IOConnectStore` service to get notified when the `@interopio/ng` library is ready.

- `holdInit: true` - If the io.Connect functionalities are a critical part your project, then it's recommended to leave `holdInit` set to `true`. This way, Angular will wait for the io.Connect factory function to resolve before bootstrapping your first component. This will spare you the need to check whether the `@interopio/ng` library is available every time you want to use it in your app. As a negative result to this approach, when your users load the app, they will keep seeing a blank screen up until the first component has been bootstrapped. Of course, you can solve this by providing a loader animation as soon as your app is accessed.

### provideIoConnect()

The `provideIoConnect()` function is responsible initializing the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library when using standalone components. You must use the `provideIoConnect()` function in the `app.config.ts` file of your app. The `provideIoConnect()` function accepts an [`IOConnectNgSettings`](#library_features-settings) object for configuring the library.

The following example demonstrates how to initialize the `@interopio/ng` library when using standalone components:

```typescript
import { ApplicationConfig } from "@angular/core";
import { provideIoConnect } from "@interopio/ng";
import IODesktop, { IOConnectDesktop } from "@interopio/desktop";

const config: IOConnectDesktop.Config = {
    // Optional configuration.
};

export const appConfig: ApplicationConfig = {
    providers: [
        // Configuring and initializing the io.Connect Desktop library.
        provideIoConnect({
            desktop: {
                factory: IODesktop,
                config
            }
        })
    ]
};
```

### IOConnectNg Module

The `IOConnectNg` module is responsible for initializing the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library when using modules. You must import the `IOConnectNg` module only once for the entire app in the root module by using the `forRoot()` method. The `forRoot()` method accepts an [`IOConnectNgSettings`](#library_features-settings) object for configuring the library.

The following example demonstrates how to initialize the `@interopio/ng` library when using modules:

```javascript
import { IOConnectNg } from "@interopio/ng";
import IODesktop from "@interopio/desktop";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        IOConnectNg.forRoot({
            desktop: {
                factory: IODesktop
            }
        })
    ],
    providers: [],
    bootstrap: [AppComponent]
});

export class AppModule { };
```

### IOConnectStore Service

The `IOConnectStore` service is used to obtain the `io` object which exposes the io.Connect API. This service can also notify you when the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library has been initialized and enables you to check for any initialization errors.

Example of creating an `IOConnectStore` service:

```typescript
import { Injectable } from "@angular/core";
import { IOConnectStore } from "@interopio/ng";

@Injectable()
export class IOConnectService {
    constructor(private readonly ioConnectStore: IOConnectStore) { }
}
```

The `IOConnectStore` service offers the following methods:

| Method | Description |
|--------|-------------|
| `getInitError()` | Returns an initialization error object from the io.Connect factory function or `undefined`. |
| `getIOConnect()` | Returns the io.Connect API object. If needed, it's up to you to cast the returned object to the respective type (either `IOConnectDesktop.API` or `IOConnectBrowser.API` depending on the used io.Connect JavaScript library). |
| `ready()` | Returns an `Observable`. Subscribe to it to get notified when the `@interopio/ng` library has been initialized. If the initialization fails, you will receive an object with an `error` property, otherwise the object will be empty. This is particularly useful if you set `holdInit` to `false` when initializing the library, because you need to make sure that the io.Connect library is ready for use before accessing any of its APIs. |

You can inject the service in the components that need it and access the io.Connect API from the object returned by `getIOConnect()`. If you prefer handling asynchronous actions with `Observables`, then this service is the perfect place to wrap the methods you want to use in `Observables`.

## Usage

The following examples demonstrate initializing and using the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library.

### Initialization

#### Standalone Components

In `app.config.ts`:

```typescript
import { ApplicationConfig } from "@angular/core";
import { provideIoConnect } from "@interopio/ng";
import IODesktop, { IOConnectDesktop } from "@interopio/desktop";

const config: IOConnectDesktop.Config = {
    // Optional configuration.
};

export const appConfig: ApplicationConfig = {
    providers: [
        // Configuring and initializing the io.Connect Desktop library.
        provideIoConnect({
            desktop: {
                factory: IODesktop,
                config
            }
        })
    ]
};
```

In `main.ts`:

```typescript
import { bootstrapApplication } from "@angular/platform-browser";
import { appConfig } from "./app/app.config";
import { App } from "./app/app";

bootstrapApplication(App, appConfig);
```

#### Modules

The following example demonstrates initializing the `@interopio/ng` library in apps that use Angular versions 15 and later.

In `app.config.ts`:

```typescript
import { ApplicationConfig, importProvidersFrom } from "@angular/core";
import { IOConnectNg } from "@interopio/ng";
import IODesktop, { IOConnectDesktop } from "@interopio/desktop";

const config: IOConnectDesktop.Config = {
    // Optional configuration.
};

export const appConfig: ApplicationConfig = {
    providers: [
        importProvidersFrom(
            IOConnectNg.forRoot({
                desktop: {
                    factory: IODesktop,
                    config
                }
            })
        )
    ]
};
```

The following example demonstrates initializing the `@interopio/ng` library in apps that use Angular versions 14 and older.

In `app.module.ts`:

```typescript
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";
import { IOConnectNg } from "@interopio/ng";
import IODesktop, { IOConnectDesktop } from "@interopio/desktop";

const config: IOConnectDesktop.Config = {
    // Optional configuration.
};

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        IOConnectNg.forRoot({
            desktop: {
                factory: IODesktop,
                config
            }
        })
    ],
    providers: [],
    bootstrap: [AppComponent]
});

export class AppModule { };
```

### Consuming io.Connect APIs

Inject the `IOConnectStore` service in your component or service of choice in order to use the io.Connect API. It's recommended that you create your own Angular service that injects `IOConnectStore` and exposes only the functionality your app needs.

When initializing the [`@interopio/ng`](https://www.npmjs.com/package/@interopio/ng) library, you can use the `holdInit` property to configure whether the Angular framework must wait for the io.Connect factory function to resolve before bootstrapping your first component. Depending on this setting, you can use the `IOConnectStore` service in different ways. The following sections demonstrate both cases.

- #### holdInit: true

Creating the service:

```typescript
import { Injectable } from "@angular/core";
import { IOConnectStore } from "@interopio/ng";

@Injectable()
export class IOConnectService {

    constructor(private readonly ioConnectStore: IOConnectStore) { }

    public get ioConnectAvailable() {
        return !this.ioConnectStore.getInitError();
    }

    public registerMethod(name: string, callback: () => void): Promise<void> {
        if (!this.ioConnectAvailable) {
            return Promise.reject("io.Connect wasn't initialized.");
        }
        return this.ioConnectStore.getIOConnect().interop.register(name, callback);
    }
}
```

Using the service:

```typescript
import { Component, OnInit } from "@angular/core";
import { IOConnectService } from "./my-io-connect-service";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {

    constructor(private ioConnectService: IOConnectService) { }

    public ngOnInit(): void {
        if (!this.ioConnectService.ioConnectAvailable) {
            // There has been an error during the io.Connect initialization.
            return;
        }
        // io.Connect has been initialized without errors and is ready to use.
    }
}
```

If you set `holdInit` to `true` (default), you can be sure that everywhere you inject the `IOConnectStore` service, the respective properties will be initialized and set. This is very convenient, because you don't have to subscribe and wait for an event in order to use the io.Connect APIs. However, you do need to always check if there is an initialization error by using the `getInitError()` method. If the io.Connect factory function throws an error, your app won't crash, but io.Connect won't be available and the value returned by `getInitError()` will be set to the respective error object during initialization.

- #### holdInit: false

Creating the service:

```typescript
import { Injectable } from "@angular/core";
import { IOConnectStore } from "@interopio/ng";

@Injectable()
export class IOConnectService {

    constructor(private readonly ioConnectStore: IOConnectStore) { }

    public ready() {
        return this.ioConnectStore.ready;
    }

    public registerMethod(name: string, callback: () => void): Promise<void> {
        return this.ioConnectStore.getIOConnect().interop.register(name, callback);
    }
}
```

Using the service:

```typescript
import { Component, OnInit } from "@angular/core";
import { IOConnectService } from "./my-io-connect-service";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {

    constructor(private ioConnectService: IOConnectService) { }

    public ngOnInit(): void {
        // Show the loader.
        this.ioConnectService
            .ready()
            .subscribe((ioConnectStatus) => {
                if (ioConnectStatus.error) {
                    // Hide the loader.
                    // io.Connect isn't available.
                    return;
                }
                // Hide the loader.
                // io.Connect is ready, continue with your logic.
            })
    }
}
```

As you can see, this approach requires a little bit more code, but it gives you an easy way to provide pleasant user experience while io.Connect is initializing, handle gracefully any initialization errors, and when the initialization resolves normally, you don't need to check the error object as in the previous example.

## App Definition

To add your Angular app to the [io.Connect launcher](https://docs.interop.io/desktop/capabilities/launcher/index.md), you must create a JSON [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) file for it. Place this file in the `<installation_location>/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/apps` folder where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`).

The following is an example definition of an Angular app:

```json
{
    "name": "my-app",
    "title": "My App",
    "type": "window",
    "details": {
        "url": "https://example.com/my-app/",
        "mode": "tab",
        "width": 500,
        "height": 400
    }
}
```

The `"name"`, `"type"`, and `"url"` properties are required and `"type"` must be set to `"window"`. The `"url"` property points to the location of the web app.

The value of the `"title"` property will be used as a name for the app in the io.Connect launcher and as a window title if the web app doesn't have a document title.

> ℹ️ *For more details on defining apps, see the [Developers > Configuration > Application](https://docs.interop.io/desktop/developers/configuration/application/index.md) section.*

## io.Connect JavaScript Capabilities

Once the `@interopio/ng` library has been initialized, your app has access to all io.Connect functionalities. For more detailed information on the different io.Connect capabilities and APIs, see the following sections:

- [Shared Contexts](https://docs.interop.io/desktop/capabilities/data-sharing/shared-contexts/javascript/index.md)
- [Channels](https://docs.interop.io/desktop/capabilities/data-sharing/channels/javascript/index.md)
- [Interop](https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.md)
- [Intents](https://docs.interop.io/desktop/capabilities/data-sharing/intents/javascript/index.md)
- [Pub/Sub](https://docs.interop.io/desktop/capabilities/data-sharing/pub-sub/javascript/index.md)
- [Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md)
- [Workspaces](https://docs.interop.io/desktop/capabilities/windows/workspaces/javascript/index.md)
- [Layouts](https://docs.interop.io/desktop/capabilities/windows/layouts/javascript/index.md)
- [Themes](https://docs.interop.io/desktop/capabilities/windows/themes/javascript/index.md)
- [Modals](https://docs.interop.io/desktop/capabilities/windows/modals/javascript/index.md)
- [App Management](https://docs.interop.io/desktop/capabilities/app-management/javascript/index.md)
- [App Preferences](https://docs.interop.io/desktop/capabilities/app-preferences/javascript/index.md)
- [Notifications](https://docs.interop.io/desktop/capabilities/notifications/javascript/index.md)
- [Search](https://docs.interop.io/desktop/capabilities/search/javascript/index.md)
- [Interception](https://docs.interop.io/desktop/capabilities/interception/javascript/index.md)
- [Hotkeys](https://docs.interop.io/desktop/capabilities/more/apis/index.md#hotkeys)
- [Displays](https://docs.interop.io/desktop/capabilities/more/apis/index.md#displays)
- [Logging](https://docs.interop.io/desktop/capabilities/logging/javascript/index.md)

## API Reference

For a complete list of the available JavaScript APIs, see the [io.Connect JavaScript reference documentation](https://docs.interop.io/desktop/reference/javascript/io.connect%20desktop/index.md).
