ChatiumFor developersPlaygroundPricing
Sign in

Working with Files

In this example, we will show how to create an application for managing images. After reading this article, you will learn how to upload, save, display, and manage images.

Main Steps

Importing Libraries

We import the modules attachMedia, refresh from @app/ui, and Heap from @app/heap.

import {attachMedia, refresh} from '@app/ui'
import {Heap} from '@app/heap'
  • attachMedia allows you to attach media files.
  • refresh updates the screen.
  • Heap from @app/heap is used for database operations.

Creating a Table

const ImagesTable = Heap.Table('images', {
  filename: Heap.String(),
  image: Heap.ImageFile(),
  sessionId: Heap.String(),
})
  • ImagesTable defines the structure of the table with fields:
    • filename, which displays the name of the file
    • image - the image file
    • sessionId - the session identifier where future uploaded files will be stored.

Main Screen

We define the route /, which displays the main screen with the title "File manager", and it will show future files in a table format.

app.screen('/', async (ctx, req) => {
  const records = await ImagesTable.findAll(ctx, {
    where: { sessionId: ctx.session.id }
  })

  return (
    <screen title="File manager">
      <text class="section">Select image file to upload</text>
      {records.map(record => 
        <list-item
          icon={{ url: record.image.getThumbnailUrl(80) }}
          content={{ title: record.filename, subTitle: record.createdAt.toLocaleDateString() }}
          onClick={cardRoute({id: record.id}).navigate()}
        />
      )}
  • ctx and req — context and request used for data processing.
  • ImagesTable.findAll retrieves all image records for the current session.
  • screen creates a screen with the title "File manager".
  • text outputs the text "Select image file to upload".
  • records.map iterates through all records and creates list items list-item with an image icon, title, and creation date.
<button class={['section', 'primary']}
        onClick={attachMedia({
          mediaType: 'photo',
          submitUrl: uploadRoute.url()
        })}
      >Upload</button>
    </screen>
  )
})
  • We add a button "Upload", which calls the attachMedia function to upload an image. When the button is clicked, a dialog opens to select a photo, and then the upload route uploadRoute is called.

Upload Route

At this stage, we define the route /upload, which handles image uploads.

const uploadRoute = app.apiCall('/upload', async(ctx, req) => {
  await ImagesTable.create(ctx, {
    filename: req.body.file.name,
    image: req.body.file.hash,
    sessionId: ctx.session.id,
  })
  return refresh()
})
  • uploadRoute is an API request for uploading images.
  • ImagesTable.create creates a new record in the table with data about the uploaded file.

After successfully uploading and saving the image, the refresh function is called to update the current screen so that the new file appears.

Image Card

To display a single image, we need to define the route /card/:id.

const cardRoute = app.screen('/card/:id', async(ctx, req) => {
  const record = await ImagesTable.getById(ctx, req.params.id)
  return <screen title={record.filename}>
    <image src={record.image.getThumbnailSrc(800)} />
    <button class={['section', 'secondary']} onClick={ctx.router.navigate('/')}>Back</button>
  </screen>
})

Here we define a screen for the route /card/:id. Then, using ImagesTable.getById(ctx, req.params.id), we retrieve the record from the ImagesTable by the identifier passed in the URL and display a screen with a title corresponding to the image file name (screen title={record.filename}). Using image src={record.image.getThumbnailSrc(800)}, we insert the image with a width of 800 pixels. We also add a "Back" button that returns the user to the main screen (button c ctx.router.navigate('/')).

Conclusion

This code demonstrates creating a table for storing images, defining routes for displaying and uploading images, as well as creating dynamic interfaces for managing these images.

Final Code