Files
ISA-Frontend/libs/shared/scanner

Scanner Library

Overview

The Scanner library provides barcode scanning capabilities for the ISA application using the Scandit SDK. It offers a complete solution for mobile barcode scanning with support for various barcode formats, ready-state detection, and seamless form integration.

Features

  • Barcode scanning with support for multiple symbologies:
    • EAN8
    • EAN13/UPCA
    • UPCE
    • Code128
    • Code39
    • Code93
    • Interleaved 2 of 5
    • QR Code
  • Platform detection (iOS/Android support)
  • Ready-state detection with conditional rendering
  • Form control integration via output bindings
  • Configuration through injection tokens
  • Error handling for unsupported platforms

Components and Directives

ScannerButtonComponent

A button component that integrates with the scanner service to trigger barcode scanning. It implements OnDestroy to properly clean up resources.

Features:

  • Only appears when scanner is ready
  • Can be disabled through binding
  • Configurable size
  • Emits scanned value through output binding
  • Includes E2E testing attribute data-which="scan-button"

Usage Example:

import { ScannerButtonComponent } from '@isa/core/scanner';

@Component({
  selector: 'app-my-component',
  template: `
    <shared-scanner-button
      [disabled]="isDisabled"
      [size]="'large'"
      (scan)="onScan($event)"
    >
    </shared-scanner-button>
  `,
  imports: [ScannerButtonComponent],
  standalone: true,
})
export class MyComponent {
  isDisabled = false;

  onScan(value: string | null) {
    console.log('Scanned barcode:', value);
  }
}

ScannerReadyDirective

A structural directive (*sharedScannerReady) that conditionally renders its content based on the scanner's ready state. Similar to *ngIf, but specifically tied to scanner readiness.

Features:

  • Only renders content when the scanner is ready
  • Supports an optional else template for when the scanner is not ready
  • Uses Angular's effect system for reactive updates

Usage Example:

import { ScannerReadyDirective } from '@isa/core/scanner';

@Component({
  selector: 'app-my-component',
  template: `
    <div *sharedScannerReady>
      <!-- Content only shown when scanner is ready -->
      <p>Scanner is ready to use</p>
      <button (click)="startScanning()">Scan Now</button>
    </div>

    <!-- Alternative with else template -->
    <div *sharedScannerReady="; else notReady">
      <p>Scanner is ready</p>
    </div>

    <ng-template #notReady>
      <p>Scanner is not yet ready</p>
      <app-spinner></app-spinner>
    </ng-template>
  `,
  imports: [ScannerReadyDirective],
  standalone: true,
})
export class MyComponent {
  // Component logic
}

ScannerComponent

Internal component used by ScannerService to render the camera view and process barcode scanning.

Features:

  • Integrates with Scandit SDK
  • Handles camera setup and barcode detection
  • Emits scanned values
  • Includes a close button to cancel scanning

Services

ScannerService

Core service that provides barcode scanning functionality.

Features:

  • Initializes and configures Scandit SDK
  • Checks platform compatibility
  • Manages scanner lifecycle
  • Provides a reactive ready signal
  • Handles scanning operations with proper cleanup

Usage Example:

import { ScannerService, ScannerInputs } from '@isa/core/scanner';
import { Component, inject } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <button (click)="scan()" [disabled]="!isReady()">Scan Barcode</button>
    <div *ngIf="result">Last Scan: {{ result }}</div>
  `,
  standalone: true,
})
export class MyComponent {
  private scannerService = inject(ScannerService);
  isReady = this.scannerService.ready;
  result: string | null = null;

  async scan() {
    const options: ScannerInputs = {
      // Optional configuration
      // symbologies: [...] // Specify barcode types
    };

    try {
      this.result = await this.scannerService.open(options);
    } catch (error) {
      console.error('Scanning failed:', error);
    }
  }
}

Configuration

The scanner module uses injection tokens for configuration:

  • SCANDIT_LICENSE - The Scandit license key (defaults to config value at 'licence.scandit')
  • SCANDIT_LIBRARY_LOCATION - The location of the Scandit library (defaults to '/scandit' relative to base URI)
  • SCANDIT_DEFAULT_SYMBOLOGIES - The default barcode symbologies to use

Custom Configuration Example:

import { SCANDIT_LICENSE, SCANDIT_LIBRARY_LOCATION } from '@isa/core/scanner';
import { Symbology } from 'scandit-web-datacapture-barcode';

@NgModule({
  providers: [
    // Custom license key
    {
      provide: SCANDIT_LICENSE,
      useValue: 'YOUR-SCANDIT-LICENSE-KEY',
    },
    // Custom library location
    {
      provide: SCANDIT_LIBRARY_LOCATION,
      useValue: 'https://cdn.example.com/scandit/',
    },
  ],
})
export class AppModule {}

Error Handling

The scanner library includes error handling for various scenarios:

  • PlatformNotSupportedError is thrown when the scanner is used on unsupported platforms
  • Configuration errors are logged and propagated
  • Aborted scan operations are handled gracefully

Requirements

  • The Scandit SDK must be properly installed and configured
  • Requires a valid Scandit license key
  • Currently supports iOS and Android platforms

E2E Testing

The scanner components include E2E testing attributes for easier selection in automated tests:

  • ScannerButton includes data-which="scan-button" for E2E test selection