Working with files and images
Updated on Published on
Article summary
Store a Single Image in an Aggregate When to use: Choose this approach when the aggregate requires exactly one image field that is tied to a specific business purpose, such as: An equipment photo in an asset record A user profile picture in an account A company logo in an organization profile
Store a Single Image in an Aggregate
Section titled “Store a Single Image in an Aggregate”When to use:
Choose this approach when the aggregate requires exactly one image field that is tied to a specific business purpose, such as:
-
An equipment photo in an asset record
-
A user profile picture in an account
-
A company logo in an organization profile
This is useful when the image:
-
Has its own dedicated update command and access permissions
-
Must always represent the same type of visual (not an arbitrary collection of images)
-
Should be stored, displayed, and managed as a single value rather than part of a gallery or list
How to:
1. Define the image field and update command
-
Add a field of type Image to the aggregate.
-
Create a command (e.g., updateImage).
-
Add the image field as a command parameter.
2. For in-place viewing and editing
-
Drag and drop the image field onto the screen.
-
Select the “Value only” display option.
-
Click the image component to review its configuration.
-
Remove the update command from the configuration if you want the image to be read-only.
-
If the update command is kept:
-
Clicking the image will prompt the user to browse for a new file if none is set.
-
If an image is already set, clicking will clear it.
-
3. To use a dialog for editing
-
Drag and drop the image field onto the screen.
-
Select the “Value and label” display option.
-
Click the field component to review its configuration.
-
Clicking the field opens a standard action dialog.
-
The dialog can be configured to allow clearing the image (if the parameter is not marked as required).
-
The dialog can also allow selecting a new image.
-
You can add additional parameters to the update command for more complex update logic.
-
Store a Single File in an Aggregate
Section titled “Store a Single File in an Aggregate”When to use:
Use this pattern when an aggregate needs to store one specific, named file that has its own update command and access permissions. This is ideal when:
-
The file serves a dedicated business purpose and is always the same type of document.
-
It must be managed independently from other files in the system.
-
Access rights and update rules differ from other documents in the aggregate.
Example:
An Employee record might store three separate documents—employmentContract, jobDescription, and signedNDA—each requiring its own permissions and update logic. Instead of treating them as a single collection of attachments, define each as an individual file field.
How to:
1. Define the file field and update command
-
Add a field of type File to the aggregate.
-
Create a command (e.g., updateFile).
-
Add the file field as a parameter to that command.
2. Add the field to the screen
-
Drag and drop the file field onto the screen.
-
Select the “Value and label” display option.
-
Click the field component to review its configuration.
3. Configure file interaction
-
Clicking the field will open a standard action dialog.
-
The dialog allows the user to clear the file (if the parameter is not marked as required).
-
The dialog allows the user to browse and select a new file.
-
You can add extra parameters to the update command for more complex update logic.
-
Store a Collection of Files in an Aggregate
Section titled “Store a Collection of Files in an Aggregate”When to use:
Use this pattern when an aggregate needs to store and manage multiple related files of the same type as a set, rather than as separate named fields. This is ideal when:
-
All files share the same update command and permissions.
-
Files are added, displayed, and removed from one unified list.
-
The number of files can change over time.
Example:
A Project record might store reference images, design drafts, or supporting documents that all follow the same rules. Instead of creating one field per file, store them together in a single file collection field for simpler management.
1. Define the collection field and update command
-
Add a field of type File to the aggregate.
-
Mark it as a collection.
-
Create a command (e.g., updateFiles).
-
Add the file collection field as a command parameter.
2. Easiest option — automatic display with built-in file management
-
Drag and drop the command onto the screen and select “Automatic form”.
-
Remove the Submit and Cancel buttons.
-
In the Page Structure panel, select the box that has the Create a Command Form behavior and enable auto-save.
Result:
This automatically renders a file list that allows:
-
Uploading new files
-
Deleting existing files
-
Downloading files by clicking them
No extra wiring or custom logic is needed.
3. Advanced — create a custom display
-
Drag and drop the file field onto the screen.
-
Choose Repeater as the display type.
-
Drag and drop the command and select a Button type.
-
Activate Play mode, click the button, and select one or more files to upload.
-
Deactivate Play mode.
-
Style the repeater to match your layout.
-
Bind the click event on repeater items to execute the update command.
4. Support deletion of individual files (custom approach)
Create the delete command:
-
Create a deleteFile command.
-
Add a storageId parameter (type: Text).
-
Create a new mutation field targeting the collection field.
-
In the mutation field, use:
return data.files.reject({ storageId }).add({ $replace: true })Wire up the UI:
-
In the repeater, add an Add Dependency behavior before Set Component Data:
-
Name: parentData
-
Value: data
-
-
Add a trash icon to each repeater card.
-
On the trash icon’s onClick event, add a Show Custom Dialog behavior.
-
In the dialog’s On submit, run:
parentData.removeFile({ storageId: data.storageId })Store a Collection of Files in an Aggregate where each file has domain-specific fields
Section titled “Store a Collection of Files in an Aggregate where each file has domain-specific fields”When to use
Choose this when each file is essentially an entity with its own data and lifecycle, not just an attachment. Typical needs:
-
Custom metadata (e.g., owner, status, tags)
-
Domain commands (e.g., Approve, Reject)
-
Workflows/lifecycle (e.g., Draft → Approved → Archived)
Example:
A Project has a documents collection of Document entities. Each Document has a single file (content), plus fields like owner and status, and commands such as Approve / Reject.
Define the collection field and entity in the aggregate
1. Add the collection to the aggregate
-
Create a new field on the aggregate (e.g.,
documents). -
Set its type to New Entity.
-
When prompted, name the entity
Document. -
The UI links
documents(collection) ↔Document(entity).
2. Add fields to the new entity
-
In
Document, add a File field (e.g.,content). -
Add any domain fields you need (e.g.,
owner,status,tags).
3. Create the update command on the parent
-
On the aggregate, create
updateDocuments(regular command, not “Entity Create”). -
Add the
documentscollection as a parameter, make sure the parameter is set as a collection (Is Collection). -
Set the mutation for that parameter to Replace values.
4. Create the delete command on the entity
- On
Document, add a standard Delete command.
5. Configure the upload dialog (on updateDocuments)
-
Add a Dialog declaration.
-
Configure the
documentsfield:componentId: @skyjs/data-model/web/DocumentsInputprops: { "hidePreview": true, "fieldName": "content" }Hide label : truefieldNamemust match the entity’s single File field.
6. Set default values when adding new files
-
In the parameter’s onChange property, use:
return newValue => newValue.assignNewDocumentsValues({ uploadDate: new DateTime(), owner: currentUser, status: 'DRAFT' },data);This code is your chance to set default values for your custom entity when new files are added. You could, for example, set the current user as the owner, initialize a status, or apply any other default metadata relevant to your domain.
UI — Automatic file list via command form
-
Drag
updateDocumentsonto the screen → choose Manual form. -
Remove Submit and Cancel buttons.
-
In Page Structure, select the box with Create a Command Form → enable auto-save.
Result:
A working list that supports upload, delete, and download.
With
"hidePreview": true, selected files won’t show the default preview.
Set it tofalsefor filename/size, or build a custom view (below) to show domain fields and actions.
UI — Custom document cards in a Repeater
-
Drag the
documentscollection onto the screen → choose Repeater. -
Drag
updateDocumentsonto the page → choose a Button type. -
In Play mode, click the button and select one or more files; exit Play mode.
-
Style the repeater.
-
Inside each card:
-
Add the Delete command (button/icon/link).
-
Add your domain commands (e.g., Approve / Reject).
-
Display fields like
owner,status,tags,uploadDate.
-
-
To allow downloading the file, attach to a filename component or download icon a Execute JavaScript behavior:
window.location = await getFileUrl("get", data.content.storageId, data.name)-
data.content= your content field name -
data.name= suggested download filename