Pour intégrer le téléchargement de fichiers avec la soumission de données de formulaire via une requête Axios, le composant <el-upload> d'ElementUI peut être configuré pour empêcher l'envoi automatique. Cela permet de regrouper le fichier et les autres champs du formulaire dans un objet FormData avant de les transmettre au serveur.
Première approche : Interception avec before-upload
Dans cette méthode, nous utilisons le hook before-upload pour bloquer le téléchargement par défaut et construire manuellement notre charge utile.
Code du composant Vue
<template>
<el-row>
<el-col :span="8" :offset="8">
<label class="el-form-item__label">Image</label>
<el-upload
:before-upload="avantTelechargement"
drag
action="https://jsonplaceholder.typicode.com/posts/"
style="margin-left:80px;">
<i class="el-icon-upload"></i>
<div class="el-upload__text">Déposez le fichier ici ou <em>cliquez pour sélectionner</em></div>
</el-upload>
<el-form ref="formulaire" :model="formulaire" label-width="80px">
<el-form-item label="Nom">
<el-input v-model="formulaire.nom" style="width:360px;"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="soumettreFormulaire">Créer</el-button>
<el-button>Annuler</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="4">
<div style="width:100%;overflow:hidden;margin-left:150px;">
<img :src="apercuImage" style="width:100%;" />
</div>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
formulaire: { nom: '' },
donneesFichier: null,
apercuImage: "https://via.placeholder.com/150"
};
},
methods: {
avantTelechargement(fichier) {
const urlLocale = window.URL || window.webkitURL;
this.apercuImage = urlLocale.createObjectURL(fichier);
this.donneesFichier = new FormData();
this.donneesFichier.append('fichier', fichier, fichier.name);
return false; // Empêche l'envoi automatique
},
soumettreFormulaire() {
this.donneesFichier.append('message', this.formulaire.nom);
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
this.$axios.post("/upload", this.donneesFichier, config).then(reponse => {
console.log(reponse);
});
}
}
}
</script>
Traitement côté serveur avec Node.js et Formidable
Côté backend, Express combiné au module formidable permet d'extraire facilement les fichiers et les champs textuels de la requête multipatr.
const express = require('express');
const routeur = express.Router();
const formidable = require('formidable');
const fs = require("fs");
routeur.post("/", (req, res, next) => {
const formulaireEntrant = new formidable.IncomingForm();
formulaireEntrant.parse(req, (err, champs, fichiers) => {
console.log("Fichiers reçus :", fichiers);
console.log("Champs reçus :", champs); // Contient le champ 'message'
});
});
module.exports = routeur;
Deuxième approche : Utilisation de auto-upload à false
Cette technique offre un meilleur contrôle, noatmment la possibilité de supprimer un fichier sélectionné avant l'envoi. On utilise :auto-upload="false" et les événements on-change ainsi que on-remove.
Interface de glisser-déposer
<template>
<el-row>
<el-col :span="8" :offset="8">
<el-form ref="frmGlisser" :model="frmGlisser" label-width="80px">
<el-form-item label="Titre">
<el-input v-model="frmGlisser.titre" style="width:360px;"></el-input>
</el-form-item>
<label class="el-form-item__label">Image</label>
<el-upload
:auto-upload="false"
:on-change="gererChangement"
:on-remove="gererSuppression"
:limit="1"
drag
action=""
style="margin-left:80px;">
<i class="el-icon-upload"></i>
<div class="el-upload__text">Déposez ici ou <em>sélectionnez</em></div>
<div class="el-upload__tip" slot="tip">Un seul fichier autorisé. Supprimez-le d'abord pour en changer.</div>
</el-upload>
<el-form-item style="padding-top:20px;">
<el-button type="primary" @click="envoyerDonnees">Soumettre</el-button>
<el-button>Annuler</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="4">
<div style="width:100%;overflow:hidden;margin-left:150px;">
<img :src="apercuGlisser" style="width:100%;" />
</div>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
frmGlisser: { titre: '' },
chargeUtile: new FormData(),
apercuGlisser: "https://via.placeholder.com/150"
};
},
methods: {
gererChangement(fichier) {
const urlLocale = window.URL || window.webkitURL;
this.apercuGlisser = urlLocale.createObjectURL(fichier.raw);
this.chargeUtile = new FormData();
this.chargeUtile.append('fichier', fichier.raw, fichier.name);
},
gererSuppression() {
this.chargeUtile.delete('fichier');
},
envoyerDonnees() {
this.chargeUtile.append('message', this.frmGlisser.titre);
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
this.$axios.post("/upload", this.chargeUtile, config).then(reponse => {
console.log(reponse);
});
}
}
}
</script>
Interface sous forme de liste d'images
L'attribut list-type="picture" permet d'afficher les miniatures dans une liste au lieu d'une zone de glisser-déposer.
<template>
<el-row>
<el-col :span="8" :offset="8">
<el-form ref="frmListe" :model="frmListe" label-width="80px">
<el-form-item label="Projet">
<el-input v-model="frmListe.projet" style="width:360px;"></el-input>
</el-form-item>
<el-form-item label="Fichier">
<el-upload
:auto-upload="false"
:on-change="gererAjout"
:on-remove="gererRetrait"
:limit="1"
action=""
list-type="picture">
<el-button size="small" type="primary">Sélectionner</el-button>
</el-upload>
</el-form-item>
<el-form-item style="padding-top:20px;">
<el-button type="primary" @click="valider">Créer</el-button>
<el-button>Annuler</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
frmListe: { projet: '' },
donneesMultiparts: new FormData()
};
},
methods: {
gererAjout(fichier) {
this.donneesMultiparts = new FormData();
this.donneesMultiparts.append('fichier', fichier.raw, fichier.name);
},
gererRetrait() {
this.donneesMultiparts.delete('fichier');
},
valider() {
this.donneesMultiparts.append('message', this.frmListe.projet);
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
this.$axios.post("/upload", this.donneesMultiparts, config).then(reponse => {
console.log(reponse);
});
}
}
}
</script>