@libs-ui/pipes-check-file-extension
v0.2.357-8
Published
> Pipe kiểm tra định dạng file theo nhóm loại (image, video, word, xlsx, pdf, pptx, other), trả về `boolean`.
Readme
@libs-ui/pipes-check-file-extension
Pipe kiểm tra định dạng file theo nhóm loại (image, video, word, xlsx, pdf, pptx, other), trả về
boolean.
Giới thiệu
LibsUiPipesCheckFileExtensionPipe nhận vào một đối tượng IFile và một nhóm loại file, sau đó trả về true nếu file thuộc nhóm đó và false nếu không. Pipe hỗ trợ kiểm tra cả extension rút gọn (vd: jpg, pdf) lẫn MIME type đầy đủ (vd: image/jpeg, application/pdf). Thích hợp dùng trong danh sách file, màn hình upload, hoặc hiển thị icon file attachment.
Tính năng
- ✅ Phân loại file theo 7 nhóm:
image,video,word,xlsx,pdf,pptx,other - ✅ Hỗ trợ extension rút gọn (vd:
jpg,mp4,docx) và MIME type đầy đủ (vd:application/pdf) - ✅ Tự động extract extension từ
name,mimetype,urlcủaIFile - ✅ Case-insensitive:
JPG,jpg,Jpgđều nhận diện đúng - ✅ Nhóm
otherbắt tất cả định dạng không nằm trong các nhóm đã biết - ✅ Standalone pipe, không cần NgModule
- ✅ Pure pipe, hiệu năng cao, an toàn trong danh sách dài
Khi nào sử dụng
- Hiển thị icon/thumbnail khác nhau cho từng loại file trong danh sách attachment
- Lọc hoặc phân nhóm file trong màn hình upload preview
- Ẩn/hiện nút xem trước (preview) tùy theo file có phải image hay video không
- Validate loại file phía client trước khi gọi API upload
- Render component phù hợp (image viewer, video player, PDF viewer) dựa trên loại file
Cài đặt
npm install @libs-ui/pipes-check-file-extensionImport
import { LibsUiPipesCheckFileExtensionPipe } from '@libs-ui/pipes-check-file-extension';
@Component({
standalone: true,
imports: [LibsUiPipesCheckFileExtensionPipe],
// ...
})
export class MyComponent {}Ví dụ sử dụng
1. Hiển thị nhãn loại file trong template
import { Component } from '@angular/core';
import { LibsUiPipesCheckFileExtensionPipe } from '@libs-ui/pipes-check-file-extension';
import { IFile } from '@libs-ui/interfaces-types';
@Component({
standalone: true,
imports: [LibsUiPipesCheckFileExtensionPipe],
template: `
@if (file | LibsUiPipesCheckFileExtensionPipe : 'image') {
<span class="libs-ui-font-h6r text-green-600">Ảnh</span>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'video') {
<span class="libs-ui-font-h6r text-blue-600">Video</span>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'pdf') {
<span class="libs-ui-font-h6r text-red-600">PDF</span>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'other') {
<span class="libs-ui-font-h6r text-gray-500">Khác</span>
}
`,
})
export class FileTypeLabelComponent {
protected file: IFile = { name: 'report.pdf', mimetype: 'application/pdf' };
}2. Render danh sách file với icon theo loại
import { Component } from '@angular/core';
import { LibsUiPipesCheckFileExtensionPipe } from '@libs-ui/pipes-check-file-extension';
import { IFile } from '@libs-ui/interfaces-types';
@Component({
standalone: true,
imports: [LibsUiPipesCheckFileExtensionPipe],
template: `
@for (file of attachments; track file.id) {
<div class="flex items-center gap-2 p-2 border border-gray-200 rounded mb-1">
@if (file | LibsUiPipesCheckFileExtensionPipe : 'image') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-green-500">
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
</svg>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'video') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-blue-500">
<path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"/>
</svg>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'word') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-indigo-500">
<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>
</svg>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'pdf') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-red-500">
<path d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z"/>
</svg>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'xlsx') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-green-700">
<path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6z"/>
</svg>
}
@if (file | LibsUiPipesCheckFileExtensionPipe : 'other') {
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" class="text-gray-400">
<path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>
</svg>
}
<span class="libs-ui-font-h6r text-gray-700">{{ file.name }}</span>
</div>
}
`,
})
export class FileListComponent {
protected attachments: IFile[] = [
{ id: '1', name: 'avatar.jpg' },
{ id: '2', name: 'demo.mp4' },
{ id: '3', name: 'report.docx' },
{ id: '4', name: 'budget.xlsx' },
{ id: '5', name: 'spec.pdf' },
{ id: '6', name: 'slides.pptx' },
{ id: '7', name: 'readme.txt' },
];
}3. Dùng standalone (pipe.transform) trong TypeScript
import { LibsUiPipesCheckFileExtensionPipe } from '@libs-ui/pipes-check-file-extension';
import { IFile } from '@libs-ui/interfaces-types';
const pipe = new LibsUiPipesCheckFileExtensionPipe();
const file: IFile = { name: 'photo.jpg' };
console.log(pipe.transform(file, 'image')); // true
console.log(pipe.transform(file, 'video')); // false
console.log(pipe.transform(file, 'other')); // false
const unknown: IFile = { name: 'archive.zip' };
console.log(pipe.transform(unknown, 'other')); // true4. Kết hợp với MIME type
import { Component } from '@angular/core';
import { LibsUiPipesCheckFileExtensionPipe } from '@libs-ui/pipes-check-file-extension';
import { IFile } from '@libs-ui/interfaces-types';
@Component({
standalone: true,
imports: [LibsUiPipesCheckFileExtensionPipe],
template: `
@if (uploadedFile | LibsUiPipesCheckFileExtensionPipe : 'image') {
<img [src]="uploadedFile.url" alt="preview" class="w-32 h-32 object-cover rounded" />
}
@if (uploadedFile | LibsUiPipesCheckFileExtensionPipe : 'pdf') {
<div class="p-4 bg-red-50 rounded libs-ui-font-h6r text-red-600">
Tài liệu PDF — {{ uploadedFile.name }}
</div>
}
`,
})
export class UploadPreviewComponent {
// MIME type đầy đủ cũng được nhận diện
protected uploadedFile: IFile = {
name: 'contract.pdf',
mimetype: 'application/pdf',
url: 'https://example.com/files/contract.pdf',
};
}Transform (Pipe API)
| Tham số | Type | Bắt buộc | Mô tả | Ví dụ |
|---|---|---|---|---|
| file | IFile | Có | Đối tượng file cần kiểm tra. Pipe ưu tiên mimetype → file.type → extract từ name/url | { name: 'photo.jpg' } |
| type | 'image' \| 'video' \| 'word' \| 'xlsx' \| 'pdf' \| 'pptx' \| 'other' | Có | Nhóm định dạng muốn kiểm tra | 'image' |
Trả về: boolean — true nếu file thuộc nhóm, false nếu không (kể cả khi không tìm được extension).
Ví dụ template
{{ file | LibsUiPipesCheckFileExtensionPipe : 'image' }}Ví dụ standalone
const pipe = new LibsUiPipesCheckFileExtensionPipe();
pipe.transform({ name: 'photo.jpg' }, 'image'); // true
pipe.transform({ name: 'photo.jpg' }, 'video'); // falseDanh sách extension hỗ trợ
| Nhóm | Extension / MIME type được nhận diện |
|---|---|
| image | gif, jpg, jpeg, png, webp, image/gif, image/jpeg, image/png |
| video | mp4, mov, mpg, avi, wmv, video/mp4, video/quicktime, video/mpeg, video/x-msvideo, video/x-ms-wmv |
| word | doc, docx, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document |
| xlsx | xls, xlsx, gsheet, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
| pdf | pdf, application/pdf |
| pptx | ppt, pptx, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation |
| other | Bất kỳ extension nào không thuộc image, video, doc, xls, ppt, pdf, json, xml và các MIME type tương ứng |
Types & Interfaces
import { IFile } from '@libs-ui/interfaces-types';
export interface IFile {
id?: string;
name?: string; // Tên file — pipe sẽ extract extension từ đây
file?: File; // Đối tượng File của browser — pipe đọc file.type
size?: string;
isUploading?: boolean;
percentUploading?: number;
isUpdate?: boolean;
url?: string; // Fallback khi không có name
origin_url?: string; // Fallback khi không có name và url
mimetype?: string; // Ưu tiên cao nhất khi extract extension
type?: TYPE_FILE;
error?: string;
isAvatar?: boolean;
}
export type TYPE_FILE = 'document' | 'image' | 'video' | 'audio';Thứ tự ưu tiên khi extract extension:
file.type(nếu là đối tượngFilegốc của browser)mimetypecủaIFilefile.file?.type(nếu có File đính kèm)- Extension từ
name - Extension từ
urlhoặcorigin_url
Lưu ý quan trọng
⚠️ Extension không tìm được: Nếu IFile không có name, mimetype, url hoặc đối tượng file browser, pipe trả về false cho mọi nhóm.
⚠️ Case-insensitive: Pipe tự động chuyển extension về chữ thường trước khi so sánh, vì vậy JPG, jpg, Jpg đều cho kết quả như nhau.
⚠️ Nhóm other: Trả về true cho các file không thuộc bất kỳ nhóm nào trong danh sách mặc định (bao gồm cả json, xml, audio). Dùng nhóm này để bắt các định dạng không xác định thay vì dùng @else.
⚠️ MIME type: Với file upload từ browser qua <input type="file">, đối tượng File gốc có thuộc tính type là MIME type đầy đủ. IFile hỗ trợ trường file: File, pipe sẽ ưu tiên đọc file.type nếu có.
⚠️ gsheet: Extension gsheet (Google Sheet) được nhận diện thuộc nhóm xlsx.
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/pipes/check-file-extension
Unit Tests
npx nx test libs-ui-pipes-check-file-extension --testFile=libs-ui/pipes/check-file-extension/src/check-file-extension.pipe.spec.ts