Angular

Use Flipswitch feature flags in Angular with directives and reactive services

The OpenFeature Angular SDK provides Angular-specific directives and an injectable service on top of the Flipswitch web provider. Flags evaluate client-side and update automatically when values change via SSE.

See the JavaScript SDK for full provider configuration (polling fallback, offline support, etc.).

Requirements

  • Angular 16+

Installation

npm install @flipswitch-io/web-provider @openfeature/angular-sdk
yarn add @flipswitch-io/web-provider @openfeature/angular-sdk
pnpm add @flipswitch-io/web-provider @openfeature/angular-sdk

@openfeature/angular-sdk re-exports everything from @openfeature/web-sdk. Import all OpenFeature types from @openfeature/angular-sdk directly.

Quick Start

Module Setup

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OpenFeatureModule } from '@openfeature/angular-sdk';
import { FlipswitchWebProvider } from '@flipswitch-io/web-provider';

@NgModule({
  imports: [
    CommonModule,
    OpenFeatureModule.forRoot({
      provider: new FlipswitchWebProvider({
        apiKey: 'YOUR_API_KEY',
      }),
    }),
  ],
})
export class AppModule {}

Standalone Setup

import { bootstrapApplication } from '@angular/platform-browser';
import { importProvidersFrom } from '@angular/core';
import { OpenFeatureModule } from '@openfeature/angular-sdk';
import { FlipswitchWebProvider } from '@flipswitch-io/web-provider';

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(
      OpenFeatureModule.forRoot({
        provider: new FlipswitchWebProvider({
          apiKey: 'YOUR_API_KEY',
        }),
      })
    ),
  ],
});

Template Directives

The SDK provides structural directives for conditional rendering directly in templates. Directives update automatically when flag values change.

Boolean Flags

<div *booleanFeatureFlag="'dark-mode'; default: false">
  Dark mode is enabled!
</div>

With an else template:

<div *booleanFeatureFlag="'dark-mode'; default: false; else: lightMode">
  Dark mode is enabled!
</div>
<ng-template #lightMode>
  Light mode is active.
</ng-template>

String Flags

Use value: to match against a specific string:

<div *stringFeatureFlag="'theme'; value: 'dark'; default: 'light'; else: otherTheme">
  Dark theme matched!
</div>
<ng-template #otherTheme>
  Using a different theme.
</ng-template>

Display the flag value directly by omitting value::

<div *stringFeatureFlag="'welcome-message'; default: 'Hello!'; let message">
  {{ message }}
</div>

Number Flags

<div *numberFeatureFlag="'max-items'; value: 50; default: 10; let count; let details = evaluationDetails">
  Showing {{ count }} items (reason: {{ details.reason }})
</div>

Loading States

Show different content while the provider initializes or reconciles after a context change:

<div *booleanFeatureFlag="'new-feature'; default: false;
  initializing: loading;
  reconciling: updating;
  else: disabled">
  Feature is enabled!
</div>
<ng-template #loading>Loading flags...</ng-template>
<ng-template #updating>Updating...</ng-template>
<ng-template #disabled>Feature is disabled.</ng-template>

FeatureFlagService

For flag evaluation in component code, inject FeatureFlagService. All methods return Observables that automatically emit new values when flags or context change.

import { Component } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { FeatureFlagService } from '@openfeature/angular-sdk';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [AsyncPipe],
  template: `
    @if ((darkMode$ | async)?.value) {
      <div class="dark">Dark mode</div>
    }
  `,
})
export class DashboardComponent {
  darkMode$ = this.flagService.getBooleanDetails('dark-mode', false);
  welcome$ = this.flagService.getStringDetails('welcome-message', 'Hello!');
  limit$ = this.flagService.getNumberDetails('max-items', 10);

  constructor(private flagService: FeatureFlagService) {}
}

With Signals

Convert to Angular signals using toSignal:

import { Component } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FeatureFlagService } from '@openfeature/angular-sdk';

@Component({
  selector: 'app-feature',
  template: `
    @if (darkMode()?.value) {
      <div class="dark">Dark mode</div>
    }
  `,
})
export class FeatureComponent {
  darkMode = toSignal(this.flagService.getBooleanDetails('dark-mode', false));

  constructor(private flagService: FeatureFlagService) {}
}

Evaluation Context

Initial Context

Set context when configuring the module:

OpenFeatureModule.forRoot({
  provider: new FlipswitchWebProvider({ apiKey: 'YOUR_API_KEY' }),
  context: {
    targetingKey: 'user-123',
    email: 'user@example.com',
    plan: 'premium',
  },
})

Or use a factory function:

OpenFeatureModule.forRoot({
  provider: new FlipswitchWebProvider({ apiKey: 'YOUR_API_KEY' }),
  context: () => loadContextFromStorage(),
})

Updating Context

Update context at runtime via the OpenFeature API. All directives and service observables re-evaluate automatically:

import { OpenFeature } from '@openfeature/angular-sdk';

OpenFeature.setContext({
  targetingKey: 'user-456',
  email: 'other@example.com',
});

Real-Time Updates

Directives and FeatureFlagService observables update automatically when flag values change via SSE. Both respond to PROVIDER_CONFIGURATION_CHANGED events emitted by the Flipswitch provider.

You can disable automatic updates per-directive or per-service call:

<div *booleanFeatureFlag="'feature'; default: false;
  updateOnConfigurationChanged: false;
  updateOnContextChanged: false">
  This won't update automatically.
</div>
this.flagService.getBooleanDetails('feature', false, undefined, {
  updateOnConfigurationChanged: false,
  updateOnContextChanged: false,
});

Domain-Scoped Providers

Use multiple providers for different parts of your application:

OpenFeatureModule.forRoot({
  provider: new FlipswitchWebProvider({ apiKey: 'DEFAULT_KEY' }),
  domainBoundProviders: {
    checkout: new FlipswitchWebProvider({ apiKey: 'CHECKOUT_KEY' }),
  },
})

Reference the domain in templates or service calls:

<div *booleanFeatureFlag="'express-checkout'; default: false; domain: 'checkout'">
  Express checkout enabled!
</div>
this.flagService.getBooleanDetails('express-checkout', false, 'checkout');

On this page