Ajout création des listes <select> qui permettront de filtrer les données du fichier
This commit is contained in:
parent
2ae5839aa9
commit
1cf6710c07
@ -10,6 +10,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCSV2HTML</h1>
|
||||
<p id="filtre1"></p>
|
||||
<p id="filtre2"></p>
|
||||
<article id="datas">
|
||||
<p>Si tout se passe bien, ce texte sera remplacé par un tableau de données extraites du fichier csv.</p>
|
||||
</article>
|
||||
|
@ -6,4 +6,5 @@ module.exports =
|
||||
needNaturalNumber: "Merci de fournir un nombre entier supérieur ou égal à zéro pour désigner chaque colonne.",
|
||||
needUrl: "Merci de fournir l'url du fichier CSV à parser.",
|
||||
parserFail: "La lecture des données du fichier a échoué.",
|
||||
selectorFieldNotFound: "Au moins une des colonnes devant servir à filtrer les données n'existe pas dans le fichier.",
|
||||
};
|
@ -6,6 +6,7 @@ const initialise = async () =>
|
||||
{
|
||||
let converter=new freeCSV2HTML();
|
||||
converter.datasViewElt={ id:"datas" };
|
||||
converter.datasSelectors=[{ colCSV:3, id:"filtre1"},{ colCSV:4, id:"filtre2"}];
|
||||
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
|
||||
await converter.run();
|
||||
}
|
||||
@ -14,77 +15,4 @@ const initialise = async () =>
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
initialise();
|
||||
|
||||
|
||||
/*
|
||||
public async setDatasUrl(url: string) : Promise<any> // pas de setter classique à cause asynchrone
|
||||
{
|
||||
const converter=this; // nécessaire pour éviter confusion avec this à l'intérieur de XMLHttpRequest
|
||||
await fetch(url).then(function(response)
|
||||
{
|
||||
if(response.ok)
|
||||
{
|
||||
converter._datasUrl=url;
|
||||
}
|
||||
})
|
||||
if(converter._datasUrl!=="")
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
let req = new XMLHttpRequest();
|
||||
req.open("GET", url);
|
||||
req.addEventListener("load", function ()
|
||||
{
|
||||
if (req.status >= 200 && req.status < 400)
|
||||
{
|
||||
converter._datasUrl=url;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error("Fichier non trouvé");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}*/
|
||||
|
||||
|
||||
/* Exemple d'appelle complet à papaparse :
|
||||
Papa.parse(url, {
|
||||
delimiter :"",
|
||||
newline: "",
|
||||
quoteChar:'"',// à proposer en option
|
||||
escapeChar:"",// idem
|
||||
header:true,
|
||||
transformHeader:"",
|
||||
dynamicTyping:false,
|
||||
preview:0,
|
||||
encoding:"",
|
||||
worker:true,
|
||||
comments:"",
|
||||
step:"",// prévoir en option pour très gros fichiers ?
|
||||
complete: function(results :any)
|
||||
{
|
||||
console.log(results.meta);
|
||||
console.log(results.data[35]);
|
||||
console.log(results.errors);
|
||||
},
|
||||
error:function(error :any)
|
||||
{
|
||||
console.log(error);
|
||||
},
|
||||
download: true,// nécessaire pour un accès via "http..."
|
||||
downloadRequestBody:false,
|
||||
skipEmptyLines: true,
|
||||
chunk:"",
|
||||
fastMode:"",
|
||||
beforeFirstChunk:"",
|
||||
withCredentials:false,
|
||||
transform: "", // à revoir
|
||||
delimitersToGuess:""
|
||||
});
|
||||
* // https://www.papaparse.com/docs#config*/
|
||||
initialise();
|
@ -11,6 +11,8 @@ interface domElement
|
||||
interface selectors extends domElement
|
||||
{
|
||||
colCSV: number;
|
||||
name?: string;
|
||||
values? : string[];
|
||||
}
|
||||
|
||||
export class freeCSV2HTML
|
||||
@ -20,7 +22,6 @@ export class freeCSV2HTML
|
||||
private _datasSourceUrl: string = "";
|
||||
private _datasSelectors: selectors[] = [];
|
||||
|
||||
// Données reçues ou générées suite parsage du fichier CSV :
|
||||
public parseMeta: papaParseMeta|undefined = undefined;
|
||||
public parseDatas: papaParseDatas[] = [];
|
||||
public parseErrors: papaParseErrors[] = [];
|
||||
@ -38,7 +39,7 @@ export class freeCSV2HTML
|
||||
}
|
||||
}
|
||||
|
||||
// Pas plus de tests car nombreux protocoles possibles pour l'url du fichier, pas uniquement http(s). À revoir.
|
||||
// Pas plus de tests + poussés, car nombreux protocoles possibles pour l'url du fichier. À revoir.
|
||||
set datasSourceUrl(url: string)
|
||||
{
|
||||
if(url.trim().length === 0)
|
||||
@ -47,35 +48,34 @@ export class freeCSV2HTML
|
||||
this._datasSourceUrl=url.trim();
|
||||
}
|
||||
|
||||
// La validité du numéro de colonne ne peut être vérifée qu'après le parsage.
|
||||
set datasSelectors(selectors: selectors[])
|
||||
set datasSelectors(selectionElts: selectors[])
|
||||
{
|
||||
let checkContainerExist: HTMLElement|null;
|
||||
for(let i = 0; i < selectors.length; i++)
|
||||
for(let i = 0; i < selectionElts.length; i++)
|
||||
{
|
||||
checkContainerExist=document.getElementById(selectors[i].id);
|
||||
checkContainerExist=document.getElementById(selectionElts[i].id);
|
||||
if(checkContainerExist === null)
|
||||
throw new Error(errors.elementNotFound+selectors[i].id);
|
||||
else if(Number.isInteger(selectors[i].colCSV) === false || selectors[i].colCSV < 0)
|
||||
throw new Error(errors.needNaturalNumber);
|
||||
throw new Error(errors.elementNotFound+selectionElts[i].id);
|
||||
else if(Number.isInteger( selectionElts[i].colCSV) === false || selectionElts[i].colCSV < 0)
|
||||
throw new Error(errors.needNaturalNumber); // La validité réelle du numéro de colonne ne peut être vérifée qu'après le parsage.
|
||||
else
|
||||
selectors[i].eltDOM=checkContainerExist;
|
||||
selectionElts[i].eltDOM=checkContainerExist;
|
||||
}
|
||||
this._datasSelectors=selectors;
|
||||
this._datasSelectors= selectionElts;
|
||||
}
|
||||
|
||||
public async parse(): Promise<any>
|
||||
{
|
||||
const converter=this; // nécessaire pour éviter confusion avec le "this" de la promise
|
||||
const converter=this;
|
||||
return new Promise((resolve,reject) =>
|
||||
{
|
||||
if(this._datasSourceUrl !== "" )
|
||||
if(converter._datasSourceUrl !== "" )
|
||||
{
|
||||
Papa.parse(this._datasSourceUrl,
|
||||
Papa.parse(converter._datasSourceUrl,
|
||||
{
|
||||
quoteChar:'"', // à proposer en option ?
|
||||
header:true,
|
||||
complete: function(results :any)
|
||||
quoteChar: '"',
|
||||
header: true,
|
||||
complete: function(results :any)
|
||||
{
|
||||
converter.parseMeta=results.meta;
|
||||
converter.parseErrors=results.errors; // prévoir option bloquant la suite à la moindre erreur trouvée ?
|
||||
@ -87,11 +87,11 @@ export class freeCSV2HTML
|
||||
reject(new Error(errors.parserFail));
|
||||
},
|
||||
download: true,
|
||||
skipEmptyLines: true, // à proposer en option ?
|
||||
skipEmptyLines: true,
|
||||
});
|
||||
}
|
||||
else
|
||||
resolve(new Error(errors.needUrl));
|
||||
reject(new Error(errors.needUrl));
|
||||
});
|
||||
}
|
||||
|
||||
@ -99,37 +99,106 @@ export class freeCSV2HTML
|
||||
{
|
||||
if (this._datasViewElt.eltDOM === undefined)
|
||||
throw new Error(errors.needDatasElt);
|
||||
|
||||
if(this._datasSourceUrl === "" )
|
||||
else if(this._datasSourceUrl === "" )
|
||||
throw new Error(errors.needUrl);
|
||||
|
||||
if(await this.parse() === true)
|
||||
await this.parse();
|
||||
|
||||
if(this.parseDatas.length === 0 || this.parseMeta === undefined || this.parseMeta.fields === undefined)
|
||||
{
|
||||
if(this.parseDatas.length === 0 || this.parseMeta === undefined || this.parseMeta.fields === undefined)
|
||||
{
|
||||
this._datasViewElt.eltDOM.innerHTML=errors.datasNotFound;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.datasHTML="<table><thead>";
|
||||
for (let i in this.parseMeta.fields)
|
||||
this.datasHTML+="<th>"+this.parseMeta.fields[i]+"</th>";
|
||||
this.datasHTML+="</thead><tbody>";
|
||||
for (let row in this.parseDatas)
|
||||
{
|
||||
this.datasHTML+="<tr>";
|
||||
for(let field in this.parseDatas[row])
|
||||
{
|
||||
if( this.parseMeta.fields.indexOf(field) !== -1) // si les erreurs papaParse sont acceptées, il peut y avoir des données en trop : "__parsed_extra"
|
||||
this.datasHTML+="<td>"+this.parseDatas[row][field]+"</td>";
|
||||
}
|
||||
this.datasHTML+="</tr>";
|
||||
}
|
||||
this.datasHTML+="</tbody></table>";
|
||||
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
||||
return true;
|
||||
}
|
||||
this._datasViewElt.eltDOM.innerHTML=errors.datasNotFound;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Affichage initial des données du fichier
|
||||
this.datasHTML="<table><thead>";
|
||||
for (let i in this.parseMeta.fields)
|
||||
this.datasHTML+="<th>"+this.parseMeta.fields[i]+"</th>";
|
||||
this.datasHTML+="</thead><tbody>";
|
||||
for (let row in this.parseDatas)
|
||||
{
|
||||
this.datasHTML+="<tr>";
|
||||
for(let field in this.parseDatas[row])
|
||||
{
|
||||
if( this.parseMeta.fields.indexOf(field) !== -1) // si les erreurs papaParse sont acceptées, il peut y avoir des données en trop : "__parsed_extra"
|
||||
this.datasHTML+="<td>"+this.parseDatas[row][field]+"</td>";
|
||||
}
|
||||
this.datasHTML+="</tr>";
|
||||
}
|
||||
this.datasHTML+="</tbody></table>";
|
||||
this._datasViewElt.eltDOM.innerHTML=this.datasHTML;
|
||||
|
||||
// Si demandé, création des listes permettant de filter les données
|
||||
if(this._datasSelectors.length > 0)
|
||||
{
|
||||
// Les colonnes devant servir de filtre existent-elles dans le fichier ?
|
||||
let selectorsHTML : string [] = [];
|
||||
for(let i in this._datasSelectors)
|
||||
{
|
||||
if(this._datasSelectors[i].colCSV > (this.parseMeta.fields.length-1))
|
||||
throw new Error(errors.selectorFieldNotFound);
|
||||
else
|
||||
{
|
||||
let values=[], colName=this.parseMeta.fields[this._datasSelectors[i].colCSV];
|
||||
for (let row in this.parseDatas)
|
||||
{
|
||||
if(values.indexOf(this.parseDatas[row][colName]) === -1)
|
||||
values.push(this.parseDatas[row][colName]);
|
||||
}
|
||||
if(values.length > 0)
|
||||
{
|
||||
values.sort(); // revoir le problème des chiffres, dates, etc. https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
|
||||
this._datasSelectors[i].name = colName;
|
||||
this._datasSelectors[i].values=values;
|
||||
selectorsHTML[i]="<label for='CSVDatasSelector"+i+"'>"+colName+" : </label><select name='CSVDatasSelector"+i+"' id='CSVDatasSelector"+i+"'><option value='0'>----</option>";
|
||||
for(let j in values)
|
||||
selectorsHTML[i]+="<option value='"+(Number(j)+1)+"'>"+values[j]+"</option>";
|
||||
selectorsHTML[i]+="</select>";
|
||||
this._datasSelectors[i].eltDOM!.innerHTML=selectorsHTML[i];// je force avec "!", car l'existence de eltDOM a été testée par le setter.
|
||||
}
|
||||
|
||||
// suite : https://stackoverflow.com/questions/19329978/change-selects-option-and-trigger-events-with-javascript
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Exemple d'appelle complet à papaparse :
|
||||
Papa.parse(url, {
|
||||
delimiter :"",
|
||||
newline: "",
|
||||
quoteChar:'"',// à proposer en option
|
||||
escapeChar:"",// idem
|
||||
header:true,
|
||||
transformHeader:"",
|
||||
dynamicTyping:false,
|
||||
preview:0,
|
||||
encoding:"",
|
||||
worker:true,
|
||||
comments:"",
|
||||
step:"",// prévoir en option pour très gros fichiers ?
|
||||
complete: function(results :any)
|
||||
{
|
||||
console.log(results.meta);
|
||||
console.log(results.data[35]);
|
||||
console.log(results.errors);
|
||||
},
|
||||
error:function(error :any)
|
||||
{
|
||||
console.log(error);
|
||||
},
|
||||
download: true,// nécessaire pour un accès via "http..."
|
||||
downloadRequestBody:false,
|
||||
skipEmptyLines: true,
|
||||
chunk:"",
|
||||
fastMode:"",
|
||||
beforeFirstChunk:"",
|
||||
withCredentials:false,
|
||||
transform: "", // à revoir
|
||||
delimitersToGuess:""
|
||||
});
|
||||
* // https://www.papaparse.com/docs#config*/
|
File diff suppressed because one or more lines are too long
@ -112,5 +112,63 @@ describe("freeCSV2HTML", () =>
|
||||
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTML);
|
||||
});
|
||||
|
||||
it("Doit générer une erreur si au moins un des numéros de colonne des sélecteurs ne correspond pas à une des colonne du fichier.", async () =>
|
||||
{
|
||||
converter.datasViewElt={ id:"datas" };
|
||||
converter.datasSourceUrl="http://localhost:9876/datas/elements-chimiques.csv";
|
||||
converter.datasSelectors=[{ colCSV:0, id:"selector1"},{ colCSV:5, id:"selector2"}];
|
||||
await expectAsync(converter.run()).toBeRejectedWith(new Error(errors.selectorFieldNotFound));
|
||||
});
|
||||
|
||||
it("Ne doit pas générer d'erreur si tous les numéros de colonne des sélecteurs correspondent pas à une des colonne du fichier.", async () =>
|
||||
{
|
||||
converter.datasViewElt={ id:"datas" };
|
||||
converter.datasSourceUrl="http://localhost:9876/datas/elements-chimiques.csv";
|
||||
converter.datasSelectors=[{ colCSV:3, id:"selector1"},{ colCSV:4, id:"selector2"}];
|
||||
await expectAsync(converter.run()).not.toBeRejected();
|
||||
});
|
||||
|
||||
it("Pour chaque sélecteur demandé doit générer un élement <select> listant les valeurs distinctes du fichier, classées par ordre alphabétique.", async () =>
|
||||
{
|
||||
converter.datasViewElt={ id:"datas" };
|
||||
converter.datasSourceUrl="http://localhost:9876/datas/elements-chimiques.csv";
|
||||
converter.datasSelectors=[{ colCSV:3, id:"selector1"},{ colCSV:4, id:"selector2"}];
|
||||
await converter.run();
|
||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML);
|
||||
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTML);
|
||||
});
|
||||
|
||||
it("Le choix d'un option dans un des sélecteurs doit modifier le contenu du tableau pour ne garder que les données valides pour ce choix et afficher toutes les données si sélection 0.", async () =>
|
||||
{
|
||||
converter.datasViewElt={ id:"datas" };
|
||||
converter.datasSourceUrl="http://localhost:9876/datas/elements-chimiques.csv";
|
||||
converter.datasSelectors=[{ colCSV:3, id:"selector1"},{ colCSV:4, id:"selector2"}];
|
||||
await converter.run();
|
||||
|
||||
let selectElement = document.getElementById("CSVDatasSelector0") as HTMLInputElement;
|
||||
selectElement.value="4";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
let txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelect1);
|
||||
|
||||
selectElement.value="0";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTML);
|
||||
|
||||
selectElement = document.getElementById("CSVDatasSelector1") as HTMLInputElement;
|
||||
selectElement.value="1";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTMLForSelect2);
|
||||
|
||||
selectElement.value="0";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
txtDatasViewsElt=document.getElementById("datas").innerHTML;
|
||||
expect(txtDatasViewsElt).toEqual(fixtures.datasHTML);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user