6. Working with Images

In this chapter, you will add the picture attribute to the User entity and learn how to upload and display images in UI.

Adding File Reference Attribute

Jmix allows you to store uploaded files outside the database in a so-called file storage. In the simple case, it’s just a file system directory with a special structure. To link the file located in the file storage to an entity, you create an attribute of the FileRef type.

Let’s create such an attribute for managing the user picture.

If your application is running, stop it using the Stop button (suspend) in the main toolbar.

Double-click on the User entity in Jmix tool window and select the joiningDate attribute (to add the new attribute after it).

Click Add (add) in the Attributes toolbar. In the New Attribute dialog, enter picture into the Name field and select FileRef in the Type dropdown:

attribute 2

Accept the suggested value (1024) in the Length field. For FileRef attribute it defines the column length for storing a reference, not the file itself, so it doesn’t limit the file size.

Click OK.

Select the picture attribute and click the Add to Views (add attribute to screens) button in the Attributes toolbar.

The appeared dialog window will show all views that display the User entity. Select User.detail view and click OK.

Studio will create the pictureField component in the formLayout of the User.detail view:

<formLayout id="form" dataContainer="userDc">
    ...
    <fileStorageUploadField id="pictureField" property="picture"/>
</formLayout>

Click the Debug button (start debugger) in the main toolbar.

Before running the application, Studio will generate a Liquibase changelog:

run app 1

As you can see, the changelog contains a command for adding the PICTURE column to the USER_ table. The column is of type VARCHAR(1024), because the file reference is actually a string.

Click Save and run.

Studio will execute the changelog, then build and run the application.

Open http://localhost:8080 in your web browser and log in to the application with admin / admin credentials.

Click on the Users item in the Application menu.

Click Edit for a user. The UI control for uploading a picture is shown on the form:

run app 3

Displaying Image in Form

In this section, you will improve the detail view to display the uploaded picture in the form.

First, let’s wrap fileStorageUpload into the collapsible Details layout:

form 1

Now the field is located not immediately in the formLayout which defines the data container for its nested components, so set the dataContainer to the field explicitly:

form 4

Then add the image component below fileStorageUpload with the following attributes:

<details summaryText="Picture">
    <hbox>
        <fileStorageUploadField id="pictureField" dataContainer="userDc" property="picture"/>
        <image id="image" property="picture" dataContainer="userDc" height="10em" width="10em"
            classNames="user-picture"/>
    </hbox>
</details>
  • dataContainer="userDc" property="picture" attributes bind the image component to the picture attribute of the User entity.

  • classNames="user-picture" refers to CSS class defined below.

Open onboarding.css file from the User InterfaceThemes section and define the user-picture class:

form 5

object-fit: contain property makes sure the image fills the whole allocated area but keeps the proportions.

.user-picture {
    object-fit: contain;
}

Press Ctrl/Cmd+S and switch to the running application. Refresh the User detail view and try to upload an image:

form 2

Displaying Image in Data Grid

Let’s create the column to render the image in the data grid of the User.list view.

Open user-list-view.xml and add the following column to usersDataGrid:

<columns resizable="true">
    <column key="picture" sortable="false" flexGrow="0" resizable="false"/>

Add the following fields to the UserListView class:

@ViewComponent
private DataGrid<User> usersDataGrid;

@Autowired
private UiComponents uiComponents;

@Autowired
private FileStorage fileStorage;
You can use Inject button in the top actions panel of the editor to inject dependencies into view controllers and Spring beans.

Select the picture column, switch to the Handlers tab of the component inspector and create the renderer handler method. Implement the method as follows:

@Supply(to = "usersDataGrid.picture", subject = "renderer")
private Renderer<User> usersDataGridPictureRenderer() {
    return new ComponentRenderer<>(user -> { (1)
        FileRef fileRef = user.getPicture();
        if (fileRef != null) {
            Image image = uiComponents.create(Image.class);  (2)
            image.setWidth("30px");
            image.setHeight("30px");
            StreamResource streamResource = new StreamResource(
                    fileRef.getFileName(),
                    () -> fileStorage.openStream(fileRef));
            image.setSrc(streamResource); (3)
            image.setClassName("user-picture");

            return image; (4)
        } else {
            return null;
        }
    });
}
1 The method returns a Renderer object that creates a UI component to be rendered in the column. The renderer receives an entity instance for the current row.
2 The Image component instance is created using the UiComponents factory.
3 The image component gets its content from the file storage by the reference stored in the picture attribute of the User entity.
4 The renderer returns the visual component to be shown in the column cells.

Press Ctrl/Cmd+S and switch to the running application. Refresh the User list view. You will see the user’s picture in the first table column:

table 3

Summary

In this section, you have added the ability to upload and show a user’s picture.

You have learned that:

  • Uploaded files can be stored in a file storage and linked with entities using attributes of the FileRef type.

  • The fileStorageUploadField component allows you to upload files, save them into the file storage and link to an entity attribute.

  • The image component can display images saved in the file storage.