DEV Community

Gabriel Gomes de Oliveira
Gabriel Gomes de Oliveira

Posted on

Usando Stimulus para mostrar o nome da imagem no input de arquivo

Oi, mais um post rápido para ensinar o que acabei de aprender: a usar o Stimulus para conseguir mostrar ao usuário o nome do arquivo que ele está fazendo upload no input tipo 'file'.

Input type file

É bem chato não mostrar isso para o usuário e, apesar de ser algo bem simples de ser feito com Javascript puro, eu queria aprender como se faz usando o Stimulus!

Primeiro, adicionamos nosso data-controller na tag que engloba o nosso input. No caso, estou modificando um formulário de criação de livros na minha biblioteca pessoal

app/views/books/new.html.erb

  <div data-controller="file-input">
    <label for="file">Escolha uma imagem para capa do livro</label>
    <input type="file" id="file" name="file" />
    <p>Nenhum arquivo selecionado...</p>
  </div>

Depois, criamos o file_input_controller para manipular essa estrutura.

app/javascript/controllers/file_input_controller

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
}

Precisamos então pensar quais são nossos "alvos", targets, para nossas ações. Queremos que nosso usuário veja o nome do arquivo selecionado após o input, então precisamos verificar o momento que ele faz essa seleção e também precisamos do local onde colocaremos a informação. Então, nossos targets são o input em si e o parágrafo logo em seguida, que mostra ou não se um arquivo foi escolhido.

app/views/books/new.html.erb

  <div data-controller="file-input">
    <label for="file">Escolha uma imagem para capa do livro</label>
    <input type="file" id="file" name="file" data-file-input-target="input" />
    <p data-file-input-target="fileName">Nenhum arquivo selecionado...</p>
  </div>

Criamos também as variáveis dos targets em nosso controller:

app/javascript/controllers/file_input_controller

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["input", "fileName"];
}

Precisamos pensar agora em que momento queremos averiguar essa informação. Ou seja, quando o usuário vai querer ter essa interação com o formulário ou quando ela tem que estar disponível para ele?

Oras, imediatamente, assim que a página é carregada, isso já precisa estar disponível funcionalmente.

Dessa forma, vamos chamar o método connect(), que é um lifecycle callback do Stimulus, uma função nativa que vai ser chamada assim que o nosso controller for conectado com alguma parte da DOM.

Como nós queremos verificar se o usuário adicionou um arquivo pelo input, precisamos adicionar algo que observe qualquer mudança nesse elemento e modifique o texto com o nome do arquivo.

Assim, temos o seguinte:

app/javascript/controllers/file_input_controller

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
    static targets = ["input", "fileName"];

    connect() {
      this.inputTarget.addEventListener("change", this.updateFileName.bind(this));
    }

    updateFileName() {      
      if (this.inputTarget.files.length > 0) {
        this.fileNameTarget.textContent = this.inputTarget.files[0].name;
      }
    }
}

Explicando tudo, assim que o controller se conectar com o elemento DOM com o atributo data-controller="file-input", ele vai buscar o target input (marcado com o atributo data-file-input-target="input") e vai adicionar o "observador de eventos" de change, conectando o contexto do controller para a função updateFileName.

A função updateFileName vai ser ativada quando o valor do input for alterado, verificando se há algum arquivo e, se houver, irá alterar o conteúdo do elemento marcado com o fileNameTarget para o nome do arquivo. E voilà, é isso, acabou.

Parando pra pensar agora, acho que eu quero mostrar a imagem para o usuário também, mas isso eu faço outro dia! Abraço

Top comments (0)