19
votes

Some while ago I started learning Vue.js and a short while after, I started a bigger project, not keeping in mind, that Javascript has limited options to interact with the local file system. I set up the project via vue-cli, so I have to start the website via npm start.

Said project consist of a visual editor for JSON Files. When I wanted to implement the save button, I recognized that it's a quite difficult task to make is write/save (and maybe read in the future) a JSON file to my local machine.

I already tried using node's fs library, thinking it would work, because it is launched with node. I also tried several external libraries e.g. the write-json-file npm lib.

I'm getting to a point where I'm out of ideas and would do pretty much anything thats necessary to make it work.

2
Well to interact with the file system you most likely would need some node server. Like using express or some kind of webserver, with which you could then communicate from your vue.js webapprsz
Are you going to use server side or client side generate json and write to local?yue you
The json data will be created "live" and stored in a vuex store. There will never be a "real" server side, for this should be like a windows application and never be accessed via the internet. I know it's quite odd to use javascript for something like this, but the specifications for this were a webbased project.Phero
I think if using browser env you can only either create a blob to download or write to local storage or IndexDB. I can share you a example I have done if it will help. But as your description you wanna implement something like VSCode or Atom. For your usecase, you can try to look at Electronyue you
A download button seems like a feasible option, if its not that complicated :) I know that there are alternatives, but it's more of an educational project in the scope of my university than a real life usecase. An example would be nicePhero

2 Answers

40
votes

There are 3 ways to do this.

  1. Write to local storage

  2. Create a Blob and invoke an event to download it

  3. Wrap it into a electron app and use node fs module to save file

I can show you a sample here for these 3 cases

index.html

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Vue test</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
</head>
<body>
<div id="vue-app">
    <form>
        <input type="text" v-model="name"/>{{name}}<br/>
        <input type="text" v-model="last"/>{{last}}<br/>
        <input type="text" v-model="index"/>{{index}}<br/>
        <select v-model="grade">
            <option>5</option>
            <option>6</option>
            <option>7</option>
            <option>8</option>
            <option>9</option>
            <option>10</option>
        </select>
        {{grade}}
        <button type="button" v-on:click="add()">Add To Table</button>
        <button type="button" v-on:click="saveFile()">saveFile</button>
    </form>
    <table border="1">
        <thead><td>Name</td><td>Last Name</td><td>Index</td><td>Grade</td></thead>
        <tbody>
        <tr v-for="x in arr">
            <td>{{x.first}}</td>
            <td>{{x.lastn}}</td>
            <td>{{x.index}}</td>
            <td>{{x.grade}}</td>
        </tr>
        </tbody>
    </table>
</div>
<script src="test.js"></script>
</body>
</html>

test.js (Write to local storage)

new Vue ({
  el: '#vue-app',
  data: {
      name: '',
      last: '',
      index: 0,
      grade: 0,
      arr: []
  },

  methods: {
      add: function (e) {
          this.arr.push({first: this.name, lastn: this.last, index: this.index, grade: this.grade});
          console.log(1);
      },
      saveFile: function() {
        const data = JSON.stringify(this.arr)
        window.localStorage.setItem('arr', data);
        console.log(JSON.parse(window.localStorage.getItem('arr')))
  }
});

Create a Blob and invoke a event to download it

only change for saveFile func

saveFile: function() {
    const data = JSON.stringify(this.arr)
    const blob = new Blob([data], {type: 'text/plain'})
    const e = document.createEvent('MouseEvents'),
    a = document.createElement('a');
    a.download = "test.json";
    a.href = window.URL.createObjectURL(blob);
    a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
    e.initEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    a.dispatchEvent(e);
}

Wrap it into an Electron app and use node fs module to save file

Change for saveFile func

saveFile: function() {
    const data = JSON.stringify(this.arr)
    const fs = require('fs');
    try { fs.writeFileSync('myfile.txt', data, 'utf-8'); }
    catch(e) { alert('Failed to save the file !'); }
}

Then use Electron to wrap it

electron ./index.html

0
votes

This is how I edit JSON files in my Vue projects. In this case, if you run the file, it will create a new data.json file and add Price to each JSON object:

const fs = require("fs");

let cars = [
  {
    Name: "chevrolet chevelle malibu",
    Miles_per_Gallon: 18,
    Cylinders: 8,
    Displacement: 307,
    Horsepower: 130,
    Weight_in_lbs: 3504,
    Acceleration: 12,
    Year: "1970-01-01",
    Origin: "USA"
  },
  {
    Name: "buick skylark 320",
    Miles_per_Gallon: 15,
    Cylinders: 8,
    Displacement: 350,
    Horsepower: 165,
    Weight_in_lbs: 3693,
    Acceleration: 11.5,
    Year: "1970-01-01",
    Origin: "USA"
  }
];
cars.forEach(car => {
  car.price = 12000;
});

let data = JSON.stringify(cars);
fs.writeFileSync("data.json", data);