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

angular-klasha

v1.0.0

Published

Angular wrapper for accepting Klasha payments (component, directive and service). Supports standalone APIs and NgModule.

Readme

angular-klasha

Angular component, directive and service for accepting Klasha payments.

npm license


⚠️ Upgrade from 0.0.x immediately — 0.0.x is completely non-functional

[email protected] cannot process a payment at all, and never warns you.

  1. Its checkout script no longer exists. 0.0.x loaded https://klastatic.fra1.digitaloceanspaces.com/{test,prod}/js/klasha-integration.js. That DigitalOcean Spaces bucket has been deleted and both URLs now return NoSuchBucket. window.KlashaClient is therefore never defined and the checkout silently never opens.

  2. The 9th isTestMode argument is missing. KlashaClient takes isTestMode as its 9th constructor argument, and on the current pay.js it is the only thing that selects the sandbox. 0.0.x passes eight. That matters now, because the current script serves one URL for both environments — repointing without adding the argument would send sandbox traffic to production. 1.0.0 passes it, coerced to a real boolean.

    For the avoidance of doubt about the past: while the old CDN existed, 0.0.x selected /test/js/ or /prod/js/ correctly from isTestMode, and that script was environment-specific by URL. There is no evidence historical sandbox payments reached production.

  3. The customer phone number was dropped. 0.0.x set kit.phone_number; the Klasha script only ever reads kit.phone.

  4. Duplicate DOM ids. 0.0.x appended a <div id="ktest"> from the service constructor on every injection, so more than one payment button meant more than one element with the same id.

  5. It loaded jQuery from the Google CDN for no reason — the Klasha script does not use jQuery.

  6. It also console.log'd on construction and shipped a stale vendored copy of the dead integration script inside the published package.

1.0.0 fixes all of the above: it loads the current script https://js.klasha.com/pay.js, forwards isTestMode as a real boolean 9th argument, sets kit.phone, gives every instance its own container element, and loads no jQuery.

There is no safe way to stay on 0.0.x. Upgrade.


Requirements

| | | | --- | --- | | Angular | 16, 17, 18, 19 or 20 (@angular/common and @angular/core) | | Environment | Browser. The checkout script cannot run during server-side rendering; call pay() from a browser-only code path. |

Published as Ivy partial-compilation output, so it works with both NgModule-based and standalone applications.

Install

npm install --save angular-klasha

No script tag, no jQuery and no extra setup: https://js.klasha.com/pay.js is injected lazily the first time a payment is started.

1. Configure your merchant credentials

Standalone applications

import { bootstrapApplication } from '@angular/platform-browser';
import { provideKlasha } from 'angular-klasha';

import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideKlasha({
      merchantKey: 'YOUR_MERCHANT_KEY',
      businessId: '1',
      isTestMode: true, // false (or omitted) targets the LIVE gateway
    }),
  ],
});

NgModule applications

forRoot() still works exactly as it did in 0.0.x, so existing code does not have to change:

import { NgModule } from '@angular/core';
import { AngularKlashaModule } from 'angular-klasha';

@NgModule({
  imports: [
    AngularKlashaModule.forRoot('YOUR_MERCHANT_KEY', '1', true),
    // a config object also works:
    // AngularKlashaModule.forRoot({ merchantKey: 'YOUR_MERCHANT_KEY', businessId: '1', isTestMode: true }),
  ],
})
export class AppModule {}

isTestMode here is what gets forwarded to KlashaClient as its 9th argument. Leaving it out means live payments.

2. Use the component or the directive

Both are standalone, so you can import either one directly into a standalone component — or get both by importing AngularKlashaModule.

AngularKlashaComponent

Renders a <button> that opens the Klasha checkout when clicked.

import { Component } from '@angular/core';
import { AngularKlashaComponent, KlashaOptions } from 'angular-klasha';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [AngularKlashaComponent],
  templateUrl: './checkout.component.html',
})
export class CheckoutComponent {
  options: KlashaOptions = this.buildOptions();

  paymentInit(): void {
    console.log('Payment initialised');
  }

  paymentDone(response: unknown): void {
    console.log('Payment done', response);
    // Build a fresh options object for the next payment: `tx_ref` must be
    // unique and the Klasha script mutates the `kit` object it is given.
    this.options = this.buildOptions();
  }

  private buildOptions(): KlashaOptions {
    return {
      merchantKey: 'YOUR_MERCHANT_KEY',
      businessId: '1',
      amount: 10000,
      email: '[email protected]',
      fullname: 'Some Customer',
      phone: '+2348000000000',
      sourceCurrency: 'NGN',
      destinationCurrency: 'NGN',
      tx_ref: `klasha-${Date.now()}`,
      paymentDescription: 'Order #1234',
      isTestMode: true,
    };
  }
}
<angular-klasha
  [klashaOptions]="options"
  [class]="'btn btn-primary'"
  (paymentInit)="paymentInit()"
  (callBack)="paymentDone($event)"
>
  Pay with Klasha
</angular-klasha>

AngularKlashaDirective

Same behaviour, applied to your own element so you keep full control of the markup:

import { Component } from '@angular/core';
import { AngularKlashaDirective } from 'angular-klasha';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [AngularKlashaDirective],
  templateUrl: './checkout.component.html',
})
export class CheckoutComponent { /* … same class body as above … */ }
<button
  type="button"
  angular-klasha
  [klashaOptions]="options"
  (paymentInit)="paymentInit()"
  (callBack)="paymentDone($event)"
>
  Pay with Klasha
</button>

Individual inputs instead of klashaOptions

Every field of KlashaOptions is also available as its own input:

<button
  type="button"
  angular-klasha
  [merchantKey]="'YOUR_MERCHANT_KEY'"
  [businessId]="'1'"
  [amount]="10000"
  [email]="'[email protected]'"
  [fullname]="'Some Customer'"
  [phone]="'+2348000000000'"
  [tx_ref]="txRef"
  [isTestMode]="true"
  (paymentInit)="paymentInit()"
  (callBack)="paymentDone($event)"
>
  Pay with Klasha
</button>

merchantKey, businessId and isTestMode set on the component/directive take priority over the values given to provideKlasha() / forRoot().

(callBack) is required. Without a subscriber, pay() refuses to open the checkout and returns angular-klasha: Insert a callBack output like so (callBack)='PaymentComplete($event)' to check payment status.

Options

KlashaOptionsmerchantKey, businessId, amount and email are required; everything else is optional.

| Option | Type | Description | | --- | --- | --- | | merchantKey | string | Your Klasha merchant key. Falls back to the globally provided one. | | businessId | string | Your Klasha business id. Falls back to the globally provided one. | | amount | number | Amount to charge. | | email | string | Customer email address. | | fullname | string | Customer full name. | | phone | string | Customer phone number. This is the field the Klasha script reads. | | phone_number | string | Deprecated alias of phone, still accepted. | | sourceCurrency | string | Currency you price in. Defaults to NGN. | | destinationCurrency | string | Currency the customer is charged in. Defaults to NGN. | | tx_ref | string | Unique transaction reference. Generated for you when omitted. | | callbackUrl | string | URL the customer is redirected to after paying. | | paymentDescription | string | Human readable description of the payment. | | isTestMode | boolean | true = Klasha sandbox, false/omitted = live gateway. | | metadata | unknown | Free-form data kept on the instance; not sent to Klasha. | | kit | KlashaKitOptions | Advanced: extra fields merged into the payload handed to the Klasha script. |

kit

You rarely need to set kit yourself — the service builds it from the options above. It ends up containing:

| Field | Source | | --- | --- | | currency | sourceCurrency | | phone | phone (or the deprecated phone_number) | | phone_number | the same value, kept only for backwards compatibility | | email | email | | fullname | fullname | | tx_ref | tx_ref, generated when omitted | | productType | kit.productType (or the deprecated kit.paymentType) | | amount | kit.amount, defaulting to amount | | sourceAmount | kit.sourceAmount, when you supply one | | callBack | wired to the (callBack) output for you |

The Klasha script mutates the kit object it is given (it assigns businessId, currency and redirect_url onto it). angular-klasha builds a brand new kit for every payment, so never share one between payments.

Outputs

| Output | Fires | | --- | --- | | (paymentInit) | Immediately before the Klasha checkout is opened. | | (callBack) | With the Klasha response once the payment flow finishes. Required. |

The checkout container

The Klasha script renders into a container element looked up by id. Each component/directive instance gets its own id (klasha-container-1, klasha-container-2, …): the element is created on the first payment, reused on every subsequent one, and removed on destroy. 0.0.x hardcoded ktest for every instance and appended a new element each time.

If you need the id — for styling, say — read it off the instance:

@ViewChild(AngularKlashaDirective) klasha!: AngularKlashaDirective;
// this.klasha.containerId

Programmatic use

AngularKlashaService is providedIn: 'root' and can be used without the component or the directive:

import { inject } from '@angular/core';
import { AngularKlashaService } from 'angular-klasha';

const klasha = inject(AngularKlashaService);

async function pay(): Promise<void> {
  const options = klasha.getKlashaOptions({
    merchantKey: 'YOUR_MERCHANT_KEY',
    businessId: '1',
    amount: 10000,
    email: '[email protected]',
    fullname: 'Some Customer',
    phone: '+2348000000000',
    isTestMode: true,
  });
  options.kit.callBack = (response) => console.log('done', response);

  const containerId = 'my-klasha-container';
  await klasha.loadScript();
  klasha.launch(options, containerId); // creates the container if needed
}

| Member | Description | | --- | --- | | loadScript() | Injects https://js.klasha.com/pay.js once and resolves when window.KlashaClient is available. | | getKlashaOptions(options) | Resolves defaults and builds a fresh kit. | | checkInput(options) | Returns '' when the options are usable, otherwise an error message. | | launch(resolvedOptions, containerId) | Constructs KlashaClient (with all nine arguments) and calls init(). | | ensureContainer(id) / removeContainer(id) | Container lifecycle. | | makeId(length?) | Random transaction reference generator. |

Also exported: KLASHA_SCRIPT_URL, nextKlashaContainerId(), and the MERCHANT_KEY, BUSINESS_ID and IS_TEST_MODE injection tokens.

Migrating from 0.0.x

| 0.0.x | 1.0.0 | | --- | --- | | AngularKlashaModule.forRoot(key, biz, isTest) | Unchanged — still works. | | <angular-klasha> / [angular-klasha] | Unchanged; now standalone as well. | | (callBack), (paymentInit) | Unchanged. | | phone_number | Still accepted; prefer phone. | | KlashaOptions required almost every field | Only merchantKey, businessId, amount and email are required. | | tx_ref had to be supplied | Generated when omitted. | | Container was always ktest | Per-instance id, available as .containerId. | | isTestMode was ignored by the Klasha script | Forwarded as the 9th constructor argument. | | PrivateKlashaOptions | Renamed ResolvedKlashaOptions (old name kept as a deprecated alias). |

Nothing that worked before has been removed.

Testing your integration

You cannot complete a real payment without live merchant credentials. Mock window.KlashaClient and assert on the constructor arguments — argument index 8 is isTestMode:

const calls: unknown[][] = [];
(window as any).KlashaClient = function (this: any, ...args: unknown[]) {
  calls.push(args);
  this.init = () => undefined;
};

// … trigger a payment …

expect(calls[0].length).toBe(9);
expect(calls[0][8]).toBe(true);          // isTestMode
expect((calls[0][7] as any).phone).toBe('+2348000000000');

Contributing

Fork the repository and open a pull request — contributions are welcome.

How can I thank you?

Star the GitHub repository, and share it. Don't forget to follow me on twitter!

Thanks! Dansteve Adekanbi.

License

The MIT License (MIT). Please see the License File for more information.