BootstrapVallidation качване на снимки (multiple)

Ticketa

Registered
Привет, някой можели да удари рамо за JavaScript валидиране при качване на снимки.


използвам BootstrapVallidation за валидиране на снимки и след това ги проверям и чрез php - с цел да няма манипулиране.

Обаче към момента не мога да огранича броя снимки чрез javascript.

Искам да бъдат максимум 10
html;
<input id="ID-img" name="img[]" type="file" multiple="multiple">

Код:
                        img: {

                            validators: {

                                file: {

                                    extension: 'jpeg,jpg,png,gif',

                                    type: 'image/jpeg,image/png,image/gif',

                                    message: 'Моля изберете файл до 5 мб с разширение: gif, jpeg, jpg, png!'

                                }

                            }

                        },


Пробвах да добавя
maxFiles: 10,

Обаче не работи :shock:
 
Не можах да намеря коя точно библиотека ползваш (като че ли има 2 или повече с това име).
Няма ли възможност да се добави custom валидатор с който да провериш колко файла има полето?
 
Код:
/*!
 * BootstrapValidator (http://bootstrapvalidator.com)
 * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
 *
 * @version     v0.5.2, built on 2014-09-25 4:01:07 PM
 * @author      https://twitter.com/nghuuphuoc
 * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
 * @license     MIT
 */

Иначе за къстъм решение и мен ми мина през ума, защото в самия валидатор не открих функция, която да позволява проверка на броя файлове

Това, което видях като "атрибути" (ако така е правилно да се казва)

Код:
        html5Attributes: {
            extension: 'extension',
            maxsize: 'maxSize',
            minsize: 'minSize',
            message: 'message',
            type: 'type'
        },

        /**
         * Validate upload file. Use HTML 5 API if the browser supports
         *
         * @param {BootstrapValidator} validator The validator plugin instance
         * @param {jQuery} $field Field element
         * @param {Object} options Can consist of the following keys:
         * - extension: The allowed extensions, separated by a comma
         * - maxSize: The maximum size in bytes
         * - minSize: the minimum size in bytes
         * - message: The invalid message
         * - type: The allowed MIME type, separated by a comma
         * @returns {Boolean}
         */
 
Май е това - https://github.com/alavers/bootstrapvalidator.
Гледам че е базирано на `formvalidation`. Там може да се добави custom ето така: https://formvalidation.io/guide/examples/creating-a-custom-validator

Само вместо FormValidation.validators най-вероятно пишеш BootstrapValidator.validators.
 
djman, пробвах различни начини , но не сработва.

Като цяла идеята ми е , снимката преди да мине през backend (php) да бъде проверена чрез javascript валидация, да се покаже като preview и първата снимка да става Main т.е. главна снимка.

Чрез php отново правя проверки и просто "игнорирам"/"спирам" качването на нередовна снимка - като в края съобщавам на потребителя:
Имате 9 качени снимки и 1 некачена, която не съвпада с нашите условия. - тук целта при php е колкото може да се избегнат пишман хакерите.

Въпроса е, как да го съчетая (custum javascript) с bootstrapvalidator ;

Това, което се опитвам да направя е да изглежда така: https://bootsnipp.com/snippets/2eNKz
Просто "филтрацията" да минава през boostrapvalidator(понеже минавам цялата <form></form> и да няма вземане от тук оттам кодове и да става мазало)

Ползвам boostrap 3
 
Аз за качване на снимки ползвам https://www.dropzonejs.com/ . Много е удобно и има всякакви екстри :)
 
Аз разбрах какво искаш, направи функция по подобие на тази от първия линк, регистрирай я във валидатора (Registering custom validator) и я използвай както използваш extension и type.

Функцията приема самия input, от който можеш да вземеш това, което те интересува (тук има няколко варианта) - броя на избрани файлове. Виж примера със "strongPassword" валидатора.

Пробвай така. Ако не стане, напиши как точно пробваш (код), за да има откъде да започнем. :)

---
А, разбира се, че има много други варианти...
 
Пробвам по този начин (https://s.bootsnipp.com/iframe/2eNKz) (за момента оставих на страна bootstrapvalidation-а тъй като не се получиха нещата)

Обаче функцията за проверка на общия брой работи само когато прикачвам "накуп" т.е. всички снимки. Обаче, ако си играя 1 по 1 , тогава всякаш функцията неработи и можеш да качиш и 20 снимки , но 1 по 1

Код:
if (i > 10){ //не сработва
                alert("можеш да качиш максимум 10 файла.");
            } else {

Код:
<script type="text/javascript">
	$(document).ready(function() {
    document.getElementById('pro-image').addEventListener('change', readImage, false);
    
    $( ".preview-images-zone" ).sortable();
    
    $(document).on('click', '.image-cancel', function() {
        let no = $(this).data('no');
        $(".preview-image.preview-show-"+no).remove();
    });
});

var num = 10;
function readImage() {
    if (window.File && window.FileList && window.FileReader) {
        var files = event.target.files; //FileList object
        var output = $(".preview-images-zone");

        for (let i = 0; i < files.length; i++) {
            if (i > 10){
                alert("можеш да качиш максимум 10 файла.");
            } else {
            var file = files[i];
            if (!file.type.match('image')) continue;
            
            var picReader = new FileReader();
            
            picReader.addEventListener('load', function (event) {
                var picFile = event.target;
                var html =  '<div class="preview-image preview-show-' + num + '">' +
                            '<div class="image-cancel" data-no="' + num + '">x</div>' +
                            '<div class="image-zone"><img id="pro-img-' + num + '" src="' + picFile.result + '"></div>' +
                            '<div class="tools-edit-image"><a href="javascript:void(0)" data-no="' + num + '" class="btn btn-light btn-edit-image">edit</a></div>' +
                            '</div>';

                output.append(html);
                num = num + 1;
            });

            picReader.readAsDataURL(file);
            }
        }
        $("#pro-image").val('');
    } else {
        console.log('Browser not support');
    }
}

	</script>
 
Еми логично е. При качване една по една, това е заявка за заявка. JavaScript ще ти ограничи броя само, когато са накуп, защото тогава са много файлове - една заявка.
 
Revelation каза:
Еми логично е. При качване една по една, това е заявка за заявка. JavaScript ще ти ограничи броя само, когато са накуп, защото тогава са много файлове - една заявка.

В такъв случай значи няма да мога да ги проверявам(?) , кофти, не се бях замислил
 
Ticketa каза:
Revelation каза:
Еми логично е. При качване една по една, това е заявка за заявка. JavaScript ще ти ограничи броя само, когато са накуп, защото тогава са много файлове - една заявка.

В такъв случай значи няма да мога да ги проверявам(?) , кофти, не се бях замислил

E защо - просто си пазиш в една променлива колко файла си пратил до сървъра към момента и премахваш полето, като надвишат 10?
 
Ако идеята ти е да ограничиш общия брой файлове за качване за потребител, то тази проверка става на backend-а и просто отказваш всяка нова заявка за качване, ако общия брой е надвишен.
Ако искаш просто да ограничиш броя файлове накуп, то тогава това няма какво да те притеснява, защото ти де факто ограничаваш броя накуп.
Ако потрбителя качва файловете един по един, не виждам защо трябва да броиш нещо от клиентска гледна точка.

Ако имаш общ лимит от страна на сървъра, дори и да качва файл по файл, в един момент сървъра просто ще го отреже.

Ако искаш да направиш това с цел ограничение на заявките към сървъра, то те уверявам, че си губиш времето с безсмислени неща.
 
Revelation каза:
Ако идеята ти е да ограничиш общия брой файлове за качване за потребител, то тази проверка става на backend-а и просто отказваш всяка нова заявка за качване, ако общия брой е надвишен.
Ако искаш просто да ограничиш броя файлове накуп, то тогава това няма какво да те притеснява, защото ти де факто ограничаваш броя накуп.
Ако потрбителя качва файловете един по един, не виждам защо трябва да броиш нещо от клиентска гледна точка.

Ако имаш общ лимит от страна на сървъра, дори и да качва файл по файл, в един момент сървъра просто ще го отреже.

Ако искаш да направиш това с цел ограничение на заявките към сървъра, то те уверявам, че си губиш времето с безсмислени неща.

Бекенда проверява общия брой на изпратени файлове, проверява и неговите формати (jpg png) , просто целта ми е при опит за прикачване на файловете (без значение накуп или един по един) да се визуализира предупреждение: Имате възможност да прикачите максимум 10 снимки съответстващи на формати: jpg png
 
Ами от сървърна гледна точка, щом имаш лимит от 10 (като цяло), то тогава не проверявай само колко са изпратени накуп.
След като получиш заявка за качване, сравняваш с базата данни (или както ги записваш нещата) и ако дадения потребител е надвишил лимита си просто връщаш грешка, с описание защо заявката е прекъсната.

От клиентска гледна точка трябва да можеш да правиш следното:
  • Да абсорбираш адекватно грешки върнати от сървъра, напр. надвишаване на лимит
  • Можеш да предотвратиш броя накуп
  • Можеш да валидираш разширения и прочие

От сървърна гледна точка:
  • Трябва да обхваща всеки use case, който е в обхвата на приложението ти. В твоя случай:
    • Валидация дали потребителя е надвишил лимита си (това може да включва за определен период или като цяло, или както ти решиш)
    • Ако лимита не е надвишен - валидация за общия брой изпратени файлове. В този случай можеш или да обработиш само част или да върнеш грешка, че броя файлове наведнъж е надвишен.
    • Валидация по общ размер на заявката (общия размер на всички изпратени файлове)
    • Валидация за име на файла
    • Валидация по разширение
    • и т.н.

Ако приложението е SPA (Single Page Application), то тогава ако искаш си сложи брояч и на клиента. Тогава само при рефреш ще губиш общия брой файлове, които са качени до сега, но знаеш, че си имаш валидацията от сървъра, която трябва да можеш абсорбираш адекватно на клиента.
Няма смисъл да записваш брой в бисквитки, local/session storage и т.н. Безсмислено е, защото всеки може да ги достъпи.
 
Скаран съм с JavaScript;
В момента имам "напредък" чрез
Код:
if (num > 10) {
ги изброявам файловете и когато ги надвишава изкарва съобщение
You can only upload a maximum of 10 files

Обаче хипотетично, ако някоя снимка е объркана или не ти харесва от тези 10 прикачени вече ти можеш да е премахнеш и да добавиш нова .... нооо скрипта не го позволява защото брояча num() вече е изброил 10те първи и не е приспаднал премахната и тя се пада като 11та

Не съм сигурен дали напълно ме разбрахте :D прикачвам демо https://jsfiddle.net/uqwzL34p/


Обмислях вариант при
Код:
    $(document).on('click', '.image-cancel', function() {
        let no = $(this).data('no');
        $(".preview-image.preview-show-"+no).remove();
    });

Да вкарам променливата num-1 и да приспада с 1 число на долу, но до колко това е правилно? (като при този начин пък... се получава дублиране на числа, например:

saveimage.png


https://jsfiddle.net/g2huzyqx/
Код:
<script type="text/javascript">
var num = 4;
	$(document).ready(function() {
    document.getElementById('pro-image').addEventListener('change', readImage, false);
    
    $( ".preview-images-zone" ).sortable();
    
    $(document).on('click', '.image-cancel', function() {
        let no = $(this).data('no');
        num = num - 1;
        $(".preview-image.preview-show-"+no).remove();
    });
});

function readImage() {
    if (window.File && window.FileList && window.FileReader) {
        var files = event.target.files; //FileList object
        var output = $(".preview-images-zone");

        for (let i = 0; i < files.length; i++) {
            //alert(num);
            if (num > 10) {
                alert("You can only upload a maximum of 10 files");
            } else {
            var file = files[i];
            if (!file.type.match('image')) continue;
            
            var picReader = new FileReader();
            
            picReader.addEventListener('load', function (event) {
                var picFile = event.target;
                var html =  '<div class="preview-image preview-show-' + num + '">' +
                            '<div class="image-cancel" data-no="' + num + '">x</div>' +
                            '<div class="image-zone"><img id="pro-img-' + num + '" src="' + picFile.result + '"></div>' +
                            '<div class="tools-edit-image"><a href="javascript:void(0)" data-no="' + num + '" class="btn btn-light btn-edit-image">edit</a></div>' +
                            '</div>';

                output.append(html);
                num = num + 1;
            });

            picReader.readAsDataURL(file);
            }
        }
        $("#pro-image").val('');
    } else {
        console.log('Browser not support');
    }
}

	</script>
 
Revelation каза:
Кога става точно комуникацията със сървъра?

След натискане на бутон "submit", тогава се изпращат данните
 
Втория примерен код, изглежда да работи нормално, и да щом заявката я изпращаш накрая, можеш да си използваш брояч по този начин.

По принцип не е хубаво да използваш глобални променливи. Можеш да оплетеш нещата доста хубаво и накрая ще се чудиш от къде ти е дошло.

За да се увериш, че броиш правилно можеш да направиш следното:

Вариант 1: Слагаш идентификатор на контейнера, който държи контейнерите с картинките и при onChange винаги взимаш този контейнер и следиш колко директни елемента има този контейнер.

Вариант 2: Слагаш еднакъв идентификатор на всички контейнери с картинките(някакъв class) и след това ги взимаш като лист, на който можеш да използваш length свойството, за да вземеш броя елементи.
С този вариант можеш да сложиш click събитието на класа и при премахване не ти трябва да знаеш номера, а вместо това да използваш $(this).remove().
 
В крайна сметка как го направи че и на мен ми стана любопитно?
 

Горе