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

@libs-ui/components-inputs-upload

v0.2.357-2

Published

> Component upload file toàn diện hỗ trợ kéo thả, xem trước, chỉnh sửa ảnh và quản lý nhiều loại tệp khác nhau.

Readme

@libs-ui/components-inputs-upload

Component upload file toàn diện hỗ trợ kéo thả, xem trước, chỉnh sửa ảnh và quản lý nhiều loại tệp khác nhau.

Giới thiệu

@libs-ui/components-inputs-upload cung cấp giao diện tải tệp mạnh mẽ cho Angular, tích hợp sẵn kéo thả (drag & drop), xem trước hình ảnh/tài liệu qua Gallery Viewer và Preview File, chỉnh sửa ảnh (cắt/xoay) bằng Image Editor động. Component sử dụng Angular Signals để quản lý trạng thái tệp theo thời gian thực, hỗ trợ kiểm soát kích thước, số lượng, định dạng và tích hợp luồng upload có tiến trình phần trăm.

Tính năng

  • ✅ Hỗ trợ đa định dạng: image, video, audio, document và các tổ hợp
  • ✅ Kéo thả tệp trực tiếp vào vùng upload (Drag & Drop)
  • ✅ Tích hợp Image Editor (cắt, xoay) với tỉ lệ khung hình tùy chỉnh
  • ✅ Xem trước hình ảnh qua Gallery Viewer và tài liệu qua Preview File
  • ✅ Chế độ Avatar — tự động gán ảnh đầu tiên làm ảnh đại diện
  • ✅ Kiểm soát kích thước tối đa theo từng loại file (image / video / audio / document)
  • ✅ Kiểm soát tổng dung lượng và số lượng tệp tối đa
  • ✅ Hai chế độ hiển thị: full (chi tiết) và short (gọn nhẹ)
  • ✅ Nút tải tệp mẫu đi kèm (download sample file)
  • ✅ Hiển thị tiến trình upload phần trăm qua IUploadFunctionControlEvent
  • ✅ Validate bắt buộc tích hợp (validRequired)
  • ✅ Chế độ readonly và disable riêng biệt

Khi nào sử dụng

  • Tải lên ảnh đại diện người dùng với crop tỉ lệ cố định
  • Đính kèm tài liệu (PDF, Excel, Word) trong biểu mẫu
  • Quản lý thư viện hình ảnh hoặc video với tính năng xem trước
  • Cần giới hạn nghiêm ngặt kích thước và định dạng tệp được phép
  • Form có yêu cầu upload bắt buộc với validate tích hợp
  • Cần kiểm soát tiến trình upload qua API bên ngoài

Cài đặt

npm install @libs-ui/components-inputs-upload

Import

import { LibsUiComponentsInputsUploadComponent } from '@libs-ui/components-inputs-upload';

// Các directives độc lập (nếu cần dùng riêng)
import { LibsUiComponentsInputsUploadDirective } from '@libs-ui/components-inputs-upload';
import { LibsUiComponentsInputsUploadDropFileDirective } from '@libs-ui/components-inputs-upload';

// Sub-component Avatar
import { LibsUiComponentsInputsUploadAvatarComponent } from '@libs-ui/components-inputs-upload';

// Types & Interfaces
import {
  TYPE_FILE_UPLOAD,
  TYPE_MODE_FILE_DISPLAY,
  IUploadFunctionControlEvent,
  IUploadConfigDownloadSampleFile,
  IUploadDescriptionFormatAndSizeFile,
} from '@libs-ui/components-inputs-upload';

Đăng ký vào component standalone:

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsUploadComponent],
})
export class MyComponent {}

Ví dụ sử dụng

Ví dụ 1 — Upload nhiều ảnh cơ bản

<libs_ui-components-inputs-upload
  [fileType]="'image'"
  [multiple]="true"
  [limitFile]="5"
  [maxImageSize]="5 * 1024 * 1024"
  (outFileChanged)="handlerFileChanged($event)"
/>
import { Component, signal, WritableSignal } from '@angular/core';
import { LibsUiComponentsInputsUploadComponent } from '@libs-ui/components-inputs-upload';
import { IFile } from '@libs-ui/interfaces-types';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsUploadComponent],
  templateUrl: './my.component.html',
})
export class MyComponent {
  protected files = signal<Array<WritableSignal<IFile>>>([]);

  protected handlerFileChanged(files: Array<WritableSignal<IFile>>): void {
    this.files.set(files);
  }
}

Ví dụ 2 — Chế độ Avatar với cắt ảnh tỉ lệ 1:1

<libs_ui-components-inputs-upload
  [fileType]="'image'"
  [multiple]="false"
  [canSetAvatar]="true"
  [aspectRatio]="{ width: 1, height: 1 }"
  [modeDisplayFile]="'short'"
  (outFileChanged)="handlerAvatarChanged($event)"
/>
import { Component, signal, WritableSignal } from '@angular/core';
import { LibsUiComponentsInputsUploadComponent } from '@libs-ui/components-inputs-upload';
import { IAspectRatio, IFile } from '@libs-ui/interfaces-types';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsUploadComponent],
  templateUrl: './my.component.html',
})
export class MyComponent {
  protected avatar = signal<WritableSignal<IFile> | undefined>(undefined);

  protected handlerAvatarChanged(files: Array<WritableSignal<IFile>>): void {
    const avatarFile = files.find((file) => file().isAvatar);
    this.avatar.set(avatarFile);
  }
}

Ví dụ 3 — Đa định dạng với validate bắt buộc và tải tệp mẫu

<libs_ui-components-inputs-upload
  [fileType]="'image_video_document'"
  [multiple]="true"
  [limitFile]="10"
  [maxTotalSize]="50 * 1024 * 1024"
  [validRequired]="{ isRequired: true, message: 'Vui lòng tải lên ít nhất 1 tệp' }"
  [configDownloadSampleFile]="{
    title: 'Tải file mẫu',
    url: 'assets/sample-template.xlsx',
    position: 'top'
  }"
  (outFunctionsControl)="handlerFunctionsControl($event)"
  (outFileChanged)="handlerFileChanged($event)"
  (outFileRemoved)="handlerFileRemoved($event)"
/>
import { Component, signal, WritableSignal } from '@angular/core';
import { LibsUiComponentsInputsUploadComponent, IUploadFunctionControlEvent } from '@libs-ui/components-inputs-upload';
import { IFile } from '@libs-ui/interfaces-types';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsUploadComponent],
  templateUrl: './my.component.html',
})
export class MyComponent {
  private uploadControl: IUploadFunctionControlEvent | undefined;
  protected files = signal<Array<WritableSignal<IFile>>>([]);

  protected handlerFunctionsControl(control: IUploadFunctionControlEvent): void {
    this.uploadControl = control;
  }

  protected handlerFileChanged(files: Array<WritableSignal<IFile>>): void {
    this.files.set(files);
  }

  protected handlerFileRemoved(file: WritableSignal<IFile>): void {
    console.log('File removed:', file().name);
  }

  protected async handlerSubmit(): Promise<void> {
    const isValid = await this.uploadControl?.checkIsValid();
    if (!isValid) {
      return;
    }
    // tiến hành submit
  }

  protected async handlerClear(): Promise<void> {
    await this.uploadControl?.removeAll();
  }
}

Ví dụ 4 — Upload file với hiển thị tiến trình

<libs_ui-components-inputs-upload
  [fileType]="'image_document'"
  [multiple]="true"
  [originFiles]="existingFiles()"
  (outFunctionsControl)="handlerFunctionsControl($event)"
  (outFileChanged)="handlerFileChanged($event)"
/>
import { Component, signal, WritableSignal } from '@angular/core';
import { LibsUiComponentsInputsUploadComponent, IUploadFunctionControlEvent } from '@libs-ui/components-inputs-upload';
import { IFile } from '@libs-ui/interfaces-types';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsUploadComponent],
  templateUrl: './my.component.html',
})
export class MyComponent {
  private uploadControl: IUploadFunctionControlEvent | undefined;
  protected files = signal<Array<WritableSignal<IFile>>>([]);
  protected existingFiles = signal<Array<WritableSignal<IFile>>>([]);

  protected handlerFunctionsControl(control: IUploadFunctionControlEvent): void {
    this.uploadControl = control;
  }

  protected handlerFileChanged(files: Array<WritableSignal<IFile>>): void {
    this.files.set(files);
    // Giả lập tiến trình upload
    files.forEach((file) => {
      const id = file().id;
      if (!id) {
        return;
      }
      this.uploadControl?.uploading({ percent: 50 }, id);
      setTimeout(() => {
        this.uploadControl?.uploading({ percent: 100 }, id);
      }, 2000);
    });
  }
}

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | allowShowPushMessageMaxSizeError | boolean | false | Hiển thị notification toast khi file vượt quá kích thước — chỉ áp dụng chế độ single | [allowShowPushMessageMaxSizeError]="true" | | aspectRatio | IAspectRatio | undefined | Tỉ lệ khung hình cố định khi mở Image Editor để crop ảnh | [aspectRatio]="{ width: 16, height: 9 }" | | audioExtList | string[] | AudioExtList | Danh sách đuôi file âm thanh được phép tải lên | [audioExtList]="['mp3', 'wav']" | | canSetAvatar | boolean | false | Bật chế độ chọn ảnh đại diện — file ảnh đầu tiên tự động được đặt làm avatar | [canSetAvatar]="true" | | canUploadIfHasExistFile | boolean | false | Cho phép tải lên tiếp khi đã có file (áp dụng chế độ single — thay thế file cũ) | [canUploadIfHasExistFile]="true" | | classIncludeAvatar | string | '' | Class CSS bổ sung cho vùng hiển thị avatar | [classIncludeAvatar]="'w-[80px] h-[80px]'" | | classIncludeFileContent | string | '' | Class CSS bổ sung cho vùng nội dung danh sách file | [classIncludeFileContent]="'mt-2'" | | classIncludeListItem | string | undefined | Class CSS bổ sung cho từng item file trong danh sách | [classIncludeListItem]="'border-dashed'" | | configDescriptionInputUpload | IMessageTranslate | { message: 'i18n_drag_file_here_to_upload_or_select_file' } | Cấu hình văn bản mô tả hiển thị trong vùng kéo thả | [configDescriptionInputUpload]="{ message: 'i18n_drop_files_here' }" | | configDownloadSampleFile | IUploadConfigDownloadSampleFile | undefined | Cấu hình nút tải file mẫu — hỗ trợ URL hoặc callback tùy chỉnh | [configDownloadSampleFile]="{ title: 'Tải mẫu', url: '/assets/sample.xlsx' }" | | descriptionFormatAndSizeFile | Array<IUploadDescriptionFormatAndSizeFile> | undefined | Ghi đè mô tả định dạng và kích thước file — mặc định tự sinh từ fileType + maxSize | [descriptionFormatAndSizeFile]="customDesc" | | disable | boolean | false | Vô hiệu hóa toàn bộ vùng upload | [disable]="isDisabled()" | | documentExtList | string[] | DocumentExtList | Danh sách đuôi file tài liệu được phép | [documentExtList]="['pdf', 'docx', 'xlsx']" | | fileType | TYPE_FILE_UPLOAD | 'image_video_document' | Nhóm định dạng file được phép tải lên — ảnh hưởng đến accept filter | [fileType]="'image'" | | ignoreIconEdit | boolean | false | Ẩn nút chỉnh sửa ảnh (Image Editor) | [ignoreIconEdit]="true" | | ignoreIconPreview | boolean | true | Ẩn nút xem trước file — mặc định đã ẩn | [ignoreIconPreview]="false" | | ignoreIconRemove | boolean | false | Ẩn nút xóa file | [ignoreIconRemove]="true" | | ignoreShowSizeFile | boolean | false | Ẩn thông tin kích thước file trong danh sách | [ignoreShowSizeFile]="true" | | imageExtList | string[] | ImageExtList | Danh sách đuôi file ảnh được phép | [imageExtList]="['jpg', 'png', 'webp']" | | labelConfig | ILabel | undefined | Cấu hình label hiển thị phía trên vùng upload | [labelConfig]="{ label: 'Tệp đính kèm', required: true }" | | limitFile | number | 10 | Số lượng file tối đa được phép tải lên | [limitFile]="3" | | maxAudioSize | number | 10485760 (10MB) | Kích thước tối đa (bytes) cho mỗi file âm thanh | [maxAudioSize]="20 * 1024 * 1024" | | maxDocumentSize | number | 10485760 (10MB) | Kích thước tối đa (bytes) cho mỗi file tài liệu | [maxDocumentSize]="5 * 1024 * 1024" | | maxImageSize | number | 5242880 (5MB) | Kích thước tối đa (bytes) cho mỗi file ảnh | [maxImageSize]="2 * 1024 * 1024" | | maxTotalSize | number | 10485760 (10MB) | Tổng dung lượng tối đa (bytes) của toàn bộ tệp được upload | [maxTotalSize]="50 * 1024 * 1024" | | maxVideoSize | number | 10485760 (10MB) | Kích thước tối đa (bytes) cho mỗi file video | [maxVideoSize]="100 * 1024 * 1024" | | messageFileUploadError | string | 'i18n_invalid_file_upload' | Key i18n thông báo lỗi khi file không hợp lệ (chế độ multiple) | [messageFileUploadError]="'i18n_custom_error'" | | messageMaxSizeError | string | 'i18n_file_size_exceeds_the_allowed_limit' | Key i18n thông báo lỗi khi file vượt kích thước giới hạn | [messageMaxSizeError]="'i18n_file_too_large'" | | messageTotalFileExceedsError | string | 'i18n_file_number_exceeds_the_allowed_limit_please_delete_the_file' | Key i18n thông báo lỗi khi số lượng file vượt limitFile | [messageTotalFileExceedsError]="'i18n_too_many_files'" | | messageTypeFileError | string | 'i18n_the_file_support_format_is_not_correct' | Key i18n thông báo lỗi khi định dạng file không được hỗ trợ | [messageTypeFileError]="'i18n_format_not_supported'" | | modeDisplayFile | 'full' \| 'short' | 'full' | Chế độ hiển thị danh sách file: full (tên, kích thước, actions) hoặc short (ảnh thumbnail nhỏ) | [modeDisplayFile]="'short'" | | multiple | boolean | undefined | Cho phép chọn nhiều file cùng lúc | [multiple]="true" | | originFiles | Array<WritableSignal<IFile>> | [] | Danh sách file khởi tạo ban đầu (từ API hoặc edit form) | [originFiles]="existingFiles()" | | readonly | boolean | false | Chế độ chỉ đọc — hiển thị file nhưng không cho phép thao tác | [readonly]="isReadonly()" | | showBorderErrorAllItemWhenError | boolean | false | Hiển thị viền đỏ toàn bộ item khi có bất kỳ lỗi nào | [showBorderErrorAllItemWhenError]="true" | | showPopupUploadWhenHasFileAndModeSingle | boolean | false | Tự động mở dialog chọn file khi click vào file đã có (chế độ single) | [showPopupUploadWhenHasFileAndModeSingle]="true" | | showVideoDuration | boolean | false | Hiển thị thời lượng video trong thumbnail | [showVideoDuration]="true" | | validRequired | IIsValidRequired | undefined | Cấu hình validate bắt buộc — hiển thị lỗi khi chưa có file | [validRequired]="{ isRequired: true, message: 'Vui lòng tải lên ít nhất 1 tệp' }" | | videoExtList | string[] | VideoExtList | Danh sách đuôi file video được phép | [videoExtList]="['mp4', 'mov', 'avi']" | | zIndex | number | 1200 | Z-index cho các popup động (Gallery Viewer, Image Editor, Preview File) | [zIndex]="1500" |

@Output()

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outClose) | boolean | Phát ra khi đóng popup upload | handlerClose(val: boolean): void { event.stopPropagation(); ... } | (outClose)="handlerClose($event)" | | (outFileChanged) | Array<WritableSignal<IFile>> | Phát ra danh sách file hiện tại mỗi khi có thay đổi (thêm, xóa, chỉnh sửa) | handlerFileChanged(files: Array<WritableSignal<IFile>>): void { this.files.set(files); } | (outFileChanged)="handlerFileChanged($event)" | | (outFileRemoved) | WritableSignal<IFile> | Phát ra file vừa bị xóa — chỉ phát ra khi xóa file có trong originFiles | handlerFileRemoved(file: WritableSignal<IFile>): void { console.log(file().name); } | (outFileRemoved)="handlerFileRemoved($event)" | | (outFunctionsControl) | IUploadFunctionControlEvent | Phát ra object chứa các hàm điều khiển component từ bên ngoài — phát ngay khi ngOnInit | handlerFunctionsControl(ctrl: IUploadFunctionControlEvent): void { this.uploadControl = ctrl; } | (outFunctionsControl)="handlerFunctionsControl($event)" |

FunctionsControl — Điều khiển từ bên ngoài

outFunctionsControl cung cấp IUploadFunctionControlEvent ngay khi component khởi tạo. Lưu tham chiếu để gọi các hàm điều khiển:

private uploadControl: IUploadFunctionControlEvent | undefined;

protected handlerFunctionsControl(ctrl: IUploadFunctionControlEvent): void {
  this.uploadControl = ctrl;
}

// Validate — dùng trước khi submit form
protected async handlerSubmit(): Promise<void> {
  const isValid = await this.uploadControl?.checkIsValid();
  if (!isValid) {
    return;
  }
  // proceed with form submit
}

// Xóa tất cả file
protected async handlerReset(): Promise<void> {
  await this.uploadControl?.removeAll();
}

// Cập nhật tiến trình upload file theo id
protected updateProgress(fileId: string, percent: number): void {
  this.uploadControl?.uploading({ percent }, fileId);
}

// Set thông báo lỗi — toàn component hoặc file cụ thể theo id
protected setError(message: string, fileId?: string): void {
  this.uploadControl?.setMessageError(message, fileId);
}

// Kích hoạt dialog chọn file (tương đương click vào nút upload)
protected handlerTriggerUpload(): void {
  this.uploadControl?.handlerUploadFile();
}

Sub-components

LibsUiComponentsInputsUploadAvatarComponent

Component con hiển thị thumbnail cho từng file trong danh sách. Dùng độc lập khi cần custom UI danh sách file.

import { LibsUiComponentsInputsUploadAvatarComponent } from '@libs-ui/components-inputs-upload';

Selector: libs_ui-components-inputs-upload-avatar

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | item | IFile (model) | bắt buộc | File cần hiển thị thumbnail — là model() hai chiều | [(item)]="fileSignal()" | | classInclude | string | '' | Class CSS bổ sung cho container | [classInclude]="'w-[60px] h-[60px]'" | | disable | boolean | undefined | Vô hiệu hóa tương tác | [disable]="true" | | showVideoDuration | boolean | undefined | Hiển thị thời lượng video | [showVideoDuration]="true" | | size | number | undefined | Kích thước ảnh thumbnail (px) | [size]="80" |

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outOpenPreview) | IFile | Phát ra khi click vào thumbnail để xem trước | handlerOpenPreview(file: IFile): void { event.stopPropagation(); ... } | (outOpenPreview)="handlerOpenPreview($event)" |

LibsUiComponentsInputsUploadDirective

Directive gắn vào element bất kỳ để biến nó thành trigger mở dialog chọn file.

import { LibsUiComponentsInputsUploadDirective } from '@libs-ui/components-inputs-upload';

Selector: [LibsUiComponentsInputsUploadDirective]

<button LibsUiComponentsInputsUploadDirective
  [accessFiles]="'.jpg,.png,.pdf'"
  [multiple]="true"
  (outUploadFiles)="handlerUploadFiles($event)"
  (outUploadFile)="handlerUploadFile($event)">
  Chọn file
</button>

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | accessFiles | string | 'image/x-png,image/jpg,image/jpeg,...' | Chuỗi MIME types hoặc extensions được chấp nhận | [accessFiles]="'.jpg,.png,.pdf'" | | multiple | boolean | true | Cho phép chọn nhiều file | [multiple]="false" |

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outUploadFiles) | File[] | Phát ra khi chọn nhiều file (multiple = true) | handlerUploadFiles(files: File[]): void { ... } | (outUploadFiles)="handlerUploadFiles($event)" | | (outUploadFile) | File | Phát ra khi chọn một file (multiple = false) | handlerUploadFile(file: File): void { ... } | (outUploadFile)="handlerUploadFile($event)" |

LibsUiComponentsInputsUploadDropFileDirective

Directive gắn vào container để nhận file kéo thả vào.

import { LibsUiComponentsInputsUploadDropFileDirective } from '@libs-ui/components-inputs-upload';

Selector: [LibsUiComponentsInputsUploadDropFileDirective]

<div LibsUiComponentsInputsUploadDropFileDirective
  [multiple]="true"
  (outDragOver)="handlerDragOver($event)"
  (outDragLeave)="handlerDragLeave($event)"
  (outDropFiles)="handlerDropFiles($event)">
  Kéo thả file vào đây
</div>

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | multiple | boolean | true | Cho phép thả nhiều file | [multiple]="false" |

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outDragOver) | IEvent | Phát ra khi file được kéo vào vùng drop | handlerDragOver(e: IEvent): void { ... } | (outDragOver)="handlerDragOver($event)" | | (outDragLeave) | IEvent | Phát ra khi file rời khỏi vùng drop | handlerDragLeave(e: IEvent): void { ... } | (outDragLeave)="handlerDragLeave($event)" | | (outDrop) | IEvent | Phát ra khi thả file (raw event) | handlerDrop(e: IEvent): void { ... } | (outDrop)="handlerDrop($event)" | | (outDropFiles) | File[] | Phát ra danh sách file khi thả nhiều (multiple = true) | handlerDropFiles(files: File[]): void { ... } | (outDropFiles)="handlerDropFiles($event)" | | (outDropFile) | File | Phát ra file đầu tiên khi thả (multiple = false) | handlerDropFile(file: File): void { ... } | (outDropFile)="handlerDropFile($event)" |

Types & Interfaces

import {
  TYPE_FILE_UPLOAD,
  TYPE_MODE_FILE_DISPLAY,
  IUploadFunctionControlEvent,
  IUploadConfigDownloadSampleFile,
  IUploadDescriptionFormatAndSizeFile,
} from '@libs-ui/components-inputs-upload';

TYPE_FILE_UPLOAD

Kiểu string xác định nhóm định dạng file được phép — ghép bằng dấu _:

export type TYPE_FILE_UPLOAD =
  | 'document'
  | 'image'
  | 'video'
  | 'audio'
  | 'image_document'
  | 'image_video'
  | 'image_audio'
  | 'document_audio'
  | 'video_audio'
  | 'image_document_audio'
  | 'image_video_audio'
  | 'document_video_audio'
  | 'image_video_document'
  | 'image_audio_video_document';

TYPE_MODE_FILE_DISPLAY

export type TYPE_MODE_FILE_DISPLAY = 'full' | 'short';

IUploadFunctionControlEvent

Object chứa các hàm điều khiển component từ bên ngoài, nhận qua (outFunctionsControl):

export interface IUploadFunctionControlEvent {
  // Validate danh sách file hiện tại — trả true nếu hợp lệ
  checkIsValid: () => Promise<boolean>;
  // Xóa toàn bộ file trong danh sách
  removeAll: () => Promise<void>;
  // Cập nhật tiến trình upload cho file theo id
  uploading: (process: IHttpProcessUpload, id: string) => Promise<void>;
  // Set thông báo lỗi — toàn component hoặc file cụ thể
  setMessageError: (message: string, id?: string) => Promise<void>;
  // Kích hoạt dialog chọn file
  handlerUploadFile: () => Promise<void>;
}

IUploadConfigDownloadSampleFile

Cấu hình nút tải file mẫu:

export interface IUploadConfigDownloadSampleFile {
  // Vị trí hiển thị nút — trên hoặc dưới vùng upload
  position?: 'top' | 'bottom';
  // Tiêu đề hiển thị trên nút
  title: string;
  // URL file mẫu để download trực tiếp
  url?: string;
  // Class CSS cho label
  classLabel?: string;
  // Class CSS bổ sung cho nút
  classInclude?: string;
  // Class CSS cho icon bên trái
  classIconLeftInclude?: string;
  // Callback tùy chỉnh — ưu tiên hơn url nếu có
  callBack?: () => void;
}

IUploadDescriptionFormatAndSizeFile

Cấu hình mô tả định dạng và kích thước file (hiển thị dưới vùng upload):

export interface IUploadDescriptionFormatAndSizeFile {
  // Key i18n
  message: string;
  // Tham số interpolation cho i18n
  interpolateParams?: TYPE_OBJECT;
}

Interfaces từ @libs-ui/interfaces-types (dùng chung)

import { IFile, IAspectRatio, IIsValidRequired, IMessageTranslate, IHttpProcessUpload } from '@libs-ui/interfaces-types';

// IFile — cấu trúc file trong danh sách
interface IFile {
  id?: string;
  name: string;
  url?: string;           // Base64 hoặc Object URL sau khi chọn
  origin_url?: string;    // URL gốc từ server
  file?: File;            // File object gốc
  size?: string;          // Kích thước định dạng text ("1.2 MB")
  type?: 'image' | 'video' | 'audio' | 'document';
  isAvatar?: boolean;     // Được chọn làm avatar
  error?: string;         // Thông báo lỗi nếu file không hợp lệ
  percentUploading?: number;  // Tiến trình upload (0-100)
  isUploading?: boolean;
  isUpdate?: boolean;     // File đã được chỉnh sửa qua Image Editor
}

// IAspectRatio — tỉ lệ khung hình cho Image Editor
interface IAspectRatio {
  width: number;
  height: number;
}

// IIsValidRequired — cấu hình validate bắt buộc
interface IIsValidRequired {
  isRequired: boolean;
  message?: string;
}

// IHttpProcessUpload — tiến trình upload
interface IHttpProcessUpload {
  percent: number;  // 0-100
}

Lưu ý quan trọng

⚠️ Dynamic Component Dependencies: Component này dùng LibsUiDynamicComponentService để khởi tạo Image Editor, Gallery Viewer và Preview File động. Đảm bảo LibsUiDynamicComponentService được cung cấp trong provider tree của app.

⚠️ outFunctionsControl phát ngay ngOnInit: Nhận IUploadFunctionControlEvent qua (outFunctionsControl) và lưu tham chiếu vào biến class (không phải local variable) để tránh mất tham chiếu. Gọi checkIsValid() trước khi submit form.

⚠️ originFiles là signal array: Input originFiles nhận Array<WritableSignal<IFile>>. Mỗi phần tử là WritableSignal<IFile> — khi chỉnh sửa ảnh qua editor, signal đó được update() trực tiếp, không tạo phần tử mới.

⚠️ maxTotalSize tính bằng bytes: Tất cả input maxXxxSizemaxTotalSize nhận giá trị bytes. Ví dụ 5MB = 5 * 1024 * 1024. Nếu truyền 5 sẽ bị giới hạn ở 5 bytes.

⚠️ fileType quyết định danh sách extension: fileType xác định nhóm định dạng và tự động sinh chuỗi accept cho input file. Các input imageExtList, videoExtList, documentExtList, audioExtList cho phép override danh sách extension mặc định trong từng nhóm.

⚠️ multiple vs canUploadIfHasExistFile: Khi multiple = false và đã có file, upload file mới sẽ không thay thế file cũ trừ khi bật canUploadIfHasExistFile = true.

Demo

npx nx serve core-ui

Truy cập: http://localhost:4500/components/inputs/upload