- Add new reward-order-confirmation feature library with components and store - Implement checkout completion orchestrator service for order finalization - Migrate checkout/oms/crm models to Zod schemas for better type safety - Add order creation facade and display order schemas - Update shopping cart facade with order completion flow - Add comprehensive tests for shopping cart facade - Update routing to include order confirmation page
@isa/utils/ean-validation
Lightweight Angular utility library for validating EAN (European Article Number) barcodes with reactive forms integration and standalone validation functions.
Overview
The EAN Validation library provides tools for validating 13-digit EAN barcodes in Angular applications. It includes both an Angular Forms validator for reactive form validation and a standalone utility function for programmatic validation. The library uses a simple regex-based approach for fast, efficient validation without external dependencies.
Table of Contents
- Features
- Quick Start
- Core Concepts
- API Reference
- Usage Examples
- EAN Format
- Architecture Notes
- Testing
- Dependencies
Features
- Angular Forms validator -
eanValidatorfor reactive form controls - Standalone validation -
isEan()utility function for programmatic checks - Regex-based validation - Fast, efficient 13-digit EAN validation
- Zero dependencies - No external libraries required
- Type-safe - Full TypeScript support
- Null-safe - Graceful handling of undefined/null values
- Lightweight - Minimal bundle size impact
- Framework agnostic core - Validation logic can be used outside Angular
Quick Start
1. Reactive Form Validation
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { eanValidator } from '@isa/utils/ean-validation';
@Component({
selector: 'app-product-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="productForm">
<label>
EAN:
<input formControlName="ean" type="text" />
</label>
@if (eanControl.errors?.['invalidEan']) {
<div class="error">
Please enter a valid 13-digit EAN
</div>
}
</form>
`
})
export class ProductFormComponent {
productForm = new FormGroup({
ean: new FormControl('', [eanValidator])
});
get eanControl() {
return this.productForm.get('ean')!;
}
}
2. Programmatic Validation
import { Component } from '@angular/core';
import { isEan } from '@isa/utils/ean-validation';
@Component({
selector: 'app-barcode-scanner',
template: `
<button (click)="validateBarcode('1234567890123')">
Validate Barcode
</button>
`
})
export class BarcodeScannerComponent {
validateBarcode(code: string): void {
if (isEan(code)) {
console.log('Valid EAN:', code);
// Process valid EAN
} else {
console.error('Invalid EAN:', code);
// Handle invalid EAN
}
}
}
3. Combined Usage
import { Component } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { eanValidator, isEan } from '@isa/utils/ean-validation';
@Component({
selector: 'app-product-search',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<input
[formControl]="searchControl"
placeholder="Enter EAN"
(keyup.enter)="search()"
/>
<button (click)="search()" [disabled]="!canSearch()">
Search
</button>
`
})
export class ProductSearchComponent {
searchControl = new FormControl('', [eanValidator]);
canSearch(): boolean {
const value = this.searchControl.value;
return !!value && isEan(value);
}
search(): void {
if (this.canSearch()) {
const ean = this.searchControl.value!;
console.log('Searching for:', ean);
// Perform search
}
}
}
Core Concepts
EAN (European Article Number)
EAN is a 13-digit barcode standard used internationally for product identification:
1234567890123
└───┬────┘││└─ Check digit
│ ││
│ │└── Product code
│ └─── Manufacturer code
└───────── Country/GS1 prefix
Validation Rules
The library validates EANs based on these criteria:
- Length: Must be exactly 13 digits
- Content: Must contain only numeric characters (0-9)
- Format: No spaces, dashes, or other separators allowed
Valid EANs:
'1234567890123' ✓ (13 digits, all numeric)
'0000000000000' ✓ (13 digits, all numeric)
'9999999999999' ✓ (13 digits, all numeric)
Invalid EANs:
'123456789012' ✗ (12 digits - too short)
'12345678901234' ✗ (14 digits - too long)
'123456789012A' ✗ (contains letter)
'1234-5678-9012' ✗ (contains dashes)
' 1234567890123' ✗ (contains whitespace)
'' ✗ (empty string - via isEan())
undefined ✗ (undefined - via isEan())
Regex Pattern
The validation uses a simple regex pattern:
const EAN_REGEX = /^[0-9]{13}$/;
Pattern breakdown:
^- Start of string[0-9]- Any digit from 0 to 9{13}- Exactly 13 times$- End of string
API Reference
eanValidator
Angular Forms validator function for validating EAN input.
Type: ValidatorFn
Signature:
eanValidator(control: AbstractControl): ValidationErrors | null
Parameters:
control: AbstractControl- The form control to validate
Returns:
null- If the value is valid or empty/null{ invalidEan: true }- If the value is invalid
Validation Behavior:
- Empty values: Returns
null(considered valid - useValidators.requiredfor required fields) - Valid EAN: Returns
null - Invalid EAN: Returns
{ invalidEan: true }
Example:
import { FormControl } from '@angular/forms';
import { eanValidator } from '@isa/utils/ean-validation';
const eanControl = new FormControl('', [eanValidator]);
eanControl.setValue('1234567890123');
console.log(eanControl.valid); // true
eanControl.setValue('123');
console.log(eanControl.errors); // { invalidEan: true }
eanControl.setValue('');
console.log(eanControl.valid); // true (empty is valid)
isEan
Standalone utility function for programmatic EAN validation.
Signature:
isEan(value: string | undefined): boolean
Parameters:
value: string | undefined- The value to validate
Returns:
true- If the value is a valid 13-digit EANfalse- If the value is invalid, undefined, null, or empty
Validation Behavior:
- undefined/null: Returns
false - Empty string: Returns
false - Valid EAN: Returns
true - Invalid EAN: Returns
false
Example:
import { isEan } from '@isa/utils/ean-validation';
isEan('1234567890123'); // true
isEan('123'); // false
isEan(''); // false
isEan(undefined); // false
isEan(null); // false (TypeScript allows via type coercion)
EAN_REGEX
Regular expression constant for EAN validation.
Type: RegExp
Value: /^[0-9]{13}$/
Note: This is an internal constant. Prefer using eanValidator or isEan() for validation.
Example:
import { EAN_REGEX } from '@isa/utils/ean-validation';
// Direct regex usage (not recommended)
const isValid = EAN_REGEX.test('1234567890123');
console.log(isValid); // true
// Prefer using isEan() instead
const isValidPreferred = isEan('1234567890123');
Usage Examples
Basic Form Validation
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { eanValidator } from '@isa/utils/ean-validation';
@Component({
selector: 'app-product-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="form-field">
<label for="ean">Product EAN*</label>
<input
id="ean"
formControlName="ean"
type="text"
maxlength="13"
placeholder="1234567890123"
/>
@if (ean.touched && ean.errors) {
<div class="errors">
@if (ean.errors['required']) {
<p class="error">EAN is required</p>
}
@if (ean.errors['invalidEan']) {
<p class="error">EAN must be exactly 13 digits</p>
}
</div>
}
</div>
<button type="submit" [disabled]="!form.valid">
Save Product
</button>
</form>
`
})
export class ProductFormComponent {
form = new FormGroup({
ean: new FormControl('', [
Validators.required,
eanValidator
])
});
get ean() {
return this.form.get('ean')!;
}
onSubmit(): void {
if (this.form.valid) {
const productData = this.form.value;
console.log('Saving product:', productData);
// Save logic
}
}
}
Barcode Scanner Integration
import { Component, inject, signal } from '@angular/core';
import { isEan } from '@isa/utils/ean-validation';
interface ScanResult {
code: string;
valid: boolean;
timestamp: Date;
}
@Component({
selector: 'app-barcode-scanner',
template: `
<div class="scanner">
<h2>Barcode Scanner</h2>
<button (click)="startScanning()">
Start Scanning
</button>
<div class="scan-history">
<h3>Scan History</h3>
@for (scan of scanHistory(); track scan.timestamp) {
<div
class="scan-result"
[class.valid]="scan.valid"
[class.invalid]="!scan.valid"
>
<span>{{ scan.code }}</span>
<span>{{ scan.valid ? '✓ Valid' : '✗ Invalid' }}</span>
<span>{{ scan.timestamp | date: 'short' }}</span>
</div>
}
</div>
</div>
`
})
export class BarcodeScannerComponent {
scanHistory = signal<ScanResult[]>([]);
startScanning(): void {
// Simulated barcode scan
this.processScan('1234567890123');
}
processScan(code: string): void {
const valid = isEan(code);
this.scanHistory.update(history => [
{
code,
valid,
timestamp: new Date()
},
...history
]);
if (valid) {
console.log('Valid EAN scanned:', code);
// Process valid EAN
this.lookupProduct(code);
} else {
console.error('Invalid EAN scanned:', code);
// Show error message
}
}
lookupProduct(ean: string): void {
// Product lookup logic
}
}
Search with Validation
import { Component, signal } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { eanValidator, isEan } from '@isa/utils/ean-validation';
@Component({
selector: 'app-product-search',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<div class="search-container">
<input
[formControl]="searchControl"
type="text"
placeholder="Enter 13-digit EAN"
maxlength="13"
(keyup.enter)="search()"
/>
<button
(click)="search()"
[disabled]="!isValidEan()"
>
Search
</button>
@if (searchControl.touched && searchControl.errors?.['invalidEan']) {
<p class="error">
Please enter a valid 13-digit EAN
</p>
}
@if (searchResult()) {
<div class="result">
<h3>Product Found</h3>
<p>EAN: {{ searchResult()!.ean }}</p>
<p>Name: {{ searchResult()!.name }}</p>
</div>
}
@if (notFound()) {
<p class="error">No product found with EAN: {{ lastSearch() }}</p>
}
</div>
`
})
export class ProductSearchComponent {
searchControl = new FormControl('', [eanValidator]);
searchResult = signal<{ ean: string; name: string } | null>(null);
notFound = signal(false);
lastSearch = signal('');
isValidEan(): boolean {
const value = this.searchControl.value;
return !!value && isEan(value);
}
search(): void {
if (!this.isValidEan()) return;
const ean = this.searchControl.value!;
this.lastSearch.set(ean);
// Simulated product lookup
const product = this.mockProductLookup(ean);
if (product) {
this.searchResult.set(product);
this.notFound.set(false);
} else {
this.searchResult.set(null);
this.notFound.set(true);
}
}
mockProductLookup(ean: string): { ean: string; name: string } | null {
// Mock implementation
return { ean, name: `Product ${ean}` };
}
}
Batch Validation
import { Component, signal } from '@angular/core';
import { isEan } from '@isa/utils/ean-validation';
interface ValidationResult {
ean: string;
valid: boolean;
}
@Component({
selector: 'app-batch-validator',
template: `
<div class="batch-validator">
<h2>Batch EAN Validator</h2>
<textarea
[value]="inputEans()"
(input)="inputEans.set($any($event.target).value)"
placeholder="Enter EANs (one per line)"
rows="10"
></textarea>
<button (click)="validate()">Validate All</button>
@if (results().length > 0) {
<div class="results">
<h3>Validation Results</h3>
<p>
Valid: {{ validCount() }} / {{ results().length }}
</p>
<table>
<thead>
<tr>
<th>EAN</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (result of results(); track result.ean) {
<tr [class.valid]="result.valid" [class.invalid]="!result.valid">
<td>{{ result.ean }}</td>
<td>{{ result.valid ? '✓ Valid' : '✗ Invalid' }}</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
`
})
export class BatchValidatorComponent {
inputEans = signal('');
results = signal<ValidationResult[]>([]);
validCount = signal(0);
validate(): void {
const eans = this.inputEans()
.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0);
const results: ValidationResult[] = eans.map(ean => ({
ean,
valid: isEan(ean)
}));
this.results.set(results);
this.validCount.set(results.filter(r => r.valid).length);
}
}
Dynamic Form with Multiple EANs
import { Component } from '@angular/core';
import { FormArray, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { eanValidator } from '@isa/utils/ean-validation';
@Component({
selector: 'app-multi-ean-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<h3>Product EANs</h3>
<div formArrayName="eans">
@for (control of eanControls.controls; track $index) {
<div class="ean-field">
<input
[formControlName]="$index"
type="text"
maxlength="13"
placeholder="1234567890123"
/>
@if (control.touched && control.errors?.['invalidEan']) {
<span class="error">Invalid EAN</span>
}
<button type="button" (click)="removeEan($index)">
Remove
</button>
</div>
}
</div>
<button type="button" (click)="addEan()">
Add EAN
</button>
<button type="submit" [disabled]="!form.valid">
Save
</button>
</form>
`
})
export class MultiEanFormComponent {
form = new FormGroup({
eans: new FormArray([
new FormControl('', [eanValidator])
])
});
get eanControls() {
return this.form.get('eans') as FormArray;
}
addEan(): void {
this.eanControls.push(
new FormControl('', [eanValidator])
);
}
removeEan(index: number): void {
this.eanControls.removeAt(index);
}
onSubmit(): void {
if (this.form.valid) {
const eans = this.eanControls.value;
console.log('Saving EANs:', eans);
}
}
}
Type Guard Usage
import { Component } from '@angular/core';
import { isEan } from '@isa/utils/ean-validation';
interface Product {
id: number;
name: string;
ean?: string; // Optional EAN
}
@Component({
selector: 'app-product-list',
template: `
<div class="products">
@for (product of products; track product.id) {
<div class="product">
<h3>{{ product.name }}</h3>
@if (hasValidEan(product)) {
<p>EAN: {{ product.ean }}</p>
} @else {
<p class="warning">No valid EAN</p>
}
</div>
}
</div>
`
})
export class ProductListComponent {
products: Product[] = [
{ id: 1, name: 'Product A', ean: '1234567890123' },
{ id: 2, name: 'Product B', ean: '123' }, // Invalid
{ id: 3, name: 'Product C' }, // Missing
];
hasValidEan(product: Product): boolean {
return isEan(product.ean);
}
}
EAN Format
Standard Format
EAN-13 Structure:
┌──────────────────────────────────┐
│ 1 2 3 4 5 6 7 8 9 0 1 2 3 │
│ └──┬──┘ └───────┬────────┘ │ │ │
│ │ │ │ │ │
│ Prefix Manufacturer Product Check │
│ Code Code Digit │
└──────────────────────────────────┘
Common Prefixes
| Prefix | Region/Type |
|---|---|
| 000-019 | GS1 US |
| 020-029 | Restricted distribution |
| 030-039 | GS1 US |
| 040-049 | Restricted distribution |
| 050-059 | GS1 US reserved |
| 060-139 | GS1 US |
| 200-299 | Restricted distribution |
| 300-379 | GS1 France |
| 380 | GS1 Bulgaria |
| 383 | GS1 Slovenia |
| 385 | GS1 Croatia |
| 400-440 | GS1 Germany |
| 450-459, 490-499 | GS1 Japan |
| 460-469 | GS1 Russia |
| 470 | GS1 Kyrgyzstan |
| 471 | GS1 Taiwan |
| 474 | GS1 Estonia |
| 475 | GS1 Latvia |
| 476 | GS1 Azerbaijan |
| 477 | GS1 Lithuania |
| 478 | GS1 Uzbekistan |
| 479 | GS1 Sri Lanka |
| 480 | GS1 Philippines |
| 481 | GS1 Belarus |
| 482 | GS1 Ukraine |
| 484 | GS1 Moldova |
| 485 | GS1 Armenia |
| 486 | GS1 Georgia |
| 487 | GS1 Kazakhstan |
| 489 | GS1 Hong Kong |
| 500-509 | GS1 UK |
| 520-521 | GS1 Association Greece |
| 528 | GS1 Lebanon |
| 529 | GS1 Cyprus |
| 530 | GS1 Albania |
| 531 | GS1 Macedonia |
| 535 | GS1 Malta |
| 539 | GS1 Ireland |
| 540-549 | GS1 Belgium & Luxembourg |
| 560 | GS1 Portugal |
| 569 | GS1 Iceland |
| 570-579 | GS1 Denmark |
| 590 | GS1 Poland |
| 594 | GS1 Romania |
| 599 | GS1 Hungary |
| 600-601 | GS1 South Africa |
| 603 | GS1 Ghana |
| 604 | GS1 Senegal |
| 608 | GS1 Bahrain |
| 609 | GS1 Mauritius |
| 611 | GS1 Morocco |
| 613 | GS1 Algeria |
| 615 | GS1 Nigeria |
| 616 | GS1 Kenya |
| 618 | GS1 Ivory Coast |
| 619 | GS1 Tunisia |
| 620 | GS1 Tanzania |
| 621 | GS1 Syria |
| 622 | GS1 Egypt |
| 623 | GS1 Brunei |
| 624 | GS1 Libya |
| 625 | GS1 Jordan |
| 626 | GS1 Iran |
| 627 | GS1 Kuwait |
| 628 | GS1 Saudi Arabia |
| 629 | GS1 Emirates |
| 640-649 | GS1 Finland |
| 690-699 | GS1 China |
| 700-709 | GS1 Norway |
| 729 | GS1 Israel |
| 730-739 | GS1 Sweden |
| 740 | GS1 Guatemala |
| 741 | GS1 El Salvador |
| 742 | GS1 Honduras |
| 743 | GS1 Nicaragua |
| 744 | GS1 Costa Rica |
| 745 | GS1 Panama |
| 746 | GS1 Dominican Republic |
| 750 | GS1 Mexico |
| 754-755 | GS1 Canada |
| 759 | GS1 Venezuela |
| 760-769 | GS1 Switzerland |
| 770-771 | GS1 Colombia |
| 773 | GS1 Uruguay |
| 775 | GS1 Peru |
| 777 | GS1 Bolivia |
| 778-779 | GS1 Argentina |
| 780 | GS1 Chile |
| 784 | GS1 Paraguay |
| 786 | GS1 Ecuador |
| 789-790 | GS1 Brazil |
| 800-839 | GS1 Italy |
| 840-849 | GS1 Spain |
| 850 | GS1 Cuba |
| 858 | GS1 Slovakia |
| 859 | GS1 Czech |
| 860 | GS1 Serbia |
| 865 | GS1 Mongolia |
| 867 | GS1 North Korea |
| 868-869 | GS1 Turkey |
| 870-879 | GS1 Netherlands |
| 880 | GS1 South Korea |
| 884 | GS1 Cambodia |
| 885 | GS1 Thailand |
| 888 | GS1 Singapore |
| 890 | GS1 India |
| 893 | GS1 Vietnam |
| 896 | GS1 Pakistan |
| 899 | GS1 Indonesia |
| 900-919 | GS1 Austria |
| 930-939 | GS1 Australia |
| 940-949 | GS1 New Zealand |
| 950 | GS1 Global Office |
| 951 | GS1 Global Office (EPCglobal) |
| 955 | GS1 Malaysia |
| 958 | GS1 Macau |
| 960-969 | GS1 Global Office (GTIN-8) |
| 977 | Serial publications (ISSN) |
| 978-979 | Bookland (ISBN) |
| 980 | Refund receipts |
| 981-984 | GS1 coupon identification |
| 990-999 | GS1 coupon identification |
Note: This library validates format only (13 digits), not check digit accuracy or prefix validity.
Architecture Notes
Design Patterns
Validator Function Pattern
The eanValidator follows Angular's ValidatorFn pattern:
export const eanValidator: ValidatorFn = (
control: AbstractControl
): ValidationErrors | null => {
const value = control.value;
if (value && !EAN_REGEX.test(value)) {
return { invalidEan: true };
}
return null;
};
Benefits:
- Composable with other validators
- Reusable across multiple form controls
- Type-safe with TypeScript
- Follows Angular conventions
Pure Function Pattern
The isEan function is a pure function with no side effects:
export const isEan = (value: string | undefined): boolean => {
if (!value) {
return false;
}
return EAN_REGEX.test(value);
};
Benefits:
- Predictable - same input always produces same output
- Testable - easy to unit test
- Framework agnostic - can be used outside Angular
- No dependencies - doesn't rely on external state
Performance Considerations
- Regex Performance - Simple regex pattern for O(n) validation
- No External Dependencies - Minimal bundle size impact
- Null-Safe - Early returns for undefined/null values
- Reusable Regex - Single compiled regex constant
Future Enhancements
Potential improvements identified:
- Check Digit Validation - Validate the EAN-13 check digit algorithm
- EAN-8 Support - Support for 8-digit EAN format
- UPC Support - Support for 12-digit UPC format
- Prefix Validation - Validate GS1 country/region prefixes
- Format Conversion - Convert between EAN-13, EAN-8, and UPC
- Barcode Generation - Generate barcode images from EAN
- Async Validation - Validate against product database
Testing
The library uses Vitest with Angular Testing Utilities for testing.
Running Tests
# Run tests for this library
npx nx test ean-validation --skip-nx-cache
# Run tests with coverage
npx nx test ean-validation --code-coverage --skip-nx-cache
# Run tests in watch mode
npx nx test ean-validation --watch
Test Structure
The library includes comprehensive unit tests covering:
-
eanValidator Tests:
- Valid 13-digit EAN returns null
- Empty value returns null (valid)
- Invalid EAN returns error object
- Null/undefined values handled correctly
-
isEan Tests:
- Valid 13-digit EAN returns true
- Invalid EAN returns false
- Empty string returns false
- Undefined returns false
Example Test
import { describe, it, expect } from 'vitest';
import { FormControl } from '@angular/forms';
import { eanValidator, isEan } from './ean-validation';
describe('eanValidator', () => {
it('should return null for valid EAN', () => {
// Arrange
const control = new FormControl('1234567890123');
// Act
const result = eanValidator(control);
// Assert
expect(result).toBeNull();
});
it('should return null for empty value', () => {
// Arrange
const control = new FormControl('');
// Act
const result = eanValidator(control);
// Assert
expect(result).toBeNull();
});
it('should return error for invalid EAN', () => {
// Arrange
const control = new FormControl('123');
// Act
const result = eanValidator(control);
// Assert
expect(result).toEqual({ invalidEan: true });
});
});
describe('isEan', () => {
it('should return true for valid EAN', () => {
// Arrange
const validEan = '1234567890123';
// Act
const result = isEan(validEan);
// Assert
expect(result).toBe(true);
});
it('should return false for undefined value', () => {
// Arrange
const undefinedValue = undefined;
// Act
const result = isEan(undefinedValue);
// Assert
expect(result).toBe(false);
});
it('should return false for invalid EAN', () => {
// Arrange
const invalidEan = '123';
// Act
const result = isEan(invalidEan);
// Assert
expect(result).toBe(false);
});
});
Dependencies
Required Libraries
@angular/core- For TypeScript types@angular/forms- ForValidatorFn,AbstractControl,ValidationErrorstypes
Path Alias
Import from: @isa/utils/ean-validation
Exports
eanValidator- Angular Forms validator functionisEan- Standalone validation utility functionEAN_REGEX- Regular expression constant (internal use)
Best Practices
1. Use with Validators.required
Combine with Validators.required for required fields:
// Good - Required + EAN validation
const eanControl = new FormControl('', [
Validators.required,
eanValidator
]);
// Avoid - Only EAN validation (allows empty)
const eanControl = new FormControl('', [eanValidator]);
2. Provide Clear Error Messages
Show user-friendly error messages:
// Good - Clear, actionable error message
@if (ean.errors?.['invalidEan']) {
<p class="error">
Please enter a valid 13-digit EAN (e.g., 1234567890123)
</p>
}
// Avoid - Generic or unclear message
@if (ean.errors?.['invalidEan']) {
<p class="error">Invalid</p>
}
3. Use isEan for Type Guards
Use isEan() for runtime type checking:
// Good - Type-safe validation
function processEan(code: string | undefined): void {
if (isEan(code)) {
// TypeScript knows code is string here
console.log('Processing:', code.toUpperCase());
}
}
// Avoid - Unsafe type assumption
function processEan(code: string): void {
// Might throw if code is invalid
console.log('Processing:', code.toUpperCase());
}
4. Add Maxlength Attribute
Prevent users from entering more than 13 digits:
// Good - Limit input length
<input
formControlName="ean"
type="text"
maxlength="13"
placeholder="1234567890123"
/>
// Avoid - No length restriction
<input
formControlName="ean"
type="text"
/>
5. Handle Validation in Components
Keep validation logic in components, not templates:
// Good - Logic in component
canSubmit(): boolean {
return this.form.valid && isEan(this.form.value.ean);
}
// Avoid - Complex logic in template
@if (form.valid && form.value.ean && /^[0-9]{13}$/.test(form.value.ean)) {
...
}
Limitations
What This Library Does NOT Do
- Check Digit Validation - Does not validate the EAN-13 checksum digit
- Database Validation - Does not verify if EAN exists in product database
- Prefix Validation - Does not validate GS1 country/region prefixes
- Format Conversion - Does not convert between EAN/UPC formats
- Barcode Generation - Does not generate barcode images
When to Use Additional Validation
For production systems, consider:
- Check digit validation for data integrity
- Database lookup for product existence
- Prefix validation for regional compliance
- Duplicate detection in batch processing
License
Internal ISA Frontend library - not for external distribution.