Только одна зона падения работает, когда несколько динамически инициализированы

#javascript #jquery #dropzone.js #dropzone

Вопрос:

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

 <script src="/js/dropzone.min.js"></script>
<script>
Dropzone.autoDiscover = false;
window.dropzones = {};


function checkDropzones(container) {
    var possibleDropzones = container.querySelectorAll('.needs-to-be-dropzoned');
    possibleDropzones.forEach(function (zone) {
        if (zone.id.length === 0) {
            zone.id = 'dropzone_filled_'   (new Date()).getTime();
            window.dropzones[zone.id] = new Dropzone(
                '#'   zone.id,
                {
                    paramName: 'image',
                    addRemoveLinks: true,
                }
            );
        }
    })
}

function renderServerContent() {
    window.customSections.forEach(function (custom_section) {
        var container = document.getElementById(custom_section);
        $.ajax({
            method: 'GET',
            url: '/customRenderUrl?section='   custom_section,
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            },
            success: function (response) {
                container.innerHTML = container.innerHTML   response.component;
                if (response.component_type === 'image_uploader') {
                    checkDropzones(container);
                }
                // ... other marginal stuff ... 
            },
            dataType: 'json'
        })
    })
}

// ... other scripts ... 

window.customSections = [/* server stuff */];
renderServerContent();
</script>
 

В принципе, у меня есть некоторые вещи, которые будут отображаться динамически с сервера, поэтому я отправляю запрос на компонент предоставляемых данных, и когда я получаю ответ обратно, я проверю, если вставлять контент содержит элемент .needs-to-be-dropzoned , если да, то назначить ему время,-на основании удостоверения личности (компонент рендеринга имеет задержку между каждым компонентом, так что идентификаторы уникальны) и, например, зоны для перемещения. Это хорошо работает только с одной зоной выпадения, но когда несколько находятся на одной странице, это не приведет к ошибкам, а будет работать только для последнего элемента на странице.

Содержимое сервера выглядит примерно так:

 <form
    class="col-12 container-fluid pb-2 dropzone needs-to-be-dropzoned"
    method="POST"
    action="/imageUploadUrl"
>
    <input type="hidden" name="_token" value="..." >

    <div class="dz-default dz-message">
        Upload files
    </div>
    <div class="fallback">
        <input name=image" type="file" />
    </div>
</form>
 

Если я запущу a console.dir(window.dropzones) , я получу 2 объекта:

 Object { dropzone_filled_1624370363574: {…}, dropzone_filled_1624370363803: {…} }
​
dropzone_filled_1624370363574: Object { element: form#dropzone_filled_1624370363574.col-12.container-fluid.pb-2.dropzone.needs-to-be-dropzoned.dz-clickable, version: "5.9.2", clickableElements: (1) […], … }
​
dropzone_filled_1624370363803: Object { element: form#dropzone_filled_1624370363803.col-12.container-fluid.pb-2.dropzone.needs-to-be-dropzoned.dz-clickable, version: "5.9.2", clickableElements: (1) […], … }
 

Что я делаю не так или упускаю?

Комментарии:

1. » Я присваиваю ему случайный идентификатор » — 'dropzone_filled_' (new Date()).getTime() это не случайно. Какую отладку вы пробовали? Вы проверили, действительно ли ваши идентификаторы отличаются при создании? Как window.dropzones выглядит, например, что console.dir(window.dropzones); показывает?

2. Да, извините, я не имел в виду случайность строго, я имел в виду случайность, потому что формы не имеют идентификатора перед его назначением, кстати, между рендерингом каждого компонента есть небольшая задержка, поэтому getTime они будут назначать разные идентификаторы. window.dropzones Содержит различные объекты dropzones, я исправлю вопрос

3. Как я уже сказал, dropzones, похоже, работают, window.dropzones содержит два объекта dropzone, но работает только последний инициализированный

4. Странный. Мне удалось заставить ваш код работать в JSFiddle . Созданы 2 выпадающие зоны, и обе работают. Единственные изменения, которые я внес, связаны с подделкой вызова AJAX на JSFiddle, используя их специальный /echo/json/ URL -адрес, и подделкой ответа сервера, который, предположительно, выглядит как ваш. Посмотрите, может быть, что-то выскочит на вас, но пока я в тупике!

Ответ №1:

Я предпринимал различные попытки исправить это, и, наконец, исправил это, завернув все вызовы сервера в обещания, дождался решения всех обещаний и только после этого проверил наличие выпадающих зон. Код примерно такой:

 <script src="/js/dropzone.min.js"></script>
<script>
Dropzone.autoDiscover = false;
window.dropzones = {};
window.containersToCheck = [];


function checkDropzones(container) {
    var possibleDropzones = container.querySelectorAll('.needs-to-be-dropzoned');
    possibleDropzones.forEach(function (zone) {
        if (zone.id.length === 0) {
            zone.id = 'dropzone_filled_'   (new Date()).getTime();
            window.dropzones[zone.id] = new Dropzone(
                '#'   zone.id,
                {
                    paramName: 'image',
                    addRemoveLinks: true,
                }
            );
        }
    })
}

function renderServerContent() {
    return new Promise(function(resolve, reject) {
        window.customSections.forEach(function (custom_section) {
            var container = document.getElementById(custom_section);
            $.ajax({
                method: 'GET',
                url: '/customRenderUrl?section='   custom_section,
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    container.innerHTML = container.innerHTML   response.component;
                    if (response.component_type === 'image_uploader') {
                        window.containersToCheck.push(container);
                    }
                    resolve();
                    // ... other marginal stuff ... 
                },
                dataType: 'json'
            })
        })
    });
}

// ... other scripts ... 

window.customSections = [/* server stuff */];
var promises = [];
promises.push(renderServerContent());
// other renderings
Promise.all(promises).then(function (results) {
    window.containersToCheck.forEach(function(container) {
        checkDropzones(container);
    });
})
</script>
 

Таким образом, все зоны выпадения работают.