web-dev-qa-db-fra.com

Intégration de Dropzone.js dans un formulaire HTML existant avec d'autres champs

Je dispose actuellement d'un formulaire HTML dans lequel les utilisateurs remplissent les détails d'une annonce qu'ils souhaitent publier. Je souhaite maintenant pouvoir ajouter une zone de dépôt pour télécharger des images de l'article en vente. J'ai trouvé dropzone.js qui semble faire presque tout ce dont j'ai besoin. Cependant, lorsque vous examinez la documentation, il apparaît que vous devez spécifier la classe de la forme entière du formulaire en tant que "zone de transfert" (par opposition à l'élément d'entrée uniquement). Cela signifie alors que toute ma forme devient la zone de chute. Est-il possible d’utiliser la zone de saut dans une partie de mon formulaire, c’est-à-dire en spécifiant uniquement l’élément comme classe dropzone, plutôt que dans son intégralité?

Je pourrais utiliser des formulaires séparés, mais je veux que l'utilisateur puisse tout envoyer avec un seul bouton.

Sinon, y a-t-il une autre bibliothèque qui peut le faire?

Merci beaucoup

146
Ben Thompson

Voici une autre façon de procéder: ajoutez une div à votre formulaire avec un nom de classe dropzone et implémentez dropzone par programme.

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

Remarque: Désactivation de la détection automatique, sinon Dropzone essaiera de se joindre deux fois.

Article de blog: Dropzone js + Asp.net: un moyen facile de télécharger des images en vrac

53
Satinder singh

J’ai eu exactement le même problème et j’ai trouvé que la réponse de Varan Sinayee était la seule à avoir résolu la question initiale. Cette réponse peut cependant être simplifiée, voici donc une version plus simple.

Les étapes sont les suivantes:

  1. Créez une forme normale (n'oubliez pas la méthode et les arguments enctype car cela n'est plus géré par dropzone).

  2. Mettez un div à l'intérieur avec le class="dropzone" (c'est ainsi que Dropzone s'y attache) et le id="yourDropzoneName" (utilisé pour changer les options).

  3. Définissez les options de Dropzone, pour définir l'URL où le formulaire et les fichiers seront postés, désactivez autoProcessQueue (afin que cela ne se produise que lorsque l'utilisateur appuie sur «Soumettre») et autorisez plusieurs téléchargements (si vous en avez besoin).

  4. Configurez la fonction init pour qu'elle utilise Dropzone au lieu du comportement par défaut lorsque l'utilisateur clique sur le bouton d'envoi.

  5. Toujours dans la fonction init, utilisez le gestionnaire d’événement "sendmultiple" pour envoyer les données de formulaire avec les fichiers.

Voilà! Vous pouvez maintenant récupérer les données comme vous le feriez avec un formulaire normal, dans $ _POST et $ _FILES (dans l'exemple, cela se produirait dans 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());
        });
    }
}
28
mrtnmgs

Le fichier "dropzone.js" est la bibliothèque la plus courante pour le téléchargement d’images. Si vous souhaitez que le fichier "dropzone.js" fasse partie intégrante de votre formulaire, procédez comme suit:

1) pour le côté 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) pour le côté serveur:

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." });
    }
17
Varan Sinayee

Le tutoriel d'Enyo est excellent.

J'ai constaté que l'exemple de script du tutoriel fonctionnait bien pour un bouton intégré à la zone de saut (c'est-à-dire l'élément de formulaire). Si vous souhaitez que le bouton soit en dehors de l'élément de formulaire, j'ai été en mesure de le réaliser à l'aide d'un événement de clic:

Tout d'abord, le 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>

Ensuite, la balise de 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();
        }); 
    }
}
11
kablamus

En plus de ce que sqram disait, Dropzone a une option non documentée supplémentaire, "hiddenInputContainer". Tout ce que vous avez à faire est de définir cette option sur le sélecteur du formulaire auquel vous souhaitez que le champ de fichier caché soit ajouté. Et le tour est joué! Le champ de fichier ".dz-hidden-input" que Dropzone ajoute normalement au corps se déplace comme par magie dans votre formulaire. Pas de modification du code source de Dropzone.

Maintenant, alors que cela fonctionne pour déplacer le champ de fichier Dropzone dans votre formulaire, le champ n'a pas de nom. Vous devrez donc ajouter:

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

dropzone.js après cette ligne:

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

autour de la ligne 547.

4
Codedragon

Vous pouvez modifier les données formData en capturant l'événement "envoi" de votre zone de dépôt.

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

Afin de soumettre tous les fichiers avec d'autres données de formulaire dans une seule demande, vous pouvez copier des noeuds temporaires input temporaires Dropzone.js dans votre formulaire. Vous pouvez le faire dans le gestionnaire d'événements addedfiles:

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

Évidemment, il s’agit d’une solution de contournement dépendant des détails de l’implémentation. Code source associé .

3
Leonid Vasilev

J'ai une solution plus automatisée pour cela. 

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

Il n'est pas nécessaire de désactiver DropZone Discovery et le formulaire normal de soumission pourra envoyer le fichier avec tout autre champ de formulaire via la sérialisation du formulaire standard. 

Ce mécanisme stocke le contenu du fichier sous forme de chaîne base64 dans le champ de saisie masqué lors de son traitement. Vous pouvez le décoder en chaîne binaire dans PHP via la méthode standard base64_decode().

Je ne sais pas si cette méthode sera compromise avec des fichiers volumineux mais cela fonctionne avec des fichiers de ~ 40MB. 

3
Umair Ahmed

Ceci est juste un autre exemple de la façon dont vous pouvez utiliser Dropzone.js dans un formulaire existant. 

dropzone.js:

 init: function() {

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

   return noop;
 },

Puis, plus tard dans le dossier, je mets 

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

Cela suppose que vous avez un div avec id #botofform de cette façon lors du téléchargement, vous pouvez utiliser les noms des fichiers téléchargés. 

Remarque: mon script de téléchargement a renvoyé theuploadedfilename.jpeg Dubblenote. Vous devez également créer un script de nettoyage qui vérifie le répertoire de téléchargement des fichiers non utilisés et les supprime ..si sous une forme frontale non authentifiée :)

0
taggart

Voici mon échantillon, basé sur Django + Dropzone. La vue a select (requis) et à soumettre.

<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>
0
smartworld-dm