Importare un CSV con Instant Developer Cloud

Chi non è mai incappato nell’importazione di dati mediante un file in formato CSV per riempire una tabella del proprio database?
Farlo con gli strumenti di gestione del database magari è relativamente facile ma se devi farlo fare ad un utente del tuo applicativo le cose si complicano.

Con Instant Developer Cloud ti viene incontro la classe Papaparse che ci permette di fare il parsing e l’unparsing di file in formato CSV.
La cosa bella è che legge direttamente il file, capisce quale separatore di colonne è stato utilizzato, divide le intestazioni dai dati nel risultato e fa molte altre cose.

Vi metto qui un esempio di codice che presuppone di dover caricare i dati in un documento con questi campi: “nome”, "cognome, “data Nascita” e “codiceFiscale”.
la variabile fileCSV contiene un oggetto File che posso aver caricato da interfaccia utente mediante l’elemento DropZone.

Definendo l’opzione header : true ottengo la separazione dei dati della prima riga (le intestazioni delle colonne) dalle altre, quindi avrò in data i dati, in meta.filds i nomi dei campi e in errors gli eventuali errori di parse del file.

La cosa bella e che nell’'oggetto data (che è un array di oggetti) ho i campi e quindi posso puntarli direttamente riga per riga. Questo mi permette di importare CSV che hanno anche più colonne di quelle che mi servono e in qualsiasi ordine.

Nell’esempio di codice si vede anche come trattare campi con nomi con uno spazio in mezzo come “data Nascita”.

  const expectedColumns = ["nome", "cognome", "data Nascita", "codiceFiscale"];
  let pp = new App.Papaparse(app);
  let options = {
    header : true
  };
  let obj = yield pp.parseFile(fileCSV, options);
  // Guardiamo un po' cosa ci restituisce questo parser
  console.log("PG - obj", obj);
  console.log("PG - obj.data", obj.data);
  console.log("PG - obj.errors", obj.errors);
  console.log("PG - obj.meta.fields", obj.meta.fields);
  // Controllo che le colonne che mi aspetto siano presenti nel file CSV
  if (!expectedColumns.every(col => obj.meta.fields.includes(col))) {
    let expectedColumnsMsg = expectedColumns.join("/");
    let messaggio = t("Le colonne del file non sono quelle previste<br>Queste quelle corrette: @col<br>Il file non verrà caricato!", {col : expectedColumnsMsg});
    yield app.popup({
      type : "alert",
      title : "Errore",
      message : messaggio,
      buttons : [{id : 1, text : "Ok"} ]
    });
  }
  else {
    if (obj.errors.length > 0) {
      let errori = obj.errors.join("<br>");
      let messaggio = t("Si sono verificati errori di caricamento del file csv<br>@err<br>Il file non verrà caricato!", {err : errori});
      yield app.popup({
        type : "alert",
        title : "Errore",
        message : messaggio,
        buttons : [{id : 1, text : "Ok"} ]
      });
    }
    else {
      let errori = [];
      yield App.DBInportCSV.beginTransaction(app);
      //
      for (let i = 0; i < obj.data.length; i++) {
        let n = new App.CSVLib.Nominativo(app);
        n.inserted = true;
        n.nome = obj.data[i].nome;
        n.cognome = obj.data[i].cognome;
        n.dataNascita = obj.data[i]["data Nascita"];
        n.codiceFiscale = obj.data[i].codiceFiscale;
        //
        // Salvo sul databse e se ci sono errori li aggiungo all'array errori
  
        if (yield n.save() === false) {
          let errDoc = n.getErrors();
          if (errDoc.length > 0)
            errori.push(errDoc.join("; "));
        }
      }
      // Se non ci sono errorii confermo la transazione
      if (errori.length === 0) {
        yield App.DBInportCSV.commitTransaction(app);
      }
      else {
        // In caso si errori annullo la transazione e mostro a video il problema
        yield App.DBInportCSV.rollbackTransaction(app);
        let messaggio = errori.join("<br>");
        //
        yield app.popup({
          type : "alert",
          title : "Errore",
          message : messaggio,
          buttons : [{id : 1, text : "Ok"} ]
        });
      }
    }
  }
5 Mi Piace

Grazie Paolo, è una funzione che mi sarà molto utile

1 Mi Piace

Ciao Paolo,

ho usato varie volte questa funzione senza problemi.
Adesso la sto usando su un progetto su cui collaboro.
In modalità online nessun problema.
Lanciando l’app in modalità “Anteprima Offline” disinserita, mi dà questo errore:

App.Papaparse is not a constructor nel Rendiconti.EsportaCsv alla riga 6 Stack trace

2025-07-24T08:19:40.294Z - WARN - Caught app exception: App.Papaparse is not a constructor - @ App.Utils.sync (appserver.min.js:11035:10)
@ App.Rendiconti.EsportaCsv (Rendiconti.js:2202:79)
@ App.Utils.sync (appserver.min.js:11035:10)
@ view.IonStdPage.header.navbar.buttons.buttonEsporta.onClick (Rendiconti.js:88:44) - (sender: App.startServerApp, data: {})

Sembrerebbe non funzionare in modalità offline.

Molto strano.

Grazie e Ciao

1 Mi Piace

@piumimarco sai ho fatto una prova con un mio progetto ed anche a me va in errore quindi direi che è un bug perché dovrebbe funzionare anche offline.
Ti consiglio di fare una segnalazione aprendo un ticket di malfunzionamento.