Dynamic attachments component - Angular Material based
@eqproject/eqp-attachments provides a complete, client-side solution for attachment management, now fully modernized with the latest Angular features.
npm install --save @eqproject/eqp-attachments
`
$3
The component is standalone , so you can import it directly into your component or module.
TypeScript
`
// in your-component.ts or app/shared module
import { EqpAttachmentsModule } from '@eqproject/eqp-attachments';
@Component({
selector: 'my-feature-component',
standalone: true,
imports: [ EqpAttachmentsModule ],
template:
})
export class MyFeatureComponent {
myAttachments: IAttachmentDTO[] = [];
onAttachmentsChange(updatedList: IAttachmentDTO[]) {
this.myAttachments = updatedList;
console.log('Attachments list updated!', this.myAttachments);
}
}
`
$3
For the best icon display, include Font Awesome in your project's styles, for example, in angular.json:
JSON
`
"styles": [
"src/styles.scss",
"node_modules/@fortawesome/fontawesome-free/css/all.min.css"
],
`
API Reference
$3
#### Core Configuration
| Input | Type | Default | Description |
| ---------------------- | -------------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
| attachmentsList | IAttachmentDTO[] | null | The array of attachments to display and manage. |
| singleAttachment | IAttachmentDTO | null | An alternative to attachmentsListfor passing a single attachment object in non-multiple mode. |
| multipleAttachment | boolean | true | If true, manages a list of attachments. If false, handles only a single attachment. |
| allowedTypes | AttachmentType[] | [FILE, LINK] | An array of allowed attachment sources (e.g.,[1, 2, 3]for File, Link, and Dropbox). |
---
#### UI & View Configuration
| Input | Type | Default | Description |
| ---------------------- | ----------- | ------------- | -------------------------------------------------------------------------------- |
| layout | 'full' | 'compact' | 'compact' |
| viewMode | 'card' | 'table' | 'card' |
| chooseView | boolean | true | If true, displays the Card/Table view switcher in the header. |
| showSummary | boolean | true | If true, displays the summary block with file count and total size. |
| cardSize | 'small' | 'medium' | 'large' |
| customCardWidthPx | number | 200 | Sets the custom card width in pixels when cardSizeis 'custom'. |
| customCardHeightPx | number | 180 | Sets the custom card height in pixels when cardSizeis 'custom'. |
| showMatCard | boolean | true | If true(and in table mode), the component is rendered inside a mat-card. |
| cropDialogClass | string | undefined | Assigns a custom CSS class to the image cropper dialog panel. |
| showUploadTitle | boolean | true | If true, will show title over dropbox |
---
#### Table View Configuration
| Input | Type | Default | Description |
| ---------------------- | ----------- | ------------- | -------------------------------------------------------------------------------- |
| customColumns | 'AttachmentFieldColumn[]' | [] | Array to add custom columns to the table view. |
| customMenuActions | 'AttachmentMenuAction[]' | [] | Array to add custom actions to the table's "more options" (...) menu.
---
#### Functional Configuration
| Input | Type | Default | Description |
| ------------------------------- | -------------------- | ------------- | --------------------------------------------------------------------------------------------------------- |
| maxFileSizeMB | number | 100 | Sets the maximum file size in megabytes for each uploaded file. |
| loadMultipleFiles | boolean | false | If true, allows selecting multiple files at once from the file browser. |
| singleAttachmentDragAndDrop | boolean | false | If true, enables the drag-and-drop UI even in single-attachment mode. |
| isDisabled | boolean | false | Disables all "add attachment" controls. |
| disableAction | boolean | false | If true, hides the actions column in the table view. |
| allowOnlyImages | boolean | false | If true, restricts file uploads to image types only. |
| acceptedFileTypes | string | undefined | A string for the acceptattribute (e.g.,'.pdf,image/*'). |
| showPreview | boolean | true | Enables the preview functionality for attachments. |
| compressionOptions | IOptions | {...} | Options for client-side image compression (maxSizeMB,maxWidthOrHeight, etc.). |
| cropOptions | CropOptionEnum[] | [] | Enables specific tools in the image cropper (1: Rotate, 2: Flip). |
| separatedUploadButtons | boolean | false | If trueand multiple allowedTypesare available, shows separate buttons instead of a dropdown menu. |
| getAttachmentEndpoint | string | null | API endpoint to fetch full attachment data for previews. |
| productionBaseUrl | string | null | Base URL for the document viewer (e.g., Google Viewer). |
---
#### Labels & Text
| Input | Default |
| --------------------------------- | --------------------------------------------- |
| uploadTitle | 'Upload file' |
| uploadSubtitle | 'Drag & drop files or click' |
| dropHereLabel | 'Drop files here' |
| supportedFormatsLabel | 'Supported formats: JPEG, PNG, PDF...' |
| browseFilesLabel | 'Browse files' |
| uploadSummaryLabel | 'Attachments List' |
| filesLabel | 'Files' |
| totalSizeLabel | 'Total Size' |
| emptyTableMessage | 'No data found' |
| emptyStateLabel | 'No files have been uploaded' |
| openLinkLabel | "Open link" |
| addButtonLabel | "Add" |
| downloadLabel | "Download" |
| deleteLabel | "Delete" |
| previewLabel | "Preview" |
| confirmLabel | "Confirm" |
| abortLabel | "Cancel" |
| saveLabel | "Save" |
| exitLabel | "Exit" |
| fileNameLabel | "File name" |
| uploadFileLabel | "Upload file" |
| uploadWithDropboxLabel | "Upload with Dropbox" |
| cropLabel | "Choose the image dimensions" |
| removedLabel | 'File removed' |
| addedSuccessfullyLabel | 'file(s) uploaded successfully.' |
| deleteDialogTitle | null |
| deleteDialogMessage | 'Are you sure you want to delete...' |
| noImageSelectedErrorMessage | 'You cannot select a file that is not...' |
| wrongTypeSelectedErrorMessage | 'The selected file cannot be uploaded.' |
| videoPreviewErrorMessage | 'Cannot open a preview of a video file.' |
| audioPreviewErrorMessage | 'Cannot open a preview of an audio file.' |
| flipHorinzontalLabel | 'Flip horizontally' |
| flipVerticalLabel | 'Flip vertically' |
| rotateRightLabel | 'Rotate right' |
| rotateLeftLabel | 'Rotate left' |
| eqpTableSearchText | 'Search' |
| downloadTooltipPosition | 'below' |
$3
| Output | Event Arguments | Description |
| -------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| (localEditedAttachments) | IAttachmentDTO[] | Emits the complete, updated list of attachments whenever a file/link is added or removed. This is the primary output to listen to. |
| (downloadAttachment) | IAttachmentDTO | Triggered on a download attempt for an attachment missing its FileDataBase64, allowing the parent component to fetch the data. |
| (onDeleteAttachment) | IAttachmentDTO | Emits the attachment object just before it is removed from the list. |
| (abortAddAttachment) | any | Fired when the user cancels an action from a modal dialog (e.g., the crop dialog). |
$3
#### IAttachmentDTO Interface
| Property | Type | Description |
| ----------------------- | ------------------- | ------------------------------------------------------ |
| ID | number \| string | Unique ID of the attachment. |
| FileName | string | Name of the file or link. |
| FilePath | string | Path of the link or the file on the server. |
| AttachmentType | AttachmentType | The type of attachment (1: FILE, 2: LINK, 3: DROPBOX). |
| FileDataBase64 | string | The base64 content of the file. |
| FileSize | number | The size of the file in bytes. |
| FileContentType | string | The mime type of the file (e.g.,image/png). |
| IsImage | boolean | trueif the attachment is an image. |
| FileThumbnailBase64 | string | The base64 content of a low-resolution thumbnail. |
| isUploading | boolean | (Internal State)trueduring the upload process. |
| uploadError | boolean | (Internal State)trueif the upload failed. |
---
#### AttachmentFieldColumn Interface
| Property | Type | Description |
| ----------------------- | ------------------- | ------------------------------------------------------ |
| key | string | . |
| display | string | The property key from the IAttachmentDTO object |
| type | TypeAttachmentColumn | The rendering type (TEXT, DATE, TEMPLATE). Defaults to TEXT. |
| externalTemplate | TemplateRef | The ng-template to use (required if type is TEMPLATE). |
| styles | { flex: string } | Defines the column width (e.g., '1 1 0%' or '0 0 150px'). |
| position | number | The column's display order (Default: 99). File is 10, Actions is 100. |
| class | string | A custom CSS class to add to the column's cells. |
---
#### AttachmentMenuAction Interface
| Property | Type | Description |
| ----------------------- | ------------------- | ------------------------------------------------------ |
| icon | string | mat-icon name to display (e.g., 'share'). |
| name | string | Text to show in the menu item.object |
| fn | (att: IAttachmentDTO) => void | Function to execute when the item is clicked. |
| disabled | (att: IAttachmentDTO) => boolean | Function to dynamically disable the action for a specific row. |
| position | number | Display order. Preview is 10, Delete is 100. Use a number in between (e.g., 20) to add an action. |
---
#### AttachmentCardSize Type
export type AttachmentCardSize = 'small' | 'medium' | 'large' | 'custom';
---
---
#### Layout Configuration
export type Layout = 'full' | 'compact';
---
Use Cases
$3
A configuration for uploading a single image, with drag-and-drop and the image cropper enabled.
HTML
`
[multipleAttachment]="false"
[attachmentsList]="singleImage"
[singleAttachmentDragAndDrop]="true"
[allowOnlyImages]="true"
[cropOptions]="[1, 2]"
[maxFileSizeMB]="10"
(localEditedAttachments)="onAttachmentsChange($event)">
`
TypeScript
`
import { IAttachmentDTO } from '@eqproject/eqp-attachments';
export class MyComponent {
singleImage: IAttachmentDTO[] = [];
onAttachmentsChange(updatedList: IAttachmentDTO[]) {
// In single mode, the list will contain 0 or 1 item
this.singleImage = updatedList;
}
}
`
$3
A full-featured configuration for managing multiple types of attachments, starting in card view and allowing the user to switch to table view.
HTML
`
[multipleAttachment]="true"
[attachmentsList]="documentList"
[allowedTypes]="[1, 2]"
[viewMode]="'card'"
[headerTitle]="'Project Documents'"
[showSummary]="true"
(localEditedAttachments)="onAttachmentsChange($event)">
`
TypeScript
`
import { IAttachmentDTO, AttachmentType } from '@eqproject/eqp-attachments';
export class MyComponent {
documentList: IAttachmentDTO[] = [
{
ID: 101,
IsImage: false,
AttachmentType: AttachmentType.FILE,
FileName: "Final Report.pdf",
FileExtension: "pdf",
FileSize: 1200000 // 1.2 MB
},
{
ID: 102,
IsImage: false,
AttachmentType: AttachmentType.LINK,
FileName: "GitHub Repository",
FilePath: "https://github.com/...",
},
];
onAttachmentsChange(updatedList: IAttachmentDTO[]) {
this.documentList = updatedList;
}
}
`
$3
HTML
`
[multipleAttachment]="true"
[attachmentsList]="documentList"
[allowedTypes]="[1, 2]"
[viewMode]="'card'"
[headerTitle]="'Project Documents'"
[showSummary]="true"
(localEditedAttachments)="onAttachmentsChange($event)"
[customColumns]="myCustomColumns"
[customMenuActions]="myCustomActions">
[style.color]="att.Status === 'Approved' ? '#2e7d32' : '#c62828'">
{{ att.Status }}
`
TypeScript
`
@ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef;
documentList: IAttachmentDTO[] = [
{
ID: 1,
FileName: 'report.pdf',
FileExtension: 'pdf',
UploadUserName: 'Mario Rossi',
Status: 'Approved'
},
{
ID: 2,
FileName: 'schema.zip',
FileExtension: 'zip',
UploadUserName: 'Laura Bianchi',
Status: 'Pending'
}
];
myCustomColumns: AttachmentFieldColumn[] = [];
myCustomActions: AttachmentMenuAction[] = [];
ngOnInit() {
this.myCustomColumns = [
{
key: 'UploadUserName',
header: 'Uploaded By',
type: TypeAttachmentColumn.TEXT, // Renders as plain text
styles: { flex: '2 1 0%' }, // Takes 2 parts of the available space
position: 20 // Shows after "File" (10)
},
{
key: 'Status', // Unique key for this column
header: 'Status',
type: TypeAttachmentColumn.TEMPLATE,
externalTemplate: this.statusTemplate, // Pass the ng-template
styles: { flex: '1 1 0%' }, // Takes 1 part of the available space
position: 30 // Shows after "Uploaded By" (20)
}
];
this.myCustomActions = [
{
icon: 'share',
label: 'Share',
onClick: (item) => this.shareAttachment(item),
position: 25 // Show after "Preview" (10) and before "Delete" (100)
},
{
icon: 'edit',
label: 'Edit Name',
onClick: (item) => this.renameAttachment(item),
position: 26
}
];
}
``