Autor Zpráva
Tirus
Profil
Snažím se napsat drop zonu pro X souborů. Funkčnost má být taková, že tam dropnu XXX souborů a následně je jeden po druhým odešlu buď jako formulář, nebo jako json objekt (ajaxově) a následně bych si vrátil pouze snippet (v Nette) a ten si nahradil aby uživatel viděl v seznamu fotek i tu přidanou a tu co se zrovna odeslala, z toho seznamu souborů buď odebrat a nebo ji označit jako success

Takže tolik kolik dám souborů, tolikrát se mi to odešle na server a tolikrát se mi překreslí seznam fotek.

                evt.stopPropagation();
                evt.preventDefault();

                var files = evt.dataTransfer.files; // FileList object.
                // files is a FileList of File objects. List some properties.
                var output = [];
                for (var i = 0, f; f = files[i]; i++) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    output.push('<li class="bg-info" id="file_' + i + '"><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                            f.size, ' bytes',
                            '</li>');
                }
                document.getElementById('list').innerHTML = '<ul class="files">' + output.join('') + '</ul>';
                for (var i = 0, f; f = files[i]; i++) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    reader = new FileReader();
                    reader.onload = function(e) {
                        console.log(e);
                        document.getElementById('file_' + i).className = 'bg-success'; // zde mi to pise Uncaught TypeError: Cannot set property 'className' of null 
                        //coz mi prijde jako hloupost, protoze element s ID file_# tam je
                    };
                    reader.readAsText(f)
                }

            }
            function handleDragOver(evt) {
                evt.stopPropagation();
                evt.preventDefault();
                evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
            }

            // Setup the dnd listeners.
            var dropZone = document.getElementById('drop_zone');
            dropZone.addEventListener('dragover', handleDragOver, false);
            dropZone.addEventListener('drop', handleFileSelect, false);
Chamurappi
Profil
Reaguji na Tira:
document.getElementById('file_' + i).className = 'bg-success'; // zde mi to píše Uncaught TypeError: Cannot set property 'className' of null 
Hodnota proměnné i v okamžiku zavolání funkce v onload bude už jiná, než jaká byla při vzniku této funkce. V té doby už cyklus dávno skončil (kvůli tomu, že i přesáhlo velikost pole files). Potřebuješ to íčko nějak zakonzervovat, viz lexikální uzávěr.
Tirus
Profil
Chamurappi:

1. jsi první na diskusních forech, kdo můj nick správně sklonil :)
2. zpět k dotazu

Upravil jsem to na
 reader.onload = function(e, i) {
                        console.log(e);
                        document.getElementById('file_' + index).className = 'bg-success'; 
                        //coz mi prijde jako hloupost, protoze element s ID file_# tam je
                    }(i);
Ale stále to nefunguje. S JS nemám skoro žádné zkušenosti :(
juriad
Profil
Tirus:
To skoloňování je zde automatické :-) Napiš do odpovědi písmena ri a pak Ctrl+Dolů a najeď šipkami na zdejší jména.

                for (var i = 0, f; f = files[i]; i++) (function(index) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    reader = new FileReader();
                    reader.onload = function(e) {
                        console.log(e);
                        document.getElementById('file_' + index).className = 'bg-success'; // zde mi to pise Uncaught TypeError: Cannot set property 'className' of null 
                        //coz mi prijde jako hloupost, protoze element s ID file_# tam je
                    };
                    reader.readAsText(f)
                })(i);

Aneb, co to dělá:

for (...) vyžaduje za sebou buď jeden příkaz nebo blok příkazů obalený složenými závorkami {}.
V tomto případě je ten jediný příkaz definice a okamžité zavolání funkce:
(function(index) {...})(i)
To způsobí, že proměnná index bude mít stejnou hodnotu jako i v okamžiku jejího zavolání.
Tirus
Profil
Reaguji na juriada:
ahááá :) děkuji

Jinak dal jsem tam ten kod co si poslal a v tu chvíli mi přestalo fungovat drag&drop zona. do konzole to nevypise zadnou chybu
juriad
Profil
Ahá, já si nevšiml toho continue, ten samozřejmě musí zůstat mimo tu funkci.

                for (var i = 0, f; f = files; i++) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    reader = new FileReader();
                    (function(index) {
                        reader.onload = function(e) {
                            console.log(e);
                            document.getElementById('file_' + index).className = 'bg-success'; // zde mi to pise Uncaught TypeError: Cannot set property 'className' of null 
                            //coz mi prijde jako hloupost, protoze element s ID file_# tam je
                        };
                    })(i);
                    reader.readAsText(f)
                }
Tirus
Profil
Reaguji na juriada:
ok a to z jakého důvodu prosím?

Mohu do té funkce normálně dát ajax? tam bych dal odeslání toho souboru v base64 vc. nazvu souboru apod. na server a zpět bych si poslal snippet apod.. (z nette). ale to už zas musím nějak proštudovat :)
juriad
Profil
Z důvodu, že nemůžeš definovat funkci, která obsahuje continue bez smyčky.
var fn;

for (var i = 0; i < 10; i++) {
    // od této funkce chceme, aby přeskočila i == 5
    fn = function(i) {
        if (i == 5) {
            continue;
        }
    }
    fn(i); // při i == 5 bude continue
    alert(i); // vypíše všechna čísla kromě 5
}

fn(5); // a sakra :-)

Ano, v té funkci můžeš dělat cokoli, co neovlivňuje jazykové konstrukty mimo ní - tedy asi jen break a continue uvnitř for, while a switche. Asi tě napadne, že return uvnitř té funkce ukončí jen tu vnitřní aktuální funkci, nikoli tu vnější.
Tirus
Profil
Reaguji na juriada:
jo, super, tak to už i chápu :) Nedalo by se ten kod i napsat trochu hezčí? (jsem zvyklej na jQuery)
 function handleFileSelect(evt) {
                evt.stopPropagation();
                evt.preventDefault();

                var files = evt.dataTransfer.files; // FileList object.
                // files is a FileList of File objects. List some properties.
                var output = [];
                for (var i = 0, f; f = files[i]; i++) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    output.push('<li class="bg-info" id="file_' + i + '"><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                            f.size, ' bytes',
                            '</li>');
                }
                document.getElementById('list').innerHTML = '<ul class="files">' + output.join('') + '</ul>';
                for (var i = 0, f; f = files[i]; i++) {
                    if (!f.type.match('image.*')) {
                        continue;
                    }
                    (function(index) {
                        reader = new FileReader();
                        reader.onload = function(e) {
                            console.log(e);
                            document.getElementById('file_' + index).className = 'bg-success';
                            $('#file_' + index).fadeOut('slow');
                        };
                        reader.readAsText(f)
                    })(i);
                }

            }
            function handleDragOver(evt) {
                evt.stopPropagation();
                evt.preventDefault();
                evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
            }

            // Setup the dnd listeners.
            var dropZone = document.getElementById('drop_zone');
            dropZone.addEventListener('dragover', handleDragOver, false);
            dropZone.addEventListener('drop', handleFileSelect, false);
a toto je pro mne celkem španělská vesnice :) (ale nutnost to není).
Jen poslední věc. Jak zde mohu nějak sepsat ten upload jeden po druhém? to mám do toho onload?
Právě přemýšlím jak to zkomponovat s Nette Ajaxem abych mohl překreslovat ty snippety :( (dělám takovýhle elaborát prvně) - edit (na to napojení na Ajax se mi rýsuje odpověď [http://forum.nette.org/cs/20667-custom-ajax-request-a-invalidace])
juriad
Profil
Ano, můžeš to zkrátit. Řádky 21 až 29 můžeš přestěhovat do toho prvního foru.
Vůbec nevadí, že v té době ještě file_N neexistuje, protože reader.onload se může zavolat až teprve skončíš se zpracováním funkce handleFileSelect a to už ty elementy existovat budou.


Podívej se na tento example: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications#Handling_the_upload_process_for_a_file.2C_asynchronously
Jen prostě místo vytváření objektu XMLHttpRequest v sendFile použiješ něco jiného (nette ajax).
Tirus
Profil
Reaguji na juriada:
Takže říkáš něco jako.

                        reader.onload = function(e) {
                            console.log(e);
                            document.getElementById('file_' + index).className = 'bg-success';
                            $.nette.ajax({
                                type: "JSON",
                               url: url,
                               data: data
                           });
                        };

? ještě jen pár informací. Potřeboval bych věci jako je obsah souboru, nazev a velikost atd. Název a velikost už vím jak, ale nenašel jsem, jak získat ten obsah. Nebo mám posílat rovnou celej reader?
Tirus
Profil
Reaguji na juriada:
Tak jsem to sešmoulil :)

<script>
                function handleFileSelect(evt) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    console.log(evt);
                    if (evt.target.id == 'inputFiles') {
                        var files = evt.target.files; // FileList object.
                    } else {
                        var files = evt.dataTransfer.files; // FileList object.
                    }

                    console.log(files);
                    // files is a FileList of File objects. List some properties.
                    var output = [];
                    var maxSize = {$maxUpload};

                    for (var i = 0, f; f = files[i]; i++) {
                        if (!f.type.match('image.*')) {
                            continue;
                        }
                        var bigger = false;
                        if (f.size > maxSize) {
                            bigger = true;
                        }
                        var itemLi = '<li class="bg-';
                        if(bigger){
                            itemLi += 'danger';
                        }else{
                            itemLi += 'info';
                        }
                        itemLi += '" id="file_' + i + '"><strong>'+ escape(f.name)+ '</strong> ('+  f.type + ') - '+f.size+ ' bytes'+'</li>';
                        output.push(itemLi);
                        if (bigger) {
                            continue;
                        }
                        (function(index, fi) {
                            reader = new FileReader();
                            reader.onload = function(e) {
                                console.log(e);
                                
                                $.nette.ext("unique", null);
                                $.nette.ajax({
                                    type: 'POST',
                                    url: {link upload!},
                                    data: {
                                        file: e.target.result,
                                        fileType: fi.type,
                                        fileName: fi.name,
                                        fileSize: fi.size
                                    },
                                    success: function(data, status, xhr) {
                                        document.getElementById('file_' + index).className = 'bg-success';
                                        $('#file_' + index).fadeOut('slow');
                                    },
                                    error: function(){
                                        document.getElementById('file_' + index).className = 'bg-danger';
                                    }
                                });
                                
                            };
                            reader.readAsDataURL(f)
                        })(i, f);
                    }
                    document.getElementById('list').innerHTML = '<ul class="files">' + output.join('') + '</ul>';
                }
                function handleDragOver(evt) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
                }

                // Setup the dnd listeners.
                document.getElementById('inputFiles').addEventListener('change', handleFileSelect, false);
                var dropZone = document.getElementById('drop_zone');
                dropZone.addEventListener('dragover', handleDragOver, false);
                dropZone.addEventListener('drop', handleFileSelect, false);
            </script>

Pro info počítá to s nette a pár věcma, ale to si každý může sám upravit. Jen se optám, je nějaká možnost jak to ještě upravit aby to fungovalo tak, že se soubory budou zasílat posobě? teď to funguje tak, že se vše odešle najednou :(
Tirus
Profil
Reaguji na juriada:

nešlo by to udělat nějak aby to nenačítalo celej seznam do paměti a pak odesílal, ale aby to odesílalo rovnou jeden soubor po druhém?

<script>
                function handleFileSelect(evt) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    if (evt.target.id == 'inputFiles') {
                        var files = evt.target.files; // FileList object.
                    } else {
                        var files = evt.dataTransfer.files; // FileList object.
                    }

                    // files is a FileList of File objects. List some properties.
                    var output = [];
                    var maxSize = {$maxUpload};

                    for (var i = 0, f; f = files[i]; i++) {
                        if (!f.type.match('image.*')) {
                            continue;
                        }
                        var bigger = false;
                        if (f.size > maxSize) {
                            bigger = true;
                        }
                        var itemLi = '<li class="bg-';
                        if (bigger) {
                            itemLi += 'danger';
                        } else {
                            itemLi += 'info';
                        }
                        itemLi += '" id="file_' + i + '"><strong>' + escape(f.name) + '</strong> (' + f.type + ') - ' + f.size + ' bytes' + '</li>';
                        output.push(itemLi);
                        if (bigger) {
                            continue;
                        }
                        $.xhrPool = [];

                        $.xhrPool.abortAll = function() {
                            $.each(this, function(jqXHR) {
                                jqXHR.abort();
                            });
                        };

                        $.ajaxSetup({
                            beforeSend: function(jqXHR) {
                                $.xhrPool.push(jqXHR);
                            }
                        });
                        (function(index, fi) {
                            reader = new FileReader();
                            reader.onload = function(e) {
                                $.nette.ext("unique", null);
                                $.nette.ajax({
                                    type: 'POST',
                                    url: {link upload!},
                                    data: {
                                        file: e.target.result,
                                        fileType: fi.type,
                                        fileName: fi.name,
                                        fileSize: fi.size,
                                    },
                                    success: function(data, status, xhr) {
                                        if (data.redirect) {
                                            $.xhrPool.abortAll();
                                            window.location.assign(data.redirect);
                                        }

                                        document.getElementById('file_' + index).className = 'bg-success';
                                        $('#file_' + index).fadeOut('slow');
                                    },
                                    error: function(jqXHR, textStatus, errorThrown) {
                                        console.log(textStatus, errorThrown);
                                    }
                                });

                            };
                            reader.readAsDataURL(f)
                        })(i, f);
                    }
                    document.getElementById('list').innerHTML = '<ul class="files">' + output.join('') + '</ul>';
                }
                function handleDragOver(evt) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
                }

                // Setup the dnd listeners.
                document.getElementById('inputFiles').addEventListener('change', handleFileSelect, false);
                var dropZone = document.getElementById('drop_zone');
                dropZone.addEventListener('dragover', handleDragOver, false);
                dropZone.addEventListener('drop', handleFileSelect, false);
            </script>

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0