ngx-growthbook
Version:
Angular library for GrowthBook
200 lines (193 loc) • 6.84 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Inject, Injectable, makeEnvironmentProviders, provideAppInitializer, inject } from '@angular/core';
import { GrowthBook } from '@growthbook/growthbook';
import { Subject, takeUntil, Observable } from 'rxjs';
const NGX_GROWTHBOOK_CONFIG_TOKEN = new InjectionToken('ngx-growthbook.config');
class NgxGrowthbookService {
config;
growthBook;
growthBookSource = new Subject();
eventCount = 0;
destroy$ = new Subject();
constructor(config) {
this.config = config;
}
ngOnDestroy() {
this.growthBookSource.unsubscribe();
this.destroy$.next();
this.destroy$.complete();
}
async init(config, trackingService) {
if (!config.clientKey) {
throw new Error('GrowthBook clientKey is required');
}
console.log('Initializing GrowthBook...');
this.growthBook = new GrowthBook({
trackingCallback: trackingService
? (experiment, result) => {
trackingService?.trackExperiment(experiment.key, result);
}
: config.trackingCallback,
onFeatureUsage: trackingService
? (featureKey, result) => {
trackingService?.trackFeature?.(featureKey, result);
}
: config.onFeatureUsage,
...config,
});
await this.growthBook.init({ skipCache: true, streaming: true });
this.growthBook.setRenderer(() => {
this.triggerUpdate();
});
console.log('...GrowthBook initialized');
return this.growthBook;
}
triggerUpdate() {
this.growthBookSource.next((this.eventCount += 1));
}
subscribe(callback) {
callback(0);
return this.growthBookSource
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
callback;
});
}
getFeature(featureKey, defaultValue) {
return this.evaluateFeatureSync(featureKey, defaultValue);
}
/**
* Evaluates a feature and returns an observable that will emit whenever the feature changes
* @param featureKey The feature key to evaluate
* @param defaultValue The default value if the feature is not found
*/
evaluateFeature(featureKey, defaultValue) {
const evaluate = () => {
const result = this.growthBook.evalFeature(featureKey);
return result;
};
// Initial evaluation
const initial = evaluate();
// Create an observable that emits whenever features are updated
return new Observable((subscriber) => {
subscriber.next(initial);
const subscription = this.growthBookSource
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
subscriber.next(evaluate());
});
return () => subscription.unsubscribe();
});
}
/**
* Evaluates a feature and returns the current value synchronously
* @param featureKey The feature key to evaluate
* @param defaultValue The default value if the feature is not found
*/
evaluateFeatureSync(featureKey, defaultValue) {
const result = this.growthBook.evalFeature(featureKey);
return result;
}
loadFeatures() {
return this.growthBook.loadFeatures();
}
isOn(featureKey) {
return this.growthBook.isOn(featureKey);
}
isOff(featureKey) {
return this.growthBook.isOff(featureKey);
}
setFeatureValue(featureKey) {
if (featureKey) {
this.growthBook.setFeatures({
featureKey: { defaultValue: true },
});
}
}
getFeatureValue(featureKey, defaultValue) {
return this.growthBook.getFeatureValue(featureKey, defaultValue);
}
/**
* In addition to the isOn and getFeatureValue helper methods,
* there is the evalFeature method that gives you more detailed
* information about why the value was assigned to the user.
* @param featureKey
* @returns
*/
evalFeature(featureKey) {
return this.growthBook.evalFeature(featureKey);
}
/**
* Completely replaces attributes
* @param attributes
*/
setAttributes(attributes) {
return this.growthBook.setAttributes(attributes);
}
updateAttributes(attributes) {
const existingAttributes = this.getAttributes();
return this.growthBook.setAttributes({
...existingAttributes,
...attributes,
});
}
refreshFeatures(options) {
return this.growthBook.refreshFeatures(options);
}
setURL(url) {
return this.growthBook.setURL(url);
}
getAttributes() {
return this.growthBook.getAttributes();
}
getFeatures() {
return this.growthBook.getFeatures();
}
getExperiments() {
return this.growthBook.getExperiments();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NgxGrowthbookService, deps: [{ token: NGX_GROWTHBOOK_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NgxGrowthbookService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NgxGrowthbookService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [NGX_GROWTHBOOK_CONFIG_TOKEN]
}] }] });
function provideNgxGrowthbook(config) {
if (!config.clientKey) {
throw new Error('GrowthBook clientKey is required');
}
const providers = [
{
provide: NGX_GROWTHBOOK_CONFIG_TOKEN,
useValue: config,
},
NgxGrowthbookService,
];
if (config.trackingService) {
providers.push(config.trackingService);
}
return makeEnvironmentProviders([
...providers,
provideAppInitializer(async () => {
const growthbookService = inject(NgxGrowthbookService);
const trackingService = config.trackingService
? inject(config.trackingService)
: null;
await growthbookService.init(config, trackingService);
}),
]);
}
/*
* Public API Surface of ngx-growthbook
*/
/**
* Generated bundle index. Do not edit.
*/
export { NGX_GROWTHBOOK_CONFIG_TOKEN, NgxGrowthbookService, provideNgxGrowthbook };
//# sourceMappingURL=ngx-growthbook.mjs.map