howdy/ui/uploader

An uploader: a place to drop or choose files, which the browser sends straight to storage, showing each as an attachment with its progress.

html.form([attribute.method("post"), attribute.action("/profile")], [
  uploader.new(name: "avatar", start: "/profile/uploads")
  |> uploader.accept(["image/png", "image/jpeg"])
  |> uploader.max_size(5_000_000)
  |> uploader.layout(attachment.Tile)
  |> uploader.view,
  ui.submit_button(Primary, [], [text("Save")]),
])

For each file the browser asks your app for somewhere to put it, sends it there, and once it has arrived adds a hidden input named name holding its key. The form then posts the keys, not the files. While a file is still on its way the form will not submit.

start is an endpoint of your own that the browser posts {"name": "cat.png", "type": "image/png", "size": 48213} to, as JSON. It checks the type and size, chooses a key and answers with where to send the file:

{"key": "avatars/42/k3j…/cat.png",
 "upload": {"url": "https://…", "method": "PUT", "headers": {"content-type": "image/png"}}}

With howdy_storage that is storage.upload_url and storage.direct_upload_to_json; see its direct uploads guide. An error response from howdy/service is shown on the file, using the message of its first field if it has one.

The keys come back from the browser, so check each one before you use it: that it is one your app handed to this user, and that the object exists.

The sending is done by howdy/ui/behaviour, which every page includes. In a live view, live.on_values(name, message) hears the keys each time a file arrives or is removed.

Types

A file stored before the page was drawn, such as the current avatar, shown as already uploaded. Its key is posted with the others unless it is removed.

pub type Stored {
  Stored(
    key: String,
    name: String,
    size: Int,
    thumbnail: option.Option(String),
  )
}

Constructors

  • Stored(
      key: String,
      name: String,
      size: Int,
      thumbnail: option.Option(String),
    )

An uploader under construction.

pub opaque type Uploader

What the uploader says. too_large may contain {limit}, and too_many {count}, for the limit.

pub type Words {
  Words(
    prompt: String,
    remove: String,
    retry: String,
    uploading: String,
    too_large: String,
    wrong_type: String,
    too_many: String,
    failed: String,
    wait: String,
    missing: String,
  )
}

Constructors

  • Words(
      prompt: String,
      remove: String,
      retry: String,
      uploading: String,
      too_large: String,
      wrong_type: String,
      too_many: String,
      failed: String,
      wait: String,
      missing: String,
    )

Values

pub fn accept(
  uploader: Uploader,
  types: List(String),
) -> Uploader

Only take files of these types: content types such as "image/png", families such as "image/*", or extensions such as ".pdf", as in the accept attribute. The file chooser offers only these, and other files are refused before they are sent.

pub fn classes() -> List(css.Class)

Every class this module uses, for howdy/ui/export.

pub fn describe(name: String, size: Int) -> String

A file’s type and size as an attachment shows them, such as "PDF · 2.4 MB", the same as the browser shows for a file just chosen.

pub fn drop_class() -> css.Class
pub fn english() -> Words
pub fn file_size(bytes: Int) -> String

A number of bytes for people: "820 KB", "2.4 MB", "18 MB". Units go up in thousands, with one decimal place below ten.

pub fn id(uploader: Uploader, id: String) -> Uploader

The id of the file input, for a <label for> such as a field’s.

pub fn input_class() -> css.Class

The file input, hidden but still focusable and announced.

pub fn layout(
  uploader: Uploader,
  layout: attachment.Layout,
) -> Uploader

Show files as rows, compact rows or tiles. Tiles suit images, which are shown as thumbnails while they upload.

pub fn max_size(uploader: Uploader, bytes: Int) -> Uploader

Refuse files over this many bytes before they are sent. Your start endpoint must check too: this only saves a wasted request.

pub fn multiple(
  uploader: Uploader,
  max_files max_files: Int,
) -> Uploader

Take up to max_files files. Without this, a new file replaces the one there.

pub fn new(name name: String, start start: String) -> Uploader

An uploader for one file, posting its key as name, that asks the endpoint at start where to send each file.

pub fn prompt_class() -> css.Class
pub fn required(uploader: Uploader) -> Uploader

Do not let the form submit without a file.

pub fn stored(
  uploader: Uploader,
  files: List(Stored),
) -> Uploader

Files already stored, shown first.

pub fn uploader_class() -> css.Class
pub fn view(uploader: Uploader) -> element.Element(msg)

The uploader on its own.

pub fn words(uploader: Uploader, words: Words) -> Uploader

Say things in other words, or another language.

✨ Search Document