J'essaie d'ajouter une option de téléchargement csv à mon site web. Elle doit convertir le tableau html présent sur le site en contenu csv et le rendre téléchargeable. J'ai cherché sur internet un bon plugin et j'en ai trouvé quelques uns d'utiles comme http://www.dev-skills.com/export-html-table-to-csv-file/ Mais il utilise php script pour effectuer le téléchargement. Je me demandais s'il existait une bibliothèque purement javascript disponible pour réaliser cette fonctionnalité en utilisant des logiciels côté serveur comme node.js sans utiliser php ?
Réponses
Trop de publicités?J'ai utilisé la réponse ci-dessus, mais je l'ai adaptée à mes besoins.
J'ai utilisé la fonction suivante et je l'ai importée dans mon REACT où je devais télécharger le fichier csv.
J'ai eu un span
à l'intérieur de mon th
éléments. Ajout de commentaires sur ce que font la plupart des fonctions/méthodes.
import { tableToCSV, downloadCSV } from './../Helpers/exportToCSV';
export function tableToCSV(){
let tableHeaders = Array.from(document.querySelectorAll('th'))
.map(item => {
// title = splits elem tags on '\n',
// then filter out blank "" that appears in array.
// ex ["Timestamp", "[Full time]", ""]
let title = item.innerText.split("\n").filter(str => (str !== 0)).join(" ")
return title
}).join(",")
const rows = Array.from(document.querySelectorAll('tr'))
.reduce((arr, currRow) => {
// if tr tag contains th tag.
// if null return array.
if (currRow.querySelector('th')) return arr
// concats individual cells into csv format row.
const cells = Array.from(currRow.querySelectorAll('td'))
.map(item => item.innerText)
.join(',')
return arr.concat([cells])
}, [])
return tableHeaders + '\n' + rows.join('\n')
}
export function downloadCSV(csv){
const csvFile = new Blob([csv], { type: 'text/csv' })
const downloadLink = document.createElement('a')
// sets the name for the download file
downloadLink.download = `CSV-${currentDateUSWritten()}.csv`
// sets the url to the window URL created from csv file above
downloadLink.href = window.URL.createObjectURL(csvFile)
// creates link, but does not display it.
downloadLink.style.display = 'none'
// add link to body so click function below works
document.body.appendChild(downloadLink)
downloadLink.click()
}
Lorsque l'utilisateur clique sur export to csv, il déclenche la fonction suivante dans react.
handleExport = (e) => {
e.preventDefault();
const csv = tableToCSV()
return downloadCSV(csv)
}
Exemple de tableau html elems.
<table id="datatable">
<tbody>
<tr id="tableHeader" className="t-header">
<th>Timestamp
<span className="block">full time</span></th>
<th>current rate
<span className="block">alt view</span>
</th>
<th>Battery Voltage
<span className="block">current voltage
</span>
</th>
<th>Temperature 1
<span className="block">[C]</span>
</th>
<th>Temperature 2
<span className="block">[C]</span>
</th>
<th>Time & Date </th>
</tr>
</tbody>
<tbody>
{this.renderData()}
</tbody>
</table>
</div>
Une solution moderne
La plupart des solutions proposées ici ne fonctionneront pas avec des tableaux imbriqués ou d'autres éléments à l'intérieur de vos éléments td. J'utilise fréquemment d'autres éléments à l'intérieur de mes tableaux, mais je ne veux exporter que le tableau le plus haut. J'ai repris une partie du code trouvé ici par Calumah et j'ai ajouté du JS ES6 vanille moderne.
Utilisation texteContenu est une meilleure solution que innerText, car innerText renvoie tout le code HTML contenu dans les éléments td. Cependant, même textContent renverra le texte des éléments imbriqués. Une solution encore meilleure est d'utiliser des attributs de données personnalisés sur vos td et d'en extraire les valeurs pour votre CSV.
Bon codage !
function downloadAsCSV(tableEle, separator = ','){
let csvRows = []
//only get direct children of the table in question (thead, tbody)
Array.from(tableEle.children).forEach(function(node){
//using scope to only get direct tr of node
node.querySelectorAll(':scope > tr').forEach(function(tr){
let csvLine = []
//again scope to only get direct children
tr.querySelectorAll(':scope > td').forEach(function(td){
//clone as to not remove anything from original
let copytd = td.cloneNode(true)
let data
if(copytd.dataset.val) data = copytd.dataset.val.replace(/(\r\n|\n|\r)/gm, '')
else {
Array.from(copytd.children).forEach(function(remove){
//remove nested elements before getting text
remove.parentNode.removeChild(remove)
})
data = copytd.textContent.replace(/(\r\n|\n|\r)/gm, '')
}
data = data.replace(/(\s\s)/gm, ' ').replace(/"/g, '""')
csvLine.push('"'+data+'"')
})
csvRows.push(csvLine.join(separator))
})
})
var a = document.createElement("a")
a.style = "display: none; visibility: hidden" //safari needs visibility hidden
a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csvRows.join('\n'))
a.download = 'testfile.csv'
document.body.appendChild(a)
a.click()
a.remove()
}
Edit : cloneNode() mis à jour en cloneNode(true) pour obtenir l'intérieur.
J'ai découvert qu'il existe une bibliothèque pour cela. Voir l'exemple ici :
https://editor.datatables.net/examples/extensions/exportButtons.html
En plus du code ci-dessus, les fichiers de la bibliothèque Javascript suivants sont chargés pour être utilisés dans cet exemple :
En HTML, inclure les scripts suivants :
jquery.dataTables.min.js
dataTables.editor.min.js
dataTables.select.min.js
dataTables.buttons.min.js
jszip.min.js
pdfmake.min.js
vfs_fonts.js
buttons.html5.min.js
buttons.print.min.js
Activez les boutons en ajoutant des scripts comme :
<script>
$(document).ready( function () {
$('#table-arrays').DataTable({
dom: '<"top"Blf>rt<"bottom"ip>',
buttons: ['copy', 'excel', 'csv', 'pdf', 'print'],
select: true,
});
} );
</script>
Pour une raison quelconque, l'exportation excel produit un fichier corrompu, mais qui peut être réparé. Une autre solution consiste à désactiver Excel et à utiliser l'exportation csv.
J'ai utilisé la fonction de Calumah affichée ci-dessus, mais j'ai rencontré un problème avec son code.
Les lignes sont reliées par un point-virgule
csv.push(row.join(';'));
mais le lien généré a pour type de contenu "text/csv".
Ce n'est peut-être pas un problème sous Windows, mais dans Excel pour Mac, cela perturbe les choses. J'ai remplacé la jointure du tableau par une virgule et cela a fonctionné parfaitement.
- Réponses précédentes
- Plus de réponses