32

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.

9
  • 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 webapp Commented Feb 4, 2018 at 18:39
  • Are you going to use server side or client side generate json and write to local? Commented Feb 4, 2018 at 18:42
  • 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. Commented Feb 4, 2018 at 18:49
  • 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 Electron Commented Feb 4, 2018 at 19:08
  • 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 nice Commented Feb 4, 2018 at 19:09

2 Answers 2

63

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

Sign up to request clarification or add additional context in comments.

6 Comments

Glad that I can help you. If possible just accept my answer
Maybe pedantic, but why go through all the trouble of creating a link element and then triggering a click on it, when it's just as easy to trigger the download without it. Solution seems really fragile.
@Hybridwebdev You can also use this lib to save the file. github.com/eligrey/FileSaver.js/edit/master/src/FileSaver.js. It is using a.href and click event as well. Or you can use the download API but it is not supported by Edge developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/…
could you please explain how to wrap with electron? i have no idea about electron. i want to write a crud code generator for vue js like yii2 gii but i have no idea to create a directory or generate files to local project with vue and js
Making an electron app for the sole purpose of allowing the user to download something seems like serious overkill to me.
|
0

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);

2 Comments

I get the error fs.writeFileSync is not a function.
You can't use fs in the browser. The browser does not have direct access to the file system. This is why the error is thrown. The function doesn't exist in the browser. Yavor's solution is not a VueJS solution, this is probably backend code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.