npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@launchtarqly/launchdarkly-angular

v0.4.1

Published

Angular library for LaunchDarkly feature flags with reactive directives and services

Downloads

15

Readme

LaunchDarkly Angular

A comprehensive Angular library for integrating LaunchDarkly feature flags with reactive directives and services.

NOTE: This library is not officially supported by LaunchDarkly.

Features

  • 🚀 Reactive Directives: Built-in directives for conditional rendering, styling, and event tracking
  • 📊 Real-time Updates: Automatic flag updates without page refresh
  • 🎯 Context Management: Easy user identification and context switching
  • 📈 Event Tracking: Built-in analytics and conversion tracking
  • 🔧 TypeScript Support: Full TypeScript support with comprehensive type definitions

Installation

npm install @launchtarqly/launchdarkly-angular

Quick Start

1. Import the Module

import { APP_INITIALIZER, NgModule, NgZone } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { LaunchDarklyService, LD_SERVICE_CONFIG, LaunchDarklyAngularModule } from '@launchtarqly/launchdarkly-angular';

import { environment } from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    LaunchDarklyAngularModule
  ],
  providers: [
    {
      provide: LD_SERVICE_CONFIG,
      useValue: {
        /* your LaunchDarkly client-side ID */
        clientId: environment.launchDarklyClientId,
        /* context to start with, should be set as early. Avoid using dummy contexts */
        context: { key: 'demo-user', name: 'Demo User' },
        /* LDOptions passed to the LaunchDarkly Client */
        options: { 
          streaming: true
          bootstrap: "localStorage"
        }
      }
    },
    // Prevent a flash of fallback values by waiting for at most 200ms for LaunchDarkly to be ready
    // for angular 17+, use provideAppInitializer(LaunchDarklyService.createAppInitializer(200)) instead
    {
      provide: APP_INITIALIZER,
      useFactory: LaunchDarklyService.createAppInitializer(200),
      deps: [LaunchDarklyService],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

2. Use Directives in Templates

<!-- Conditional rendering -->
<div *ldIf="'new-feature'; fallback: false">New feature content</div>

<!-- Conditional CSS classes -->
<div [ldClassIf]="'premium-features'" [ldClassIfClass]="'premium-user'">
  User content
</div>

<!-- Event tracking -->
<button [ldTrack]="'button-clicked'">Click me</button>

3. Use Service in Components

import { LaunchDarklyService } from '@launchtarqly/launchdarkly-angular';

@Component({...})
export class MyComponent {
  constructor(private ld: LaunchDarklyService) {}

  ngOnInit() {
    this.ld.variation$('new-feature', false).subscribe(enabled => {
      if (enabled) {
        this.showNewFeature();
      }
    });
  }
}

Directives

LdIfDirective

Conditionally renders content based on feature flags.

<!-- Simple boolean flag -->
<div *ldIf="'new-feature'; fallback: false">New feature content</div>

<!-- String flag with specific value -->
<div *ldIf="'user-tier'; fallback: 'basic'; value: 'premium'">Premium content</div>

<!-- Number flag -->
<div *ldIf="'max-items'; fallback: 5; value: 10">Show 10 items</div>

LdFlagDirective

Universal directive for any flag type with template injection.

<!-- String flag with text injection -->
<ng-template [ldFlag]="'welcome-message'" [ldFlagFallback]="'Welcome!'" let-message>
  <h1>{{ message }}</h1>
</ng-template>

LdSwitchDirective

Switch-like conditional rendering for multi-variant flags.

<ng-container [ldSwitch]="'user-tier'" [ldSwitchFallback]="'basic'">
  <ng-template [ldSwitchCase]="'basic'">
    <div>Basic user features</div>
  </ng-template>
  <ng-template [ldSwitchCase]="'premium'">
    <div>Premium user features</div>
  </ng-template>
  <ng-template ldSwitchDefault>
    <div>Unknown user tier</div>
  </ng-template>
</ng-container>

LdClassIfDirective

Conditionally applies CSS classes.

<!-- Apply class when flag is truthy -->
<div [ldClassIf]="'enable-premium-features'" [ldClass]="'premium-user'">
  User content
</div>

<!-- Use a fallback value if initialization fails -->
<div [ldClassIf]="'enable-premium-features'" [ldClassIfFallback]="false" [ldClass]="'premium-user'">
  User content
</div>

<!-- Apply different classes based matching a specific value -->
<div [ldClassIf]="'config-user-tier'" 
     [ldClassIfValue]="'premium'" 
     [ldClassIfClass]="'premium-user'" 
     [ldClassIfElseClass]="'basic-user'">
  User content
</div>

LdStyleIfDirective

Conditionally applies inline CSS styles.

<!-- Apply styles when flag is truthy -->
<div [ldStyleIf]="'premium-features'" [ldStyle]="{backgroundColor: '#007bff', color: 'white'}">
  Premium content
</div>

<!-- Apply different styles based on condition -->
<div [ldStyleIf]="'user-tier'" 
     [ldStyleIfValue]="'premium'" 
     [ldStyle]="{background: 'linear-gradient(45deg, #ffd700, #ffed4e)', color: '#8b4513'}"
     [ldElseStyle]="{backgroundColor: '#e9ecef', color: '#495057'}">
  User content
</div>

LdTrackDirective

Automatically tracks events for analytics.

<!-- Simple click tracking -->
<button [ldTrack]="'button-clicked'">Click me</button>

<!-- Track with custom data -->
<button [ldTrack]="'purchase'" [ldTrackData]="{product: 'premium', price: 29.99}">
  Buy Premium
</button>

<!-- Track conversion with metric value -->
<button [ldTrack]="'conversion'" [ldTrackValue]="29.99" [ldTrackData]="{product: 'premium'}">
  Buy Premium
</button>

<!-- Track on different events -->
<div [ldTrack]="'hover-detected'" [ldTrackEvent]="'mouseenter'" [ldTrackData]="{section: 'hero'}">
  Hover me
</div>

Service API

LaunchDarklyService

The main service for feature flag management.

Methods

variation$(key: string, fallback: T): Observable<T>

Gets the value of a feature flag as an observable stream.

this.ldService.variation$('new-feature', false).subscribe(enabled => {
  if (enabled) {
    this.showNewFeature();
  }
});
variationDetail$(key: string, fallback: T): Observable<LDEvaluationDetail>

Gets detailed evaluation information for a feature flag.

this.ldService.variationDetail$('pricing-tier', 'basic').subscribe(detail => {
  console.log(`Flag value: ${detail.value}`);
  console.log(`Reason: ${detail.reason.kind}`);
});
setContext(context: LDContext, timeoutMs?: number): Promise<void>

Changes the user context for the LaunchDarkly client.

const newContext = { key: 'user123', email: '[email protected]' };
try {
  await this.ldService.setContext(newContext, 5000);
  console.log('Context updated successfully');
} catch (err) {
  console.error('Failed to update context', err);
}
track(key: string, data?: any, metricValue?: number): void

Tracks a custom event for analytics and experimentation.

// Track a simple event
this.ldService.track('button-clicked');

// Track an event with data
this.ldService.track('purchase-completed', { productId: 'abc123', amount: 99.99 });

// Track an event with metric value
this.ldService.track('page-view', { page: '/dashboard' }, 1);
flush(): Promise<void>

Forces the LaunchDarkly client to flush any pending analytics events.

await this.ldService.flush();
waitUntilReady$(timeoutMs: number): Observable<boolean>

Waits for LaunchDarkly to be ready with a timeout.

this.ldService.waitUntilReady$(2000).subscribe(isReady => {
  if (isReady) {
    console.log('LaunchDarkly is ready');
  } else {
    console.log('Still waiting for LaunchDarkly...');
  }
});

Configuration

Module Configuration

LaunchDarklyAngularModule.forRoot({
  clientId: 'your-client-id',
  context: { key: 'user123', name: 'John Doe' },
  options: {
    streaming: true,
    debug: false
  },
  timeout: 500
})

Configuration Options

  • clientId: Your LaunchDarkly client-side ID
  • context: User context for flag evaluation
  • options: LaunchDarkly client options
  • timeout: Timeout for initialization in milliseconds

APP_INITIALIZER Setup

For applications that need to wait for LaunchDarkly to be ready before starting:

import { APP_INITIALIZER } from '@angular/core';
import { LaunchDarklyService } from '@launchtarqly/launchdarkly-angular';

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: LaunchDarklyService.createAppInitializer(1000),
      deps: [LaunchDarklyService],
      multi: true
    }
  ]
})
export class AppModule {}

Development

Building the Library

# Build the library
npm run build

# Build for production
npm run build:prod

Running Tests

# Run tests once
npm test

# Run tests in watch mode
npm run test:watch

Running the Demo

# Start the demo application
npm run demo:start

# Build the demo
npm run demo:build

Examples

Check out the examples/demo directory for a complete working example of the library in action. The demo includes:

  • All directive examples
  • Service usage patterns
  • User context switching
  • Event tracking examples

Testing

Unit Testing

import { LaunchDarklyService } from '@launchtarqly/launchdarkly-angular';

describe('MyComponent', () => {
  let mockLdService: jasmine.SpyObj<LaunchDarklyService>;

  beforeEach(() => {
    mockLdService = jasmine.createSpyObj('LaunchDarklyService', ['variation$']);
    mockLdService.variation$.and.returnValue(of(true));
  });

  it('should show feature when flag is enabled', () => {
    // Test implementation
  });
});

Integration Testing

import { LaunchDarklyAngularModule } from '@launchtarqly/launchdarkly-angular';

TestBed.configureTestingModule({
  imports: [
    LaunchDarklyAngularModule.forRoot({
      clientId: 'test-client-id',
      context: { key: 'test-user' }
    })
  ]
});

Best Practices

1. Use Directives for UI Changes

Prefer directives for conditional rendering and styling:

<!-- Good: Use directive -->
<div *ldIf="'new-feature'; fallback: false">New feature</div>

<!-- Avoid: Manual subscription in component -->
<div *ngIf="showFeature">New feature</div>

2. Use Service for Complex Logic

Use the service for complex business logic:

// Good: Complex logic in component
this.ldService.variation$('pricing-tier', 'basic').subscribe(tier => {
  this.calculatePricing(tier);
  this.updateUI(tier);
});

3. Provide Fallback Values

Always provide meaningful fallback values:

// Good: Meaningful fallback
this.ldService.variation$('welcome-message', 'Welcome!')

// Avoid: Generic fallback
this.ldService.variation$('welcome-message', null)

4. Handle Loading States

Use the waitUntilReady$ method for critical features:

this.ldService.waitUntilReady$(1000).subscribe(isReady => {
  if (isReady) {
    this.loadCriticalFeatures();
  } else {
    this.showLoadingState();
  }
});

Troubleshooting

Common Issues

1. Flags Not Updating

  • Check that streaming: true is set in options
  • Verify client ID is correct
  • Check browser console for errors

2. Directives Not Working

  • Ensure module is imported correctly
  • Check that fallback values are provided
  • Verify flag keys match LaunchDarkly dashboard

3. User Context Not Updating

  • Use setContext method with timeout
  • Check that context object is valid
  • Verify targeting rules in LaunchDarkly

Debug Mode

Enable debug mode for troubleshooting:

LaunchDarklyAngularModule.forRoot({
  clientId: 'your-client-id',
  context: { key: 'user123' },
  options: {
    streaming: true,
    debug: true
  }
})

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Support