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'.
É 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)