Help us understand the problem. What is going on with this article?

Vue.jsでCSVをインポート

結構記事があるので余裕だと思ったら躓きまくったので残しておこうと思います.

目指すもの

Image from Gyazo

CSVファイルをドラッグアンドドロップ もしくは 選択してアップロードして, そのCSVファイルを自由に読み取れるようにするまでです.

簡単な流れを説明すると

ファイルアップロード => パース => dataにぶちこむ => 表示

といった感じです.

[f:id:ustrgm:20181223003622p:plain]

script

vueファイルのCSVを読み込む部分はこんな感じになってます.

CSV.vue
<script>
export default {
  data: function() {
    return {
      // CSVファイルのヘッダー部を定義しておきます
      headers: [
        {
          text: "Code",
          align: "left",
          sortable: false,
          value: "code"
        },
        { text: "Name", align: "left", value: "name" },
        { text: "WorkerType", align: "left", value: "workerType" }
      ],
      workers: []
    };
  },
  methods: {
    fileChange: function(e) {
      const file = e.target.files[0];
      const reader = new FileReader();
      const workers = [];

      const loadFunc = () => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

      // onloadはreadAsBinaryStringでファイルを読み込んだ後に実行されます.
      reader.onload = loadFunc;

      reader.readAsBinaryString(file);
    }
  }
};
</script>

うまくいかないパターン

最初以下のように書いてました

      // onloadはreadAsBinaryStringでファイルを読み込んだ後に実行されます.
      reader.onload =() => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

これで行けそうな気がしたのですが, this がFileReaderを指すためうまくいきません.

workersとかも更新されません.

上記のように関数を作っておいてそれを渡すようにします.

ちなみにスコープ外の値を操作するのに作成する関数をクロージャといいます.クロージャ

躓いたのはここだけでしたが, ほとんど記事はonloadに直接関数を入れ込んでいるのでthisを使って値を変えようとする場合はうまくいかないです.

また, ローカル変数を作って最後に代入しているのは, 配列のpush関数を使っても再レンダリングがおこらないためです. (値そのものを書き換えるときにsetterが呼ばれ, vueは再レンダリングします)

全体

vuetifyを使ってますがこんな感じにテーブルにして表現することができます.

CSV.vue
<template>
  <div>
    <h1>CAVインポート</h1>
    <input @change="fileChange" type="file" id="file_input_expense" name="file_input_expense">
    <v-data-table :headers="headers" :items="workers" class="elevation-1">
      <template slot="items" slot-scope="props">
        <td class="text-xs-right">{{ props.item.code }}</td>
        <td class="text-xs-right">{{ props.item.name }}</td>
        <td class="text-xs-right">{{ props.item.workerType }}</td>
      </template>
    </v-data-table>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      headers: [
        {
          text: "Code",
          align: "left",
          sortable: false,
          value: "code"
        },
        { text: "Name", align: "left", value: "name" },
        { text: "WorkerType", align: "left", value: "workerType" }
      ],
      workers: []
    };
  },
  methods: {
    fileChange: function(e) {
      const file = e.target.files[0];
      const reader = new FileReader();
      const workers = [];

      const loadFunc = () => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

      reader.onload = loadFunc;

      reader.readAsBinaryString(file);
    }
  }
};
</script>

まとめ

vueというよりほぼJSでしたがこれでCSV読み込んで色々できます!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away