Integrazione di Dropzone.js nel modulo HTML esistente con altri campi


181

Al momento ho un modulo HTML che gli utenti compilano i dettagli di un annuncio che desiderano pubblicare. Ora voglio essere in grado di aggiungere un dropzone per il caricamento di immagini dell'articolo in vendita.

Ho trovato Dropzone.js che sembra fare la maggior parte di ciò di cui ho bisogno. Tuttavia, quando si esamina la documentazione, sembra che sia necessario specificare la classe dell'intero modulo come dropzone(anziché solo l' elemento di input ). Ciò significa quindi che la mia intera forma diventa la dropzone .

È possibile utilizzare il dropzone solo in una parte del mio modulo, ovvero specificando l'elemento come classe "dropzone" , piuttosto che l'intero modulo?

Potrei usare moduli separati, ma voglio che l'utente sia in grado di inviare tutto con un solo pulsante.

In alternativa, c'è un'altra libreria che può farlo?

Grazie molto

Risposte:


59

Ecco un altro modo per farlo: aggiungi un divnel tuo modulo con un dropzone di nome classe e implementa dropzone a livello di codice.

HTML:

<div id="dZUpload" class="dropzone">
      <div class="dz-default dz-message"></div>
</div>

JQuery:

$(document).ready(function () {
    Dropzone.autoDiscover = false;
    $("#dZUpload").dropzone({
        url: "hn_SimpeFileUploader.ashx",
        addRemoveLinks: true,
        success: function (file, response) {
            var imgName = response;
            file.previewElement.classList.add("dz-success");
            console.log("Successfully uploaded :" + imgName);
        },
        error: function (file, response) {
            file.previewElement.classList.add("dz-error");
        }
    });
});

Nota: disabilitare AutoDiscover, altrimenti Dropzone proverà a collegarsi due volte

Articolo Blog : Dropzone js + Asp.net: un modo semplice per caricare immagini in blocco


25
Con ciò, non può usare il pulsante di invio predefinito, non risponde alla sua domanda
Clemente

5
ma questo non utilizza ancora il modulo originale per l'invio
dangel

3
questo era il mio problema e l'hai risolto, ty @Satindersingh
Su4p

1
@ Su4p: sono contento che ti aiuti, inoltre puoi controllare il link dell'articolo del blog per la spiegazione dei dettagli insieme all'opzione di ridimensionamento dell'immagine durante il caricamento
Satinder singh

2
Ciò ha aiutato molto, è possibile impostare qualsiasi elemento come dropzone se si imposta manualmente l'URL. Ho usato il gestore del successo per pubblicare il nome file in un campo nascosto / disabilitato nella forma principale.
DigitalDesignDj

40

Ho avuto lo stesso identico problema e ho scoperto che la risposta di Varan Sinayee era l'unica a risolvere effettivamente la domanda originale. Questa risposta può essere semplificata, quindi ecco una versione più semplice.

I passaggi sono:

  1. Crea un modulo normale (non dimenticare il metodo e l'enctype args poiché questo non è più gestito da dropzone).

  2. Inserisci un div all'interno con class="dropzone"(è così che Dropzone si collega ad esso) e id="yourDropzoneName"(usato per cambiare le opzioni).

  3. Imposta le opzioni di Dropzone, per impostare l'URL in cui verranno inseriti il ​​modulo e i file, disattivare autoProcessQueue (quindi succede solo quando l'utente preme 'invia') e consentire caricamenti multipli (se ne hai bisogno).

  4. Impostare la funzione init per utilizzare Dropzone invece del comportamento predefinito quando si fa clic sul pulsante di invio.

  5. Sempre nella funzione init, utilizzare il gestore eventi "sendmultiple" per inviare i dati del modulo insieme ai file.

Ecco ! Ora puoi recuperare i dati come faresti con un modulo normale, in $ _POST e $ _FILES (nell'esempio ciò accadrebbe in upload.php)

HTML

<form action="upload.php" enctype="multipart/form-data" method="POST">
    <input type="text" id ="firstname" name ="firstname" />
    <input type="text" id ="lastname" name ="lastname" />
    <div class="dropzone" id="myDropzone"></div>
    <button type="submit" id="submit-all"> upload </button>
</form>

JS

Dropzone.options.myDropzone= {
    url: 'upload.php',
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 5,
    maxFiles: 5,
    maxFilesize: 1,
    acceptedFiles: 'image/*',
    addRemoveLinks: true,
    init: function() {
        dzClosure = this; // Makes sure that 'this' is understood inside the functions below.

        // for Dropzone to process the queue (instead of default form behavior):
        document.getElementById("submit-all").addEventListener("click", function(e) {
            // Make sure that the form isn't actually being sent.
            e.preventDefault();
            e.stopPropagation();
            dzClosure.processQueue();
        });

        //send all the form data along with the files:
        this.on("sendingmultiple", function(data, xhr, formData) {
            formData.append("firstname", jQuery("#firstname").val());
            formData.append("lastname", jQuery("#lastname").val());
        });
    }
}

1
Questa soluzione è valida e funziona, ma non reindirizza più alla pagina successiva, a causa della prevenzione del comportamento di invio predefinito.
Felix G.,

@TIIUNDER - è pronto per l'invio di informazioni sul modulo tramite chiamata ajax senza ricaricare la pagina - ecco perché c'è e.preventDefault ();
born2fr4g

1
@TIUNDER puoi aggiungere il reindirizzamento in caso di successo
doflamingo il

È possibile inviare il modulo dopo la processQueue()chiamata? Provo a usare submit()o click(), entrambi non funzionano.
Grey Li

1
+1 Questa sembra essere l'unica soluzione funzionante. Invece di fare formData.appendersi uno per uno, puoi anche farlo $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (mi dispiace non so come mettere le interruzioni di riga qui)
Aximili

20

"Dropzone.js" è la libreria più comune per il caricamento di immagini. Se si desidera che "dropzone.js" sia solo una parte del modulo, è necessario effettuare le seguenti operazioni:

1) per il lato client:

HTML:

    <form action="/" enctype="multipart/form-data" method="POST">
        <input type="text" id ="Username" name ="Username" />
        <div class="dropzone" id="my-dropzone" name="mainFileUploader">
            <div class="fallback">
                <input name="file" type="file" multiple />
            </div>
        </div>
    </form>
    <div>
        <button type="submit" id="submit-all"> upload </button>
    </div>

JQuery:

    <script>
        Dropzone.options.myDropzone = {
            url: "/Account/Create",
            autoProcessQueue: false,
            uploadMultiple: true,
            parallelUploads: 100,
            maxFiles: 100,
            acceptedFiles: "image/*",

            init: function () {

                var submitButton = document.querySelector("#submit-all");
                var wrapperThis = this;

                submitButton.addEventListener("click", function () {
                    wrapperThis.processQueue();
                });

                this.on("addedfile", function (file) {

                    // Create the remove button
                    var removeButton = Dropzone.createElement("<button class='btn btn-lg dark'>Remove File</button>");

                    // Listen to the click event
                    removeButton.addEventListener("click", function (e) {
                        // Make sure the button click doesn't submit the form:
                        e.preventDefault();
                        e.stopPropagation();

                        // Remove the file preview.
                        wrapperThis.removeFile(file);
                        // If you want to the delete the file on the server as well,
                        // you can do the AJAX request here.
                    });

                    // Add the button to the file preview element.
                    file.previewElement.appendChild(removeButton);
                });

                this.on('sendingmultiple', function (data, xhr, formData) {
                    formData.append("Username", $("#Username").val());
                });
            }
        };
    </script>

2) per il lato server:

ASP.Net MVC

    [HttpPost]
    public ActionResult Create()
    {
        var postedUsername = Request.Form["Username"].ToString();
        foreach (var imageFile in Request.Files)
        {

        }

        return Json(new { status = true, Message = "Account created." });
    }

2
Grazie per il post! Risolto il mio problema Un'altra domanda veloce, questo non funziona quando nessuna immagine selezionata (da caricare), come risolverlo?
Sato

A proposito: se si utilizza l'azione del controller con associazione del modello e si invia il modulo in questo modo, il modello sarà vuoto. Per qualche motivo questo metodo non associa i dati effettivi al modello.
Edward Chopuryan,

1
quando autoProcessQueue = false non vengono generati eventi
cyril

@Sato su clic del pulsante di invio è possibile verificare la lunghezza dei file accettati su dropzone utilizzando galleryfile.getAcceptedFiles (). Length e se non è stato caricato alcun file è necessario inviare il modulo.
Varan Sinayee,

@EdwardChopuryan Questo non è correlato al metodo di invio dei dati per dropzone. Probabilmente il problema è nella "convenzione di denominazione" dei tag di input sulla piattaforma come ASP.Net MVC.
Varan Sinayee,

11

Il tutorial di Enyo è eccellente.

Ho scoperto che lo script di esempio nel tutorial ha funzionato bene per un pulsante incorporato nel dropzone (cioè l'elemento del modulo). Se desideri avere il pulsante all'esterno dell'elemento del modulo, sono stato in grado di realizzarlo utilizzando un evento click:

Innanzitutto, l'HTML:

<form id="my-awesome-dropzone" action="/upload" class="dropzone">  
    <div class="dropzone-previews"></div>
    <div class="fallback"> <!-- this is the fallback if JS isn't working -->
        <input name="file" type="file" multiple />
    </div>

</form>
<button type="submit" id="submit-all" class="btn btn-primary btn-xs">Upload the file</button>

Quindi, il tag script ....

Dropzone.options.myAwesomeDropzone = { // The camelized version of the ID of the form element

    // The configuration we've talked about above
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 25,
    maxFiles: 25,

    // The setting up of the dropzone
    init: function() {
        var myDropzone = this;

        // Here's the change from enyo's tutorial...

        $("#submit-all").click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            myDropzone.processQueue();
        }); 
    }
}

23
Non è possibile avere un modulo all'interno di un modulo e inviare.
Paolo

1
Quando provo questo, il contenitore delle anteprime dropzone sembra essere ignorato. Dropzone aggiunge solo le anteprime in fondo al modulo. Dovrai aggiungere "anteprimeContainer:" .dropzone-anteprime "," alla tua configurazione.
Aaron Hill il

6
Questo non risponde alla domanda originale. La domanda originale era come utilizzare Dropzone con un modulo esistente, non sulla posizione del pulsante per attivare l'azione.
CSSian,

7

Oltre a ciò che stava dicendo sqram, Dropzone ha un'opzione aggiuntiva non documentata, "hiddenInputContainer". Tutto quello che devi fare è impostare questa opzione sul selettore del modulo a cui desideri aggiungere il campo file nascosto. E voilà! Il campo file ".dz-hidden-input" che Dropzone normalmente aggiunge al corpo si sposta magicamente nella tua forma. Nessuna modifica del codice sorgente di Dropzone.

Ora, mentre questo funziona per spostare il campo del file Dropzone nel modulo, il campo non ha nome. Quindi dovrai aggiungere:

_this.hiddenFileInput.setAttribute("name", "field_name[]");

a dropzone.js dopo questa riga:

_this.hiddenFileInput = document.createElement("input");

intorno alla linea 547.


5

Ho una soluzione più automatizzata per questo.

HTML:

<form role="form" enctype="multipart/form-data" action="{{ $url }}" method="{{ $method }}">
    {{ csrf_field() }}

    <!-- You can add extra form fields here -->

    <input hidden id="file" name="file"/>

    <!-- You can add extra form fields here -->

    <div class="dropzone dropzone-file-area" id="fileUpload">
        <div class="dz-default dz-message">
            <h3 class="sbold">Drop files here to upload</h3>
            <span>You can also click to open file browser</span>
        </div>
    </div>

    <!-- You can add extra form fields here -->

    <button type="submit">Submit</button>
</form>

JavaScript:

Dropzone.options.fileUpload = {
    url: 'blackHole.php',
    addRemoveLinks: true,
    accept: function(file) {
        let fileReader = new FileReader();

        fileReader.readAsDataURL(file);
        fileReader.onloadend = function() {

            let content = fileReader.result;
            $('#file').val(content);
            file.previewElement.classList.add("dz-success");
        }
        file.previewElement.classList.add("dz-complete");
    }
}

laravel:

// Get file content
$file = base64_decode(request('file'));

Non è necessario disabilitare DropZone Discovery e l'invio del modulo normale sarà in grado di inviare il file con qualsiasi altro campo del modulo tramite la serializzazione del modulo standard.

Questo meccanismo memorizza il contenuto del file come stringa base64 nel campo di input nascosto quando viene elaborato. Puoi decodificarlo in stringa binaria in PHP tramite il base64_decode()metodo standard .

Non so se questo metodo verrà compromesso con file di grandi dimensioni, ma funziona con file di ~ 40 MB.


Come decodifichi ed elabori i dati da altri campi che verranno inviati insieme alle immagini?
sam,

@sam Non è necessario decodificare gli altri campi. In primo luogo non vengono codificati, ma solo il file viene codificato.
Umair Ahmed,

Puoi condividere qualche codice di esempio per html, javascript e come recuperare in laravel php.
sam

2
Se vuoi aggiungere immagini multiple devi rimuovere l'input del file html e aggiungerlo quing js per ogni immagine $ ('# fileUpload'). Append ('<input hidden name = "files []" value =' + content + ' /> ') dove contenuto è l'immagine codificata in base64.
AleXzpm,

1
@codepushr bene è una vecchia risposta del tempo che non stavamo prendendo in considerazione soluzioni a pagamento. Ora abbiamo acquistato FileUploader, sebbene abbia i suoi shenanigans ma basti dire che può essere personalizzato per fare praticamente qualsiasi cosa.
Umair Ahmed,

4

È possibile modificare il formData catturando l'evento "invio" dal proprio dropzone.

dropZone.on('sending', function(data, xhr, formData){
        formData.append('fieldname', 'value');
});

1
Mi piace questa risposta, ma presumo che il nome campo e il valore siano stati popolati. Questo viene attivato durante il caricamento che può verificarsi in un momento separato per l'invio del modulo. In altre parole, non si può presumere che quando si invia l'immagine il modulo sia compilato.
Antony,

4

Per inviare tutti i file insieme ad altri dati del modulo in una singola richiesta, è possibile copiare i inputnodi nascosti temporanei Dropzone.js nel modulo. Puoi farlo all'interno del addedfilesgestore eventi:

var myDropzone = new Dropzone("myDivSelector", { url: "#", autoProcessQueue: false });
myDropzone.on("addedfiles", () => {
  // Input node with selected files. It will be removed from document shortly in order to
  // give user ability to choose another set of files.
  var usedInput = myDropzone.hiddenFileInput;
  // Append it to form after stack become empty, because if you append it earlier
  // it will be removed from its parent node by Dropzone.js.
  setTimeout(() => {
    // myForm - is form node that you want to submit.
    myForm.appendChild(usedInput);
    // Set some unique name in order to submit data.
    usedInput.name = "foo";
  }, 0);
});

Ovviamente si tratta di una soluzione alternativa che dipende dai dettagli di implementazione. Relativo codice sorgente .


Fondamentalmente ho usato questo approccio, ma a causa di evidenti ritardi nell'elaborazione, alla fine ho collegato l'elaborazione del contenuto del file nell'ambito myDropzone.on("thumbnail", () => {})dell'evento. L'elaborazione immediata sul "addedFile"file potrebbe essere ancora undefinedin corso l'accesso.
Matti,

Sto cercando di utilizzare questo e funziona nel portare il campo di input del file nascosto nel modulo e quando invio, i dati di post mostrano il mio campo files[]ma è vuoto, qualunque cosa io faccia. Qualche idea? Farlo in Laravel se fa la differenza.
Zen,

Ciao! Perché il file selezionato viene caricato ma se il file viene eliminato, non (errore 4)?
Ingus l'

2

Voglio dare una risposta qui perché anch'io ho affrontato lo stesso problema: vogliamo l'elemento $ _FILES disponibile come parte dello stesso post di un altro modulo. La mia risposta si basa su @mrtnmgs, tuttavia nota i commenti aggiunti a quella domanda.

Primo: Dropzone pubblica i suoi dati tramite ajax

Solo perché si utilizza l' formData.appendopzione significa comunque che è necessario affrontare le azioni UX, ovvero tutto ciò accade dietro le quinte e non è un tipico post di modulo. I dati vengono inviati al tuourl parametro.

In secondo luogo: se si desidera quindi imitare un post di un modulo, è necessario archiviare i dati pubblicati

Ciò richiede il codice lato server per memorizzare il tuo $_POSTo$_FILES in una sessione che è disponibile per l'utente su un altro caricamento della pagina poiché l'utente non andrà alla pagina in cui vengono ricevuti i dati pubblicati.

Terzo: è necessario reindirizzare l'utente alla pagina in cui vengono utilizzati questi dati

Ora hai pubblicato i tuoi dati, archiviati in una sessione, devi visualizzarli / agire per l'utente in una pagina aggiuntiva. Devi inviare anche l'utente a quella pagina.

Quindi per il mio esempio:

[Codice Dropzone: utilizza Jquery]

$('#dropArea').dropzone({
    url:        base_url+'admin/saveProject',
    maxFiles:   1,
    uploadMultiple: false,
    autoProcessQueue:false,
    addRemoveLinks: true,
    init:       function(){
        dzClosure = this;

        $('#projectActionBtn').on('click',function(e) {
            dzClosure.processQueue(); /* My button isn't a submit */
        });

        // My project only has 1 file hence not sendingmultiple
        dzClosure.on('sending', function(data, xhr, formData) {
            $('#add_user input[type="text"],#add_user textarea').each(function(){
                formData.append($(this).attr('name'),$(this).val());
            })
        });

        dzClosure.on('complete',function(){
            window.location.href = base_url+'admin/saveProject';
        })
    },
});

1

Questo è solo un altro esempio di come è possibile utilizzare Dropzone.js in un modulo esistente.

dropzone.js:

 init: function() {

   this.on("success", function(file, responseText) {
     //alert("HELLO ?" + responseText); 
     mylittlefix(responseText);
   });

   return noop;
 },

Quindi, più avanti nel file che ho inserito

function mylittlefix(responseText) {
  $('#botofform').append('<input type="hidden" name="files[]" value="'+ responseText +'">');
}

Ciò presuppone che tu abbia un div con ID in #botofformquel modo durante il caricamento puoi usare i nomi dei file caricati.

Nota: il mio script di caricamento ha restituito il doppiaggio del file scaricato.jpeg. Dovresti anche creare uno script di pulizia che controlla la directory di caricamento per i file non in uso e li elimina .. se in un front-end non autenticato :)


Questo non invia immagini di dropzone insieme ad altri campi del modulo. Quello che stai facendo è caricare normalmente le immagini, salvare i nomi delle immagini e quindi reinviare il resto dei campi del modulo con i nomi delle immagini.
Zen,

1

Ecco il mio esempio, è basato su Django + Dropzone. Visualizza ha selezionato (richiesto) e invia.

<form action="/share/upload/" class="dropzone" id="uploadDropzone">
    {% csrf_token %}
        <select id="warehouse" required>
            <option value="">Select a warehouse</option>
                {% for warehouse in warehouses %}
                    <option value={{forloop.counter0}}>{{warehouse.warehousename}}</option>
                {% endfor %}
        </select>
    <button id="submit-upload btn" type="submit">upload</button>
</form>

<script src="{% static '/js/libs/dropzone/dropzone.js' %}"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script>
    var filename = "";

    Dropzone.options.uploadDropzone = {
        paramName: "file",  // The name that will be used to transfer the file,
        maxFilesize: 250,   // MB
        autoProcessQueue: false,
        accept: function(file, done) {
            console.log(file.name);
            filename = file.name;
            done();    // !Very important
        },
        init: function() {
            var myDropzone = this,
            submitButton = document.querySelector("[type=submit]");

            submitButton.addEventListener('click', function(e) {
                var isValid = document.querySelector('#warehouse').reportValidity();
                e.preventDefault();
                e.stopPropagation();
                if (isValid)
                    myDropzone.processQueue();
            });

            this.on('sendingmultiple', function(data, xhr, formData) {
                formData.append("warehouse", jQuery("#warehouse option:selected").val());
            });
        }
    };
</script>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.