Integrieren von Dropzone.js in vorhandene HTML-Formulare mit anderen Feldern


179

Ich habe derzeit ein HTML-Formular, in das Benutzer Details einer Anzeige eintragen, die sie veröffentlichen möchten. Ich möchte jetzt eine Dropzone hinzufügen können zum Hochladen von Bildern des zum Verkauf stehenden Artikels .

Ich habe Dropzone.js gefunden, das das meiste zu tun scheint, was ich brauche. Wenn Sie sich die Dokumentation ansehen, müssen Sie jedoch die Klasse des gesamten Formulars als angeben dropzone(im Gegensatz nur zum Eingabeelement ). Dies bedeutet dann, dass meine gesamte Form zur Dropzone wird .

Ist es möglich, die Dropzone nur in einem Teil meines Formulars zu verwenden, dh indem Sie das Element nur als Klasse "Dropzone" und nicht als das gesamte Formular angeben ?

Ich könnte separate Formulare verwenden, aber ich möchte, dass der Benutzer alles mit einer Schaltfläche senden kann.

Gibt es alternativ eine andere Bibliothek, die dies tun kann?

Danke vielmals

Antworten:


58

Hier ist eine andere Möglichkeit: divFügen Sie in Ihrem Formular eine Dropzone mit dem Klassennamen dropzone hinzu und implementieren Sie dropzone programmgesteuert.

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

Hinweis: Deaktivieren Sie autoDiscover. Andernfalls versucht Dropzone zweimal, eine Verbindung herzustellen

Blog-Artikel : Dropzone js + Asp.net: Einfache Möglichkeit, Massenbilder hochzuladen


24
Damit kann er den Standard-Submit-Button nicht verwenden, er antwortet nicht auf seine Frage
Clement

5
aber dies verwendet immer noch nicht das Originalformular, um einzureichen
Dangel

3
Dies war mein Problem und Sie haben es gelöst, ty @Satindersingh
Su4p

1
@ Su4p: Ich bin froh, dass es Ihnen hilft, auch können Sie den Link zum Blog-Artikel überprüfen, um Details zu
erfahren und die

2
Dies hat sehr geholfen. Sie können jedes Element als Dropzone einrichten, wenn Sie die URL manuell einrichten. Ich habe den Erfolgshandler verwendet, um den Dateinamen in einem ausgeblendeten / deaktivierten Feld im primären Formular zu veröffentlichen.
DigitalDesignDj

40

Ich hatte genau das gleiche Problem und stellte fest, dass Varan Sinayees Antwort die einzige war, die die ursprüngliche Frage tatsächlich löste. Diese Antwort kann jedoch vereinfacht werden. Hier ist eine einfachere Version.

Die Schritte sind:

  1. Erstellen Sie ein normales Formular (vergessen Sie nicht die Methoden- und Enctype-Argumente, da dies nicht mehr von dropzone behandelt wird).

  2. Fügen Sie ein div mit dem class="dropzone"(so hängt Dropzone es an) und id="yourDropzoneName"(wird zum Ändern der Optionen verwendet) ein.

  3. Legen Sie die Dropzone-Optionen fest, um die URL festzulegen, unter der das Formular und die Dateien veröffentlicht werden sollen, deaktivieren Sie autoProcessQueue (dies geschieht nur, wenn der Benutzer auf "Senden" drückt) und lassen Sie mehrere Uploads zu (falls erforderlich).

  4. Stellen Sie die Init-Funktion so ein, dass Dropzone anstelle des Standardverhaltens verwendet wird, wenn Sie auf die Schaltfläche "Senden" klicken.

  5. Verwenden Sie noch in der Init-Funktion den Ereignishandler "sendmultiple", um die Formulardaten zusammen mit den Dateien zu senden.

Voilà! Sie können die Daten jetzt wie in einem normalen Formular in $ _POST und $ _FILES abrufen (im Beispiel würde dies in upload.php passieren).

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
Diese Lösung ist nett und funktioniert, leitet jedoch nicht mehr zur nächsten Seite weiter, da das Standardübermittlungsverhalten verhindert wird.
Felix G.

@TIIUNDER - es ist für das Senden von Formularinformationen per Ajax-Aufruf ohne erneutes Laden der Seite vorbereitet - deshalb gibt es e.preventDefault ();
born2fr4g

1
@TIUNDER Sie können Weiterleitung im Erfolgsereignis hinzufügen
doflamingo

Ist es möglich, das Formular nach dem processQueue()Anruf einzureichen ? Ich versuche zu verwenden submit()oder click()beide funktionieren nicht.
Gray Li

1
+1 Dies scheint die einzige funktionierende Lösung zu sein. Anstatt formData.append einzeln auszuführen, können Sie dies auch tun $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (Entschuldigung, ich weiß nicht, wie ich Zeilenumbrüche hier
einfügen

20

Die "dropzone.js" ist die häufigste Bibliothek zum Hochladen von Bildern. Wenn Sie die "dropzone.js" nur als Teil Ihres Formulars haben möchten, sollten Sie die folgenden Schritte ausführen:

1) für den Kunden:

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) für die Serverseite:

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
Danke für den Beitrag! Mein Problem gelöst. Eine weitere kurze Frage: Dies funktioniert nicht, wenn keine Bilder ausgewählt wurden (zum Hochladen). Wie kann dies behoben werden?
Sato

Übrigens: Wenn Sie die Controller-Aktion mit Modellbindung verwenden und Ihr Formular wie folgt senden, ist das Modell leer. Aus irgendeinem Grund bindet diese Methode die tatsächlichen Daten nicht an das Modell.
Edward Chopuryan

1
Wenn autoProcessQueue = false, werden keine Ereignisse ausgelöst
Cyril

@Sato beim Klicken auf das Ereignis des Senden-Buttons können Sie die Länge der akzeptierten Dateien in der Dropzone mithilfe von galleryfile.getAcceptedFiles (). Length überprüfen. Wenn keine Datei hochgeladen wurde, sollten Sie Ihr Formular senden.
Varan Sinayee

@EdwardChopuryan Dies hängt nicht mit der Methode zum Übermitteln von Daten per Dropzone zusammen. Wahrscheinlich liegt das Problem in Ihrer "Namenskonvention" für Eingabe-Tags auf Ihrer Plattform wie ASP.Net MVC.
Varan Sinayee

11

Enyos Tutorial ist ausgezeichnet.

Ich fand, dass das Beispielskript im Tutorial für eine in die Dropzone eingebettete Schaltfläche (dh das Formularelement) gut funktioniert. Wenn Sie die Schaltfläche außerhalb des Formularelements haben möchten, konnte ich dies mithilfe eines Klickereignisses erreichen:

Erstens das 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>

Dann das Skript-Tag ....

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
Sie können kein Formular in einem Formular haben und senden.
Paul

1
Wenn ich das versuche, scheint der Dropzone-Vorschau-Container ignoriert zu werden. Dropzone fügt nur die Vorschau am unteren Rand des Formulars hinzu. Sie müssen Ihrer Vorschau 'PreviewsContainer:' .dropzone-Previews 'hinzufügen.
Aaron Hill

6
Dies beantwortet nicht die ursprüngliche Frage. Die ursprüngliche Frage war, wie Dropzone mit einem vorhandenen Formular verwendet werden soll, nicht die Position der Schaltfläche zum Auslösen der Aktion.
CSSian

7

Zusätzlich zu den Aussagen von sqram verfügt Dropzone über eine zusätzliche undokumentierte Option, "hiddenInputContainer". Sie müssen diese Option lediglich auf die Auswahl des Formulars setzen, an das das ausgeblendete Dateifeld angehängt werden soll. Und voila! Das Dateifeld ".dz-hidden-input", das Dropzone normalerweise dem Körper hinzufügt, wird auf magische Weise in Ihr Formular verschoben. Keine Änderung des Dropzone-Quellcodes.

Während dies funktioniert, um das Dropzone-Dateifeld in Ihr Formular zu verschieben, hat das Feld keinen Namen. Sie müssen also hinzufügen:

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

zu dropzone.js nach dieser Zeile:

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

um die Linie 547.


5

Ich habe eine automatisiertere Lösung dafür.

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

DropZone Discovery muss nicht deaktiviert werden, und die normale Formularübermittlung kann die Datei mit anderen Formularfeldern über die Standardformularserialisierung senden.

Dieser Mechanismus speichert den Dateiinhalt als base64-Zeichenfolge im ausgeblendeten Eingabefeld, wenn er verarbeitet wird. Sie können es in PHP mit der Standardmethode wieder in eine Binärzeichenfolge dekodieren base64_decode().

Ich weiß nicht, ob diese Methode bei großen Dateien beeinträchtigt wird, aber sie funktioniert mit ~ 40 MB-Dateien.


Wie dekodieren und verarbeiten Sie Daten aus anderen Feldern, die zusammen mit den Bildern übermittelt werden?
Sam

@sam Die anderen Felder müssen nicht dekodiert werden. Sie werden nicht erst verschlüsselt, sondern nur die Datei.
Umair Ahmed

Können Sie einen Beispielcode für HTML, Javascript und das Abrufen in Laravel PHP teilen?
Sam

1
Wenn Sie mehrere Bilder hinzufügen möchten, müssen Sie die HTML-Dateieingabe entfernen und sie für jedes Bild hinzufügen. $ ('# FileUpload'). Append ('<input hidden name = "files []" value =' + content + ' /> ') wobei Inhalt das base64-codierte Bild ist.
AleXzpm

1
@codepushr Nun, es ist eine alte Antwort der Zeit, als wir nicht über bezahlte Lösungen nachdachten. Jetzt haben wir FileUploader gekauft, obwohl es seine eigenen Spielereien hat, aber es reicht zu sagen, dass es für fast alles angepasst werden kann.
Umair Ahmed

4

Sie können die formData ändern, indem Sie das Ereignis "Senden" aus Ihrer Dropzone abfangen.

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

1
Ich mag diese Antwort - aber es würde voraussetzen, dass Feldname und Wert ausgefüllt wurden. Dies wird beim Upload ausgelöst, der zu einem anderen Zeitpunkt als das Senden des Formulars erfolgen kann. Mit anderen Worten, Sie können nicht davon ausgehen, dass das Formular beim Senden des Bildes ausgefüllt wird.
Antony

4

Um alle Dateien zusammen mit anderen Formulardaten in einer einzigen Anfrage zu senden, können Sie die temporären versteckten inputKnoten von Dropzone.j in Ihr Formular kopieren . Sie können dies im addedfilesEvent-Handler tun :

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

Dies ist offensichtlich eine Problemumgehung, die von den Implementierungsdetails abhängt. Zugehöriger Quellcode .


Grundsätzlich habe ich diesen Ansatz verwendet, aber aufgrund offensichtlicher Verarbeitungsverzögerungen habe ich am Ende die Verarbeitung des Dateiinhalts unter dem myDropzone.on("thumbnail", () => {})Ereignis angeschlossen. Die sofortige Verarbeitung "addedFile"der Datei erfolgt möglicherweise noch undefinedbeim Zugriff.
Matti

Ich versuche dies zu verwenden und es funktioniert, um das Eingabefeld für versteckte Dateien in das Formular zu bringen. Wenn ich es sende, zeigen die Post-Daten mein Feld an, files[]aber es ist leer, egal was ich tue. Irgendwelche Ideen? Mach es in Laravel, wenn es einen Unterschied macht.
Zen

Hallo! Warum wird die ausgewählte Datei hochgeladen, aber wenn die Datei gelöscht wird, nicht (Fehler 4)?
Ingus

2

Ich möchte hier eine Antwort einbringen, da auch ich mit demselben Problem konfrontiert bin. Wir möchten, dass das Element $ _FILES als Teil desselben Beitrags wie ein anderes Formular verfügbar ist. Meine Antwort basiert auf @mrtnmgs, bemerkt jedoch die Kommentare, die zu dieser Frage hinzugefügt wurden.

Erstens: Dropzone veröffentlicht seine Daten über Ajax

Nur weil Sie die formData.appendOption verwenden, bedeutet dies immer noch, dass Sie die UX-Aktionen angehen müssen - dh dies geschieht alles hinter den Kulissen und ist kein typischer Formularbeitrag. Daten werden in Ihren urlParameter gebucht .

Zweitens: Wenn Sie daher einen Formularbeitrag nachahmen möchten, müssen Sie die veröffentlichten Daten speichern

Dies erfordert serverseitigen Code zum Speichern Ihrer $_POSToder $_FILESeiner Sitzung, die dem Benutzer auf einer anderen Seite zur Verfügung steht, da der Benutzer nicht zu der Seite wechselt, auf der die veröffentlichten Daten empfangen werden.

Drittens: Sie müssen den Benutzer auf die Seite umleiten, auf der diese Daten verarbeitet werden

Nachdem Sie Ihre Daten veröffentlicht und in einer Sitzung gespeichert haben, müssen Sie sie für den Benutzer auf einer zusätzlichen Seite anzeigen / bearbeiten. Sie müssen den Benutzer auch auf diese Seite senden.

Also für mein Beispiel:

[Dropzone-Code: Verwendet 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

Dies ist nur ein weiteres Beispiel dafür, wie Sie Dropzone.js in einem vorhandenen Formular verwenden können.

dropzone.js:

 init: function() {

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

   return noop;
 },

Dann, später in die Datei, die ich eingefügt habe

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

Dies setzt voraus, dass Sie ein Div mit einer ID haben. Auf #botofformdiese Weise können Sie beim Hochladen die Namen der hochgeladenen Dateien verwenden.

Hinweis: Mein Upload-Skript hat die hochgeladene Dateiname.jpeg-Dubblenote zurückgegeben. Außerdem müssten Sie ein Bereinigungsskript erstellen, das das Upload-Verzeichnis auf nicht verwendete Dateien überprüft und diese löscht ..if in einer nicht authentifizierten Front-End-Form :)


Dadurch werden keine Dropzone-Bilder zusammen mit anderen Formularfeldern gesendet. Sie laden Bilder normal hoch, speichern die Bildnamen und senden die restlichen Formularfelder erneut mit Bildnamen.
Zen

1

Hier ist mein Beispiel, basiert auf Django + Dropzone. Ansicht hat auswählen (erforderlich) und senden.

<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>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.