ngx-task

July 25, 2026 · View on GitHub

Signal-first controlled asynchronous actions for Angular with cancellation, lifecycle cleanup, and explicit concurrency policies.

Documentation npm version npm downloads license bundle size Angular

Stop rewriting loading flags, cancellation controllers, duplicate submission guards, and queue mechanics for every Angular action. ngx-task provides a single reactive primitive that explicitly answers the question:

"What should happen when this asynchronous operation is invoked again before it finishes?"


📖 Full Interactive Documentation

Explore the complete Astro Starlight documentation site:

👉 https://MahmoudAdelJR.github.io/ngx-task-suite/

SectionLinks
🚀 Getting StartedInstallation · Quick Start
🧠 ConceptsArchitecture · Task vs Resource / RxJS
🛠️ Core API ReferencecreateTask() · Task Signals · TaskExecution · TaskContext
🚦 Concurrency PoliciesOverview · drop · restart · enqueue · latest · parallel
🔌 Handlers & AdaptersPromise / AbortSignal · RxJS & HttpClient
Production FeaturesTimeouts · Anti-Flicker · Error Classification · Progress & Retries · Lifecycle
🎨 Template DirectivesDirectives Overview
🧪 Testing UtilitiesTesting Guide
🔬 AdvancedZoneless Angular

📦 Installation

npm install ngx-task

Peer dependencies: @angular/core >= 16.0.0 · rxjs >= 7.5.0


⚡ Quick Start

import { Component, inject } from '@angular/core';
import { createTask } from 'ngx-task';
import { TaskTriggerDirective, TaskDisableWhilePendingDirective } from 'ngx-task/directives';

@Component({
  selector: 'app-profile-editor',
  standalone: true,
  imports: [TaskTriggerDirective, TaskDisableWhilePendingDirective],
  template: `
    <button
      type="button"
      [taskTrigger]="saveProfile"
      [taskArgs]="userForm"
      taskDisableWhilePending
    >
      @if (saveProfile.pending()) { Saving… } @else { Save Profile }
    </button>

    @if (saveProfile.error(); as err) {
      <p class="error">{{ err.message }}</p>
    }
  `,
})
export class ProfileEditorComponent {
  private api = inject(ProfileApiService);
  readonly userForm = { name: 'Alice', email: 'alice@example.com' };

  readonly saveProfile = createTask(
    async (profile, { signal }) => this.api.saveProfile(profile, { signal }),
    {
      concurrency: 'drop', // Ignore duplicate clicks while running
      timeout: 15_000,     // Auto-abort after 15 s
      pendingDelay: 150,   // No spinner flash for sub-150 ms responses
    },
  );
}

🚦 Concurrency Policies

PolicyBehaviorTypical Use Case
dropIgnores new invocations while one is running.Form submit · Login · Payment checkout
restartCancels active execution; runs newest immediately.Live search · Filter inputs · Tab switching
enqueueRuns invocations sequentially in FIFO order.Audit logs · Sequential file uploads
latestFinishes active; keeps only the newest queued invocation.Autosave · Canvas/Slider sync
parallelRuns up to limit executions simultaneously.Bulk uploads · Parallel asset preloads

🧠 Key Concepts

Task vs Angular resource / rxResource

  • resource: Declarative reactive data fetching driven by signal dependencies (reads).
  • ngx-task: Imperative action triggered by user gestures (form submit, click) with explicit concurrency rules (writes/commands).

Task vs RxJS Flattening Operators

RxJS operators (exhaustMap, switchMap, concatMap, mergeMap) transform streams. ngx-task surfaces execution handles, signals (pending, running, result, error), progress, anti-flicker timing, and DestroyRef cleanup as a first-class Angular primitive — no subjects or manual subscriptions required.

Cooperative Cancellation

ngx-task provides an AbortSignal for Promise handlers and auto-calls unsubscribe() for RxJS Observables. Pass context.signal to fetch() or HttpClient to stop in-flight network I/O on cancel, timeout, or component destroy.


📂 Package Entry Points

ImportContents
ngx-taskcreateTask, all signals, schedulers, state machine, and adapters
ngx-task/directivesTaskTriggerDirective, TaskDisableWhilePendingDirective, TaskBusyDirective
ngx-task/testingcreateTaskHarness, createControlledTaskHandler, createDeferred, createTaskTestClock

⚖️ License

MIT © Mahmoud Adel