Skip to main content
ParityEdge
Angular (v14+)
Frontend Framework Guide

Angular Integration (@angular/core v14 to 18+)

Complete guide for integrating ParityEdge localized purchasing power parity pricing into Angular applications using Standalone Components, Angular Signals (toSignal), RxJS HttpClient Services, and Shadow DOM Web Components.

Drop-in Web Component (Shadow DOM)

Enable CUSTOM_ELEMENTS_SCHEMA & Load Global CDN

Because the ParityEdge banner is rendered in an isolated Shadow DOM custom element, configure your Angular component or module with CUSTOM_ELEMENTS_SCHEMA:

Load CDN Script in src/index.html (or angular.json)

<!-- src/index.html -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My Angular App</title>
  <base href="/">
  <!-- ParityEdge Sub-10ms Edge CDN Script -->
  <script
    src="https://api.parityedge.app/v1/parity.global.js"
    async
  ></script>
</head>
<body>
  <app-root></app-root>
</body>
</html>

Configure Standalone Angular Component (pricing.component.ts)

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-pricing',
  standalone: true,
  imports: [CommonModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA], // Enables <parity-element> web component
  template: `
    <div class="pricing-container">
      <!-- Isolated Shadow DOM Web Component Banner (Near-Zero CLS) -->
      <parity-element
        [attr.project-id]="projectId"
        theme="dark"
        position="bottom-pill">
      </parity-element>

      <h1>Simple, Predictable Pricing</h1>
      <!-- Pricing cards here -->
    </div>
  `,
  styles: [`
    .pricing-container {
      min-height: 100vh;
      background-color: #0a0e17;
      color: #ffffff;
      padding: 3rem 1rem;
    }
  `]
})
export class PricingComponent {
  projectId = 'prj_live_YOUR_PROJECT_ID';
}
Angular Signals & Headless HTTP Service

Type-Safe ParityEdgeService with Angular Signals

For full UI control, inject an Angular HTTP Service that communicates with the ParityEdge Edge API, exposing reactive state via Angular Signals (toSignal):

src/app/services/parity-edge.service.ts

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, shareReplay, catchError, of } from 'rxjs';

export interface ParityResolution {
  eligible: boolean;
  countryCode: string;
  countryName: string;
  discountPercentage: number;
  couponCode: string;
  currency: string;
  tier: number;
}

@Injectable({
  providedIn: 'root'
})
export class ParityEdgeService {
  private http = inject(HttpClient);
  private edgeApiUrl = 'https://api.parityedge.app/v1/lookup';

  resolveParity(projectId: string): Observable<ParityResolution | null> {
    return this.http.get<ParityResolution>(`${this.edgeApiUrl}?projectId=${projectId}`).pipe(
      shareReplay(1),
      catchError((err) => {
        console.warn('[ParityEdge] Resolution fallback to default USD:', err);
        return of(null);
      })
    );
  }
}

src/app/components/pricing-table.component.ts (Angular 16+)

import { Component, inject, computed } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { ParityEdgeService } from '../services/parity-edge.service';

@Component({
  selector: 'app-pricing-table',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="p-6 rounded-2xl border border-slate-800 bg-slate-900 text-white space-y-4">
      <h3>Pro Tier</h3>

      <!-- Dynamic Price Calculation with Signal -->
      <div class="text-3xl font-extrabold">
        ${{ discountedPrice() }} <span class="text-xs text-slate-400">/ month</span>
      </div>

      <!-- Discount Notification Pill -->
      @if (parity()?.eligible && (parity()?.discountPercentage ?? 0) > 0) {
        <div class="p-3 bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 rounded-xl text-xs font-medium">
          <span>{{ parity()?.discountPercentage }}% Parity Discount applied for {{ parity()?.countryName }}!</span>
          <code class="ml-2 bg-emerald-950 px-2 py-0.5 rounded">Code: {{ parity()?.couponCode }}</code>
        </div>
      }

      <button 
        (click)="checkout()"
        class="w-full py-2.5 px-4 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-white font-semibold text-xs transition-all">
        Subscribe Now
      </button>
    </div>
  `
})
export class PricingTableComponent {
  private parityService = inject(ParityEdgeService);
  private baseUsdPrice = 49;

  // Reactive Signal directly from Edge API
  readonly parity = toSignal(
    this.parityService.resolveParity('prj_live_YOUR_PROJECT_ID')
  );

  // Computed signal for discounted price
  readonly discountedPrice = computed(() => {
    const data = this.parity();
    if (!data || !data.eligible || data.discountPercentage <= 0) return this.baseUsdPrice.toFixed(2);
    return (this.baseUsdPrice * (1 - data.discountPercentage / 100)).toFixed(2);
  });

  checkout() {
    const coupon = this.parity()?.couponCode;
    window.location.href = coupon
      ? `https://buy.stripe.com/test_123?prefilled_promo_code=${coupon}`
      : 'https://buy.stripe.com/test_123';
  }
}

Angular Production Architecture Highlights

Reactive Signal Caching

shareReplay(1) prevents duplicate HTTP requests on route changes, maintaining instant local state across views.

Anti-VPN Edge Validation

ParityEdge validates ASN threats at the Anycast edge layer, guaranteeing that datacenter proxies do not receive discounted rates.