Skip to content

App Features Tool

The App Features Tool allows developers to test product-level features that are typically controlled by license tiers, deployment configuration, or environment settings. This enables testing premium features without changing deployment configuration.

  • License Tier Testing: Test application behavior across different subscription tiers (Basic, Pro, Enterprise)
  • Premium Feature Development: Develop and test premium features without upgrading your development environment
  • Demo Preparation: Enable all features for demonstrations without changing your environment configuration
app.component.ts
import { Component, inject, signal } from '@angular/core';
import { ToolbarAppFeaturesService } from 'ngx-dev-toolbar';
@Component({
selector: 'app-root',
template: `
@if (hasAnalytics()) {
<app-analytics-dashboard />
}
@if (hasAdvancedReporting()) {
<app-advanced-reports />
}
`
})
export class AppComponent {
private appFeaturesService = inject(ToolbarAppFeaturesService);
hasAnalytics = signal(false);
hasAdvancedReporting = signal(false);
ngOnInit() {
// Define available app features
this.appFeaturesService.setAvailableOptions([
{
id: 'analytics',
name: 'Analytics Dashboard',
description: 'Advanced analytics and insights',
isEnabled: false,
isForced: false
},
{
id: 'advanced-reporting',
name: 'Advanced Reporting',
description: 'Export and custom reports',
isEnabled: false,
isForced: false
}
]);
// Subscribe to forced feature values
this.appFeaturesService.getForcedValues().subscribe(features => {
const analytics = features.find(f => f.id === 'analytics');
const reporting = features.find(f => f.id === 'advanced-reporting');
this.hasAnalytics.set(analytics?.isEnabled || false);
this.hasAdvancedReporting.set(reporting?.isEnabled || false);
});
}
}

You can persist forced app feature values back to your actual data source. When configured, each feature item shows an “apply” button.

Call setApplyToSource() on the service — right alongside setAvailableOptions():

app-features.service.ts
import { Injectable, inject } from '@angular/core';
import { ToolbarAppFeaturesService } from 'ngx-dev-toolbar';
@Injectable({ providedIn: 'root' })
export class AppFeaturesService {
private toolbarService = inject(ToolbarAppFeaturesService);
constructor() {
this.toolbarService.setAvailableOptions([...]); // [!code highlight]
this.toolbarService.setApplyToSource(async (featureId, value) => { // [!code highlight]
await fetch(`/api/app-features/${featureId}`, { // [!code highlight]
method: 'PUT', // [!code highlight]
body: JSON.stringify({ enabled: value }), // [!code highlight]
}); // [!code highlight]
}); // [!code highlight]
}
}

The toolbar automatically manages loading, success, and error states for each item.

Organize related features into collapsible sections by adding an optional group field to each feature. Groups appear as headers in the toolbar UI and can be expanded or collapsed; collapsed state persists across reloads.

app-features.service.ts
this.appFeaturesService.setAvailableOptions([
{
id: 'analytics',
name: 'Analytics Dashboard',
isEnabled: true,
isForced: false,
group: 'Reporting', // [!code highlight]
},
{
id: 'bulk-export',
name: 'Bulk Export',
isEnabled: false,
isForced: false,
group: 'Reporting', // [!code highlight]
},
{
id: 'white-label',
name: 'White Label Branding',
isEnabled: false,
isForced: false,
group: 'Branding', // [!code highlight]
},
]);

Behavior:

  • Pinned features always appear at the top in a dedicated Pinned section, regardless of their group
  • Named groups render alphabetically with each group’s features sorted alphabetically inside
  • Features without a group field appear under an Other section at the bottom
  • Each group header shows the item count and is collapsible

Backward compatible: if no feature has a group field, the toolbar renders the flat list exactly as before — no headers, no behavioral change.