Clique no gatilho input = file no ajax asynchronous done ()

Eu tenho um formulário com alguns dados e upload. O upload pode ser iniciado somente se os dados forem recebidos e processados ​​com sucesso. Para fazer isso, eu faço uma chamada ajax onde eu

  1. enviar dados
  2. verifique seu resultado,
  3. acione um clique () para abrir uma checkbox de diálogo de arquivo.

A última coisa com click () não funciona, pois parece que blocos de chamadas assíncronas abrem uma janela de upload . Só funciona se eu definir async: false .

Não consigo encontrar nada na documentação e neste site e quero saber qual é o problema e como fazê-lo funcionar mantendo a chamada assíncrona?

Exemplo:

 $.ajax({ type: "POST", url: "/Save", data: jsonText, dataType: "json", //async: false [1] }).done(function (msg) { $("#upload").click(); }); //$("#upload").click(); [2] 

Demonstração: http://jsfiddle.net/c2v00uxn/

Nota:

  • se eu descomentar [1] ou [2], funciona (a checkbox de diálogo de arquivo aparece como esperado).
  • replace click () com trigger (‘click’) não funciona
  • replace click () por live () / on () não ajuda
  • controle de upload de arquivo é visível como por exemplo (por isso não é por causa do controle oculto)
  • configurações de tempo limite para ajax não ajudam.

ATUALIZAR

Não é sobre como fazer um “click” em geral, é sobre como clicar após uma chamada ajax assíncrona (a partir de agora, funciona apenas com uma chamada não assíncrona).

Não é possível agora abrir uma janela pop-up de arquivo a partir de um retorno de chamada ajax asynchronous devido aos resources de segurança recomendados pelo w3c nos navegadores.

No comportamento de ativação do elemento de input de arquivo, ele primeiro verifica se o algoritmo tem permissão para mostrar um pop-up , se não abortar os próximos passos sem fazer mais nada. de w3c.org

Um algoritmo pode mostrar um pop-up se qualquer uma das seguintes condições for verdadeira:

  1. A tarefa na qual o algoritmo está em execução está processando atualmente um comportamento de ativação cujo evento de clique foi confiável . (Eventos confiáveis: Eventos gerados pelo agente do usuário, como resultado da interação do usuário ou como resultado direto de alterações no DOM, são confiáveis ​​pelo agente do usuário com privilégios que não são concedidos a events gerados pelo script através do método DocumentEvent.createEvent("Event") , modificado usando o método Event.initEvent() ou despachado via EventTarget.dispatchEvent() O atributo isTrusted de events confiáveis ​​tem um valor verdadeiro, enquanto que events não confiáveis ​​têm um valor de atributo isTrusted como falso, caso contrário, http://www.w3.org/TR/2012/WD-DOM-Level-3-Events -20120614 / # trusted-events .)
  2. A tarefa na qual o algoritmo está sendo executado está executando atualmente o ouvinte de events para um evento confiável cujo tipo está na lista a seguir:

    • mudança
    • clique
    • dblclick
    • mouseup
    • restabelecer
    • enviar
  3. A tarefa na qual o algoritmo está em execução era enfileirada por um algoritmo que permitia mostrar um pop-up e a cadeia de tais algoritmos era iniciada dentro de um período de tempo definido pelo agente do usuário.

w3c.org

Em seu código, o evento click não é acionado pelo usuário, mas é acionado pelo callback completo do ajax. Aqui, o navegador declara que o evento não pode ser confiável para abrir um pop-up. Em alguns navegadores, você pode ver um atributo isTrusted definido como true se o evento for declarado como confiável. https://developer.mozilla.org/pt-BR/docs/Web/API/Event/isTrusted

Nota

Navegadores diferentes prendem a diferença entre um script ativado e um usuário real usando diferentes methods.

O que você pode fazer neste cenário é desabilitar o botão de input de arquivo (ou o formulário inteiro) e habilitar após o ajax ser feito. Dessa forma, o usuário não clicará no botão de upload até que a solicitação do ajax seja concluída. A partir de agora não há outra maneira de fazer os dois em um clique, pois há um limite de tempo também para abrir o popup. Quando eu chequei no cromo, o prazo é de 1000 ms. 1000ms após a ação do usuário, a janela não será aberta.

JQuery em si diz que, o gatilho não funcionará para elementos como upload de arquivos e âncora. (fonte: https://learn.jquery.com/events/triggering-event-handlers/ )

A function .trigger () não pode ser usada para imitar events nativos do navegador, como clicar em uma checkbox de input de arquivo ou em uma marca de âncora. Isso porque, não há nenhum manipulador de events anexado usando o sistema de events do jQuery que corresponda a esses events.

Então, nesse caso, você pode precisar criar events manualmente usando as seguintes funções de javascript.

  • document.createEvent
  • event.initMouseEvent
  • element.dispatchEvent

Um exemplo de código + definição para as funções acima mencionadas pode ser encontrado no site do desenvolvedor do Mozilla.

https://developer.mozilla.org/samples/domref/dispatchEvent.html

Talvez isso ajude você.

Eu tenho uma solução que funciona por enquanto. É um hack, por isso pode não funcionar em um futuro próximo, pois contorna os resources de segurança mencionados por Tkay acima.

Eu introduzo um tempo limite que aguarda a solicitação do ajax para retornar os dados que desejo verificar antes de iniciar a checkbox de diálogo do navegador de arquivos.

 customFileUploadButton.addEventListener('click', function(e) { var returnValueToCheck; //Value we want to check against //reference to vanilla JS ajax function that takes callback ajax(function(ajaxData) { returnValueToCheck = ajaxData; }); setTimeout(function() { if (returnValueToCheck !== undefined) { //dummy check for example file.click(); } else { console.log("Criteria not fulfilled"); } }, 1000);//timer should be larger than AJAX timeout }); 

Para ser honesto, estou um pouco inseguro sobre por que exatamente esse trabalho, além de aparentemente passar nos testes específicos do navegador, normalmente proíbe esse tipo de comportamento. Por isso eu considero isso como um hack.

Meu exemplo é vanilla JS, mas deve ser fácil criar uma versão do jQuery. Veja este JSFiddle para o exemplo completo.

(Este é o meu primeiro empreendimento a contribuir, por favor, comente sobre possíveis erros e omissões)