DEV Community

Mthobisi
Mthobisi

Posted on

Toggle This: Feature Flags in Angular

Angular Directives

Angular uses directives to add additional behavior to elements. There are several built-in directives that help manage different aspects of your application.

Directive types

Directive Type Details Example
Components Used with a template. This type of directive is the most common directive type. Any angular component
Attributes directives Change the appearance or behavior of an element, component, or another directive. NgClass NgStyle, NgModel
Structural directives Change the DOM layout by adding and removing DOM elements. ngIf, ngFor

Our focus will be on Structural directives, so let us take a deep dive into them.

Why Do We Need Structural Directives?

Structural directives are useful when we want to dynamically change the structure of the HTML Document Object Model (DOM) by adding, removing, or transforming elements based on a condition or data.

Key reasons for using structural directives

  • Conditional rendering
  • Dynamic lists
  • Managing DOM structure
  • Reusability

Toggle This: What Are Feature Flags?

Feature flags are a software development technique that allows teams to enable or disable specific features in an application at runtime, without changing or redeploying the code.

In Angular, feature flags are implemented as custom structural directives. They are similar to ngIf, but with key differences.

How does the two differ

Purpose

ngIf: Used for conditional rendering based on a boolean expression in the code. It primarily controls UI elements based on local component state or simple logic.
Feature Flags: A mechanism to remotely enable or disable features in an application without requiring a new deployment. They help manage features across different environments, support A/B testing, and enable progressive rollouts.

Control Mechanism

ngIf: The condition for *ngIf is determined by a boolean expression directly within your Angular template or component logic. Changes require modifying the code and redeploying the application.

Feature Flags: The state of a feature flag is typically managed externally, often through a dedicated feature flag service or platform. This allows toggling features on or off at runtime without code changes or redeployments.

Implementation

To create a directive, you can use the Angular CLI as follows:

ng generate directive <directive-name> --standalone
Enter fullscreen mode Exit fullscreen mode

The following class should be generated.

@Directive({
  selector: '[appFeatureFlag]',
  standalone: true,
})
export class FeatureFlagDirective implements OnInit, OnDestroy {
  @Input('appFeatureFlag') featureFlag!: string;
Enter fullscreen mode Exit fullscreen mode

The @Directive decorator registers this class as a directive. The selector is the directive name (appFeatureFlag). The @Input decorator allows Angular to pass a value when the directive is used.

Directive Logic

private subscription?: Subscription;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private featureFlagService: FeatureFlagService
  ) {}

  public ngOnInit() {
    if (!this.featureFlag) {
      this.viewContainer.clear();
      return;
    }

    this.subscription = this.featureFlagService
      .hasAccess(this.featureFlag)
      .subscribe((hasAccess) => {
        this.viewContainer.clear();
        if (hasAccess) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        }
      });
  }
Enter fullscreen mode Exit fullscreen mode

Explanation: On initialization, we clear the viewContainer, which effectively removes a component or element from the DOM. Then, if a feature flag is provided, we check access and render the component only if access is granted.

Deep Dive To a Feature Flag Service

private checkFullPath(nodes: ItemNames[] | undefined, segments: string[]): boolean {
    if (!nodes) {
      return false;
    }

    const [current, ...rest] = segments;

    for (const node of nodes) {
      if (node.name === current) {
        // Recurse into children for the remaining segments
        if (rest.length === 0) {
          return true; // Last segment matched
        }

        if (node.itemNames && node.itemNames.length > 0) {
          return this.checkFullPath(node.itemNames, rest);
        } else {
          return false; // No children to match remaining segments
        }
      }
    }

    return false; // Current segment not found
  }
Enter fullscreen mode Exit fullscreen mode

Explanation: Due to the hierarchical structure of features, we split the feature flag into segments and recursively check each parent and its children to confirm if a feature is accessible.

Pros and Cons of feature flags

Pros

  • Dynamic Control: Features can be turned on or off without redeploying code.
  • Safe Rollouts: Supports progressive feature rollouts and A/B testing.
  • Environment Flexibility: Different features can be enabled for different environments or user groups.
  • Reduced Risk: Bugs in new features can be quickly disabled without impacting the whole system.

Cons

  • Increased Complexity: Managing many flags can make the codebase harder to maintain.
  • Technical Debt: Old or unused flags need to be cleaned up to prevent clutter.
  • Testing Challenges: Testing all combinations of feature flags can be complex.
  • Performance Overhead: Frequent checks on feature flags might introduce minimal runtime overhead.

Here is a fronend code: https://github.com/mthobisig8/feature-flag-fe

Top comments (0)