Angular 17+ standalone component via multipleupload/angular
A standalone Angular component (<multiple-upload>) that can be imported directly into any standalone-compatible Angular module or component. Late-binds @angular/core via lazy evaluation so non-Angular consumers don't pay the peer-dep tax. Works with Angular 17, 18, 19, 20.
Subpath import:
multipleupload/angular ships in the same npm package. @angular/core is an optional peer dep - only resolved when you actually use the component class.
Install
npm install multipleupload @angular/core
Standalone component usage
// app.component.ts
import { Component } from '@angular/core';
import { MultipleUploadComponent } from 'multipleupload/angular';
import 'multipleupload/multipleupload.css';
@Component({
selector: 'app-root',
standalone: true,
imports: [MultipleUploadComponent],
template: `
<multiple-upload
[options]="uploadOptions"
(taskComplete)="onComplete($event)"
(taskProgress)="onProgress($event)"
(uploadError)="onError($event)">
</multiple-upload>
`
})
export class AppComponent {
uploadOptions = {
uploadUrl: '/api/upload',
multiple: true,
autoUpload: false,
strategy: 'chunked',
chunkSize: 5 * 1024 * 1024,
chunkConcurrency: 4
};
onComplete([task, result]: any) {
console.log('uploaded', result.fileGuid, result.fileName);
}
onProgress(task: any) {
console.log(task.fileName, task.progress + '%');
}
onError(err: any) {
console.error(err);
}
}Emitted events
Every core event is a same-named @Output(). Multi-arg events (taskComplete, taskFailed) emit as a tuple [task, result].
taskAdded, taskRemoved, taskStarted, taskProgress, taskComplete, taskFailed, taskCancelled, taskPaused, taskResumed, queueComplete, allComplete, progress, stateRestored, uploadError // 'error' is renamed to avoid DOM ErrorEvent collision
Use without the component (services, tests, manual bootstrap)
import { attachUploader } from 'multipleupload/angular';
// In an Angular service or anywhere outside a component context:
const handle = attachUploader(hostEl, { uploadUrl: '/api/upload' }, {
taskComplete: (task, result) => console.log(result),
error: (err) => console.error(err)
});
// Tear down later:
handle.destroy();Imperative API (via @ViewChild + a host ref)
// Wrap in a small directive if you need imperative access from the parent.
// The component itself doesn't expose ViewChild on the underlying instance,
// but a thin pattern works:
@Component({
template: `<div #host></div><button (click)="upload()">Upload</button>`
})
export class ManualUploaderComponent implements AfterViewInit, OnDestroy {
@ViewChild('host') hostRef!: ElementRef;
private handle: any;
ngAfterViewInit() {
this.handle = attachUploader(this.hostRef.nativeElement, {
uploadUrl: '/api/upload', autoUpload: false
});
}
upload() { this.handle.instance.upload(); }
ngOnDestroy() { this.handle?.destroy(); }
}Why lazy @angular/core binding?
- The wrapper module itself
require()s nothing from@angular/coreat load time. - The
MultipleUploadComponentgetter callsrequire('@angular/core')lazily on first access. - Non-Angular consumers (React, Vue, Svelte, plain JS) can keep importing
multipleupload/angular'sattachUploaderwithout dragging in 100 KB of Angular runtime.