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-sdkyarn add @flipswitch-io/web-provider @openfeature/angular-sdkpnpm 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');