Em aplicações web é comum existir a necessidade de pedir para que o usuário selecione um ou mais arquivos. O jeito mais fácil de fazer isso é utilizando o elemento input com type=”file”, mas isso obriga que o usuário clique no respectivo componente renderizado.
Muitas vezes a proposta da aplicação que você está desenvolvendo pede um UX diferente desse padrão do browser.
Para poder chamar a janela de seleção de arquivos programaticamente via JavaScript ou TypeScript, sem a necessidade de clique do usuário, eu fiz essa função:
function selectFiles(multiple) { return new Promise(function (resolve) { const input = document.createElement('input'); input.setAttribute('type', 'file'); if (multiple) { input.setAttribute('multiple', 'multiple'); } input.addEventListener('change', function (e) { const fileList = []; for (const file of e.target.files) { fileList.push(file) } resolve(fileList); input.remove(); }); input.click(); }); }
const selectFiles = (multiple = false): Promise<File[]> => { return new Promise(resolve => { const input = document.createElement('input'); input.setAttribute('type', 'file'); if (multiple) { input.setAttribute('multiple', 'multiple'); } input.addEventListener('change', (e: any) => { const fileList: File[] = []; for (const file of e.target.files) { fileList.push(file) } resolve(fileList); input.remove(); }); input.click(); }); }
A função retornar uma promise de um array de files. O único parâmetro é um booleano com padrão false que indica se serão múltiplos arquivos.
A utilização fica assim:
// Teste com async / await async test1() { const fileList = await selectFiles(); for (const file of fileList) { console.log(file.name); } } // Teste sem async / await test2() { selectFiles().then(fileList => { for (const file of fileList) { console.log(file.name); } }); }
Espero que isso ajude alguém!