Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. ###raw>post.musername###
    Nouveau Candidat au Club
    Bonjour !

    Alors je travail sur une application nodeJS actuellement et j'ai un système qui permet d'upload un fichier de type CSV et qui met à jour la base de donnée directement.

    Mon problème est que j'aimerai ne pas upload tout le fichier CSV, et supprimer des lignes quand je clique sur envoyer la demande (voir images).



    J'aimerais supprimer mes 5 premières lignes du document ainsi que ceux où le nom du fournisseur c'est NE PLUS UTILISER comme dans l'image ci-dessous.



    Voici le code pour vous aidez à comprendre.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    const csv = require('csvtojson');
    const fs = require('fs');
     
    const CSV_RETURN_CODES = {
      ERRORS: 'Le fichier a été importé avec succès mais avec des erreurs non bloquantes.',
      SUCCESS: 'Le fichier a été importé avec succès.',
    };
     
    module.exports.CSV_RETURN_CODES = CSV_RETURN_CODES;
    module.exports.Csv = class Csv {
      constructor(filePath) {
        this.filePath = filePath;
        // this.filePath = './temp/fournisseurs.csv';
      }
     
      async toJson(Model, callback) {
        const rows = [];
        await csv({
          delimiter: [';'],
          ignoreEmpty: true,
          noheader: false,
          headers: ['id', 'raison_sociale', 'mail', 'tel', 'adresse', 'cp', 'localite'],
        })
          .fromFile(this.filePath)
          .on('json', async (jsonObj) => {
            try {
              if (jsonObj.id !== '' && Number.isInteger(parseInt(jsonObj.id, 10)) && parseInt(jsonObj.id, 10) < 5000000) {
                rows.push(Model.upsert(jsonObj));
              }
            } catch (e) {
              console.error(e);
            }
          })
          .on('end', async (err) => {
            fs.unlinkSync(this.filePath);
            try {
              await Promise.all(rows);
              if (err) {
                console.error(err);
                return callback(CSV_RETURN_CODES.ERRORS);
              }
              console.log('Fournisseurs importés avec success');
              return callback(CSV_RETURN_CODES.SUCCESS);
            } catch (e) {
              console.error(e);
            }
          });
      }
    };

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    /*
        Import fournisseurs
      */
     
      $('#fournisseurs-input').fileinput({
        language: 'fr',
        showUpload: false,
        showCaption: false,
        showPreview: false,
        allowedFileExtensions: ['csv']
      });
     
      $('#importer-fournisseurs').click(function() {
        const fichier = $('#fournisseurs-input').prop('files')[0];
        let form = $('#form-import-fournisseurs');
        $(this).button('loading');
        console.log(form);
        if(fichier) {
          let payload = new FormData();
          payload.append('fichier', fichier);
          $.ajax({
            url: form.attr('action'),
            type: form.attr('method'),
            data: payload,
            processData: false,
            contentType: false,
            success: function () {
              $('#importer-fournisseurs').button('reset');
              displaySuccess('Fournisseurs ajoutés avec <strong>succes</success>');
            },
            error: function () {
              $('#importer-fournisseurs').button('reset');
              displayError('lors de l\'ajout des utilisateurs !');
            },
          });
        }
        else {
          $('#importer-fournisseurs').button('reset');
          displayError('Veuillez insérer un fichier à importer');
        }
      });
     
      $('#fournisseurs-input').on('fileloaded', function (event, file) {
        const label_selector = '#label-fournisseurs-input';
        $(label_selector).text(file.name.substring(0, 25) + '...');
        $(label_selector).attr('title', file.name);
      });
     
      $('#fournisseurs-input').on('fileclear', function () {
        $('#label-fournisseurs-input').text('');
      });
     
      $('#fournisseurs-input').on('fileerror', function () {
        $(this).fileinput('clear');
        $('#label-fournisseurs-input').text('Extension invalide. Utilisez des .csv');
        displayError('Extension invalide. Utilisez des .csv');
      });


    HTML :

    Code html :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <div class="row">
      <div class="col-md-6">
        <form id="form-import-fournisseurs" action="/fournisseurs/import" method="POST">
     
          <h1>Importer les fournisseurs</h1>
     
          <p>Le fichier doit être dans le fomat CSV (séparateur 'point-virgule').</p>
     
          <div class="form-group col-md-5">
            <label for="fournisseurs-input">Fichier:
              <span id="label-fournisseurs-input"></span>
            </label>
            <input id="fournisseurs-input" type="file" accept=".csv" class="fileinput">
          </div>
     
          <div class="hidden divider"></div>
     
          <button id="importer-fournisseurs" type="button" class="btn btn-success"
          data-loading-text="<i class='glyphicon glyphicon-refresh spinner'></i> Importation en cours">
            <span class="glyphicon glyphicon-ok"></span>
            {{i18n "bon_commande.btn_envoyer"}}
          </button>
     
          <div id="messages-zone"></div>
      </div>
    </div>


    Merci par avance pour votre aide !
      0  0

  2. #2
    Expert éminent
    Bonjour&#8239;!

    Je pense que le truc qui te manque c’est FileReader. Ça va s’insérer quelque part entre tes deux lignes&#8239;:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const fichier = $('#fournisseurs-input').prop('files')[0];
     
    // ...
     
    payload.append('fichier', fichier);

    Le principe est assez simple, c’est un objet qui lit le fichier de manière asynchrone et te renvoie le résultat sous une forme voulue&#8239;; en l’occurence on va choisir la forme texte avec .readAsText(). Le résultat ou l’erreur se gèrent avec des fonctions de rappel.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const reader = new FileReader();
     
    reader.onerror = function () {
      console.error(reader.error);
      // insérer dans la page un message d’erreur adressé à l’utilisateur (pas de détails techniques)
    };
     
    reader.onload = function () {
      // ...
    };
     
    reader.readAsText(fichier);


    (Je rajoute vite fait un mot à propos du message d’erreur. D’après la spec, un FileReader peut émettre trois types d’erreur&#8239;: le fichier est introuvable, le fichier est illisible, ou il y a un problème de permissions. Tu peux utiliser la propriété .name pour connaître le type d’erreur et tenter d’afficher un message à peu près adapté à la situation.)

    Dans le .onload, je propose de découper la chaîne en lignes et utiliser les méthodes de Array. J’utilise un second tableau pour empiler les lignes à garder, parce que je ne sais jamais si ça se passe bien quand on supprime des lignes en place pendant une itération

    À la fin, pour coller les morceaux ensemble, on aura besoin de Blob qui nous permettra de reconvertir notre chaîne en un objet que FormData enverra de la même façon que le fichier original. Ainsi, on n’a pas besoin de modifier le code serveur.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    reader.onload = function () {
      const lines = reader.result.split(/\r?\n/);
      const n = lines.length;
      const linesToKeep = [];
     
      // on commence à 5
      for (let i = 5; i < n; i++) {
        const line = lines[i];
        // on garde seulement si la ligne ne contient pas « NE PAS UTILISER »
        if (line.indexOf('NE PAS UTILISER') < 0) {
          linesToKeep.push(line);
        }
      }
     
      const blob = new Blob(linesToKeep, { type: 'text/csv' }); // le type est optionnel, je l’ai mis pour l’exemple
      payload.append('fichier', blob);
     
      $.ajax({
        // ...
        // ... (ne change pas)
        // ...
      });
    };
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  3. #3
    Nouveau Candidat au Club
    CSV
    Bonjour,

    Déjà désoler pour la réponse très tardive ! Je n'avais pas retravaillé sur le projet depuis un moment.
    J'ai repris depuis lundi et je me suis penché sur ce cas, j'ai essayer d'intégré ce que tu m'avais conseillé mais sans résultat de ma part.

    Je ne voit pas trop le problème après de nombreuse recherche sur internet également et comme je ne suis pas trop a l'aise avec ça je reviens vers vous pour un peu plus d'aide.

    Voici le code avec l'intégration, je pense l'avoir bien intégré et j'ai l'impression que il ne prend pas en compte le nouveau fichier modifier avec le blob.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    $('#importer-fournisseurs').click(function() {
        const fichier = $('#fournisseurs-input').prop('files')[0];
        let form = $('#form-import-fournisseurs');
        $(this).button('loading');
        console.log(form);
        if(fichier) {
          console.log(fichier);
          const reader = new FileReader();
          let payload = new FormData();
          reader.onerror = function() {
            console.error(reader.error)
          };
          reader.onload = function() {
            const lines = reader.result.split(/\r?\n/);
            const n = lines.length;
            const linesToKeep = [];
     
            for (let i = 5; i < n; i++) {
              const line = lines[i];
     
              if (line.indexOf('NE PAS UTILISER') < 0) {
                linesToKeep.push(line);
              }
            }
            const blob = new Blob(linesToKeep, { type: 'text/csv' });
            payload.append('fichier', blob);
            console.log(blob);
          }
          reader.readAsText(fichier);


    J'ai mis dans le if(fichier) car le mettre au-dessus, je trouve que cela n'a pas de sens en sachant que si nous avons pas de fichier, il ne faut pas le faire.
    Ensuite ce que j'ai constaté dans un premier temps, c'est que le blob fonctionne bien avec les console.log cela enlève bien les lignes on dirait comme la taille du fichier rétréci mais quand on fais le reader.readAsText(fichier) le fichier est celui du départ, ce que je ne comprend pas tellement, faut-il mettre le blob ?

    Je n'est pas de message d'erreur, le fichier charge a l'infini sans résultat.

    Merci de votre réponse d'avance !

    Cordialement.

  4. #4
    Nouveau Candidat au Club
    Problème CSV
    Re !

    Je reviens vers vous pour vous demander de l'aide encore si possible.
    Je n'ai toujours pas résolu mon problème et cela devient embêtant..

    On m'a parlé de SheetJS mais je ne pense pas que ça soit la bonne solution non plus.

    Quelqu’un aurait une idée ?

    Merci !
    Cordialement.

  5. #5
    Expert éminent
    Re,
    je ne suis pas sûr de comprendre ce passage&#8239;:
    Citation Envoyé par Nutss45 Voir le message
    quand on fais le reader.readAsText(fichier) le fichier est celui du départ
    Comment tu constates ça&#8239;? Tu as mis un autre console.log dans une partie du code que tu ne montres pas&#8239;?

    Je pense comme toi que SheetJS n’est pas une bonne idée, c’est hors sujet.

    Dans mon précédent post, j’ai dit un truc que je n’ai pas pris le temps d’expliquer en détail&#8239;:
    Citation Envoyé par Watilin Voir le message
    c’est un objet qui lit le fichier de manière asynchrone
    Asynchrone, ça veut dire que l’opération de lecture se fait dans un autre fil d’exécution que ton script. La fonction onload est appelée «&#8239;à un moment&#8239;», on ne sait pas précisément quand.
    Voici un schéma&#8239;:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    fil JS principal                                                | temps
    ----------------                                                v
         ...
          |                            fil du reader
          |                            -------------
          + readAsText() -----------------> | (lecture du fichier)
          |                                 |
          x (fin de la fonction click)      |
                                            |
                                            |
          | <--------------------- onload() +
          |
         ...

    Comme tu peux le voir, la fonction onload est appelée après readAsText, chronologiquement, malgré le fait qu’elle se trouve avant dans le code. C’est peut-être ça que tu ne comprends pas.

    Dans le code dans ton premier post, il y avait un appel $.ajax( ... ). Où est-il passé&#8239;?

    Au fait, j’insiste sur ce point&#8239;:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
      // insérer dans la page un message d’erreur adressé à l’utilisateur (pas de détails techniques)

    Il faut expliquer ce qui se passe à l’utilisateur ou l’utilisatrice, sinon tu as un problème d’UX. C’est important aussi
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  6. ###raw>post.musername###
    Nouveau Candidat au Club
    Re,

    Alors pour commencé si je constate bien que le fichier change de taille grâce au console.log et grâce au console.log, j'ai compris comment ça fonctionnais le système de onload



    Ensuite quand je met mon fichier, j'ai aucune erreur et ça tourne en boucle pendant 10 minutes puis m'affiche l'erreur de mon $.ajax( ... ) qui est :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    error: function () {
              $('#importer-fournisseurs').button('reset');
              displayError('lors de l\'ajout des utilisateurs !');
            },
          });




    Mon $.ajax( ... ) est toujours là et je ne l'ai pas changé et il se situe après le payload.append('fichier', blob);

    L’opération s'effectue bien et malgré les explications et les recherches, je ne vois pas d'ou vient mon erreur, si c'est moi qui ai mal placé le code ou qu'il manque une chose

    Merci !
      0  0

  7. ###raw>post.musername###
    Expert éminent
    Je vois dans ta console un affichage de la variable fichier qui semble venir de la ligne 1501, donc après la ligne console.log(blob) dans le code. Or, il se produit avant l’affichage du blob, ce qui laisse supposer que la partie de code où il se trouve (que tu n’as pas montrée) s’exécute sur le fil principal avant l’appel à reader.onload.
    De plus, c’est peut-être bête à dire mais je le dis quand même&#8239;: le contenu de fichier n’est pas modifié. La version modifiée du texte est représentée par blob, et c’est normal que fichier contienne les données originales.

    Cette histoire de 10 minutes nous met sur une nouvelle piste&#8239;: une boucle infinie côté serveur (ou alors un très gros lag réseau, mais vu que tu es en localhost, c’est peu probable ). Tu peux vérifier deux choses&#8239;:
    • le message de statut HTTP via les arguments passés à la fonction error&#8239;:
      Code :Sélectionner tout -Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      error: function (jqXHR, textStatus, errorThrown) {
                console.log('statut HTTP: ', errorThrown);
                $('#importer-fournisseurs').button('reset');
                displayError('lors de l\'ajout des utilisateurs !');
              },
            });

      (Les arguments de cette fonction sont bizarrement nommés mais c’est comme ça dans la doc )
      Note que des fois, errorThrown ne contient rien.
    • Les logs de ton serveur. Par exemple si c’est un serveur Apache, vérifie les logs Apache. Tu pourrais trouver des indices dans apache_error.log ou php_error.log en fonction du genre d’erreur.
      0  0

  8. #8
    Nouveau Candidat au Club
    Je te remet une partie du code avec les lignes pour que les console.log soit compréhensible.



    J'ai vérifier les erreurs comme tu m'a demandé et voici le résultat :
    Http = textStatus
    Http2 = jqXHR



    errorThrown ne contient rien du tout.

    Ensuite pour apache j'ai juste trouvé ceci :



    Je pense pas que cette erreur est pertinente pour mon problème

  9. #9
    Expert éminent
    C’est bizarre, tu as un status: 0 qui semble indiquer que la requête n’est jamais partie…
    Mais dans les situations que je connais, un status 0 s’accompagne d’un readyState 4, or là il est 0 également. (Mais c’est peut-être juste jQuery qui masque le vrai objet XMLHttpRequest.)
    Je ne sais pas ce qui se passe. À tout hasard, regarde l’onglet réseau de ta console, il y a peut-être des infos.
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

###raw>template_hook.ano_emploi###