Подтвердить что ты не робот

Триггерное нажатие на input = файл при асинхронном выполнении ajax()

У меня есть форма с некоторыми данными и загрузка. Загрузка может быть инициирована только в том случае, если данные были успешно получены и обработаны. Для этого я делаю вызов ajax, где I

  • отправить данные,
  • проверить его результат,
  • вызвать клик(), чтобы открыть диалоговое окно файла.

Последняя вещь с click() не работает, поскольку кажется, что блоки асинхронного вызова открывают окно загрузки. Он работает, только если я установил async: false.

Я не могу найти что-либо в документации и на этом сайте и хочу знать, в чем проблема, и как заставить ее работать, сохраняя асинхронный вызов?

Пример:

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

//$("#upload").click();       [2]

Демо: http://jsfiddle.net/c2v00uxn/

Примечание:

  • Если я раскомментирую [1] или [2], он работает (диалог файла появляется, как ожидалось).
  • заменить click() с помощью триггера ('click') не работает
  • заменить click() с помощью live()/on() не помогает
  • Управление загрузкой файлов видно в соответствии с примером (так что это не из-за скрытого управления).
  • Настройки таймаута для ajax не помогают.

ОБНОВЛЕНИЕ

Это не о том, как сделать "click" в общем, о том, как щелкнуть после асинхронного вызова ajax (на данный момент работает только с неасинхронным вызовом).

4b9b3361

Ответ 1

Невозможно прямо сейчас открыть всплывающее окно файла из обратного вызова async ajax из-за рекомендованных w3c функций безопасности в браузерах.

В действии активации элемента ввода файла он сначала проверяет, разрешен ли алгоритм показывать всплывающее окно, а затем отменяет следующие шаги, не делая ничего другого. от w3c.org

Алгоритм позволяет отображать всплывающее окно, если выполняется одно из следующих условий:

  • Задача, в которой работает алгоритм, в настоящее время обрабатывает поведение активации, которому было присвоено событие click. (доверенные события: события, которые генерируются пользовательским агентом, либо в результате взаимодействия с пользователем, либо как прямой результат изменений в DOM, являются надежными пользовательским агентом с привилегиями, которые не предоставляются событиям, генерируемым с помощью script, через метод DocumentEvent.createEvent("Event"), модифицированный с помощью метода Event.initEvent() или отправленный методом EventTarget.dispatchEvent(). Атрибут isTrusted доверенных событий имеет значение true, а недоверенные события имеют значение атрибута isTrusted false. в противном случае. http://www.w3.org/TR/2012/WD-DOM-Level-3-Events-20120614/#trusted-events.)
  • Задача, в которой работает алгоритм, в настоящее время запускает прослушиватель событий для доверенного события, тип которого находится в следующем список:

    • изменить
    • выберите
    • DblClick
    • MouseUp
    • reset
    • представить
  • Задача, в которой выполняется алгоритм, была поставлена ​​в очередь алгоритм, которому было разрешено отображать всплывающее окно, и цепочка таких алгоритмы, запущенные в пользовательском агенте, определены таймфреймом.

w3c.org

В вашем коде событие клика не запускается пользователем, а запускается с помощью полного обратного вызова ajax. Здесь браузер заявляет, что этому событию нельзя доверять, чтобы открыть всплывающее окно. В некоторых браузерах атрибут isTrusted имеет значение true, если событие объявлено как доверенное. https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted

Примечание

Различные браузеры ловят разницу между активированным кликом script и реальным пользователем с использованием разных методов.

Что вы можете сделать в этом сценарии, это отключить кнопку ввода файла (или всю форму) и включить после завершения ajax. Таким образом, пользователь не будет нажимать кнопку загрузки до тех пор, пока запрос ajax не будет завершен. На данный момент нет другого способа сделать это за один клик, так как для открытия всплывающего окна есть ограничение по таймфрейму. Когда я проверил в хроме, таймфрейм равен 1000 мс. 1000 мс после действия пользователя, окно не открывается.

Ответ 2

У меня есть решение, которое работает сейчас. Это взлом, поэтому он может не работать в ближайшем будущем, поскольку он обходит функции безопасности, упомянутые выше Ткаем.

Я представляю тайм-аут, ожидающий запроса ajax, чтобы вернуть данные, которые я хочу проверить, прежде чем запускать диалог браузера файлов.

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
});

Честно говоря, я немного не уверен, почему именно эта работа за исключением явно проходящих специфических тестов в браузере, обычно запрещающих такое поведение. Поэтому я считаю это взломом.

Моим примером является vanilla JS, но создать jQuery-версию должно быть легко. Для полного примера см. JSFiddle.

(Это мое первое участие в создании, поэтому, пожалуйста, прокомментируйте возможные ошибки и недочеты)

Ответ 3

JQuery сам говорит, что триггер не будет работать для таких элементов, как загрузка файлов и привязка. (источник - https://learn.jquery.com/events/triggering-event-handlers/)

Функция .trigger() не может использоваться для имитации собственных событий браузера, например, нажатие на поле ввода файла или якорный тег. Это потому что при использовании события jQuery обработчик события отсутствует которая соответствует этим событиям.

Итак, в этом случае вам может понадобиться создавать события вручную, используя следующие функции javascript.

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

Пример кода + определение вышеупомянутых функций можно найти на сайте разработчика Mozilla

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

Возможно, это поможет вам.

Ответ 4

$(function () {
    $('#demo').click(function () {         
        $.ajax({
            type: "POST",
            url: "/echo/json/",
            data: "jsonText",
            dataType: "json",
            }).done(function (msg) {
            $("#demo").addClass("test");
            }).fail(function(jqXHR, textStatus, errorThrown){
                alert(textStatus);  
            });
        if($("#demo").hasClass("test")){
           $("#upload").click(); 
        }
    });
});