Skip to content
Advertisement

When writing to a json file, the writing isn’t fully overwriting the previous data

I am attempting to take some data from a JSON file, alter that data and overwrite the data of the original file with that new and altered data however when writing back to the file, some old data is being left behind.

My js code for reading, altering, and writing the files are as follows:

const fs = require("fs/promises");

const timeSelectForm = document.getElementById('timeSelectForm');
const textInput = document.getElementById('timeSelectInput');

const activitiesList = document.getElementById('activitiesList');
const addActivity = document.getElementById('addActivity');
let addActivityForm;
let addActivityTextInput;

async function onStart() {
    let saveData;
            
            try {
                await fs.access("./save.json"); // check if the the file exists
            } catch {
                saveData = { selectedTime: "", activityList: [], selectedActivity: "" }; // give saveData default values if the file doesnt exist
            }
        
            if (!saveData) {
                saveData = JSON.parse(await fs.readFile("./save.json", "utf8")); // if the file exists then read the contents of the file and save it to saveData
            }
        
            let activities = saveData.activityList;

            activities.forEach(activity => {
                activitiesList.innerHTML = /*html*/`<li>${activity}</li>` + activitiesList.innerHTML;
            });


            if (saveData.activityList.length == 6) {
                document.getElementById("addActivity").remove();
            }
}


// when timeSelectForm is submitted call async function
timeSelectForm.addEventListener('submit', async function (e) {
    e.preventDefault(); // prevent default page refresh

    let saveData;

    try {
        await fs.access("./save.json"); // check if the the file exists
    } catch {
        saveData = { selectedTime: "", activityList: [], selectedActivity: "" }; // give saveData default values if the file doesnt exist
    }

    if (!saveData) {
        saveData = JSON.parse(await fs.readFile("./save.json", "utf8")); // if the file exists then read the contents of the file and save it to saveData
    }

    let timeInput = textInput.value === '' ? "00:10:00" : textInput.value; // if time input is empty then set time input to 10mins otherwise set time input to textInput.value
    
    saveData.selectedTime = timeInput;

    await fs.writeFile("./save.json", JSON.stringify(saveData, null, 2), 'utf8'); // save data to JSON file

    textInput.value = ''; // clear the text input
});

let addActivityHasClicked = false;

document.body.addEventListener('click', async function (event) {
    if (!addActivityHasClicked && event.target.id == "addActivity") {
        addActivityHasClicked = true;
        event.target.innerHTML = /*html*/`
        <form id="addActivityForm">
            <input type="textInput" id="addActivityInput" placeholder="Activity">
        </form>`; // clear the inner html and put in the form
        addActivityForm = document.getElementById('addActivityForm');
        addActivityInput = document.getElementById('addActivityInput');

        addActivityForm.addEventListener('submit', async function (e) {
            e.preventDefault(); // prevent default page refresh
        
            let saveData;
            
            try {
                await fs.access("./save.json"); // check if the the file exists
            } catch {
                saveData = { selectedTime: "", activityList: [], selectedActivity: "" }; // give saveData default values if the file doesnt exist
            }
        
            if (!saveData) {
                saveData = JSON.parse(await fs.readFile("./save.json", "utf8")); // if the file exists then read the contents of the file and save it to saveData
            }
        
            let activity = addActivityInput.value;

            saveData.activityList.push(activity);
        
            await fs.writeFile("./save.json", JSON.stringify(saveData, null, 2), 'utf8'); // save data to JSON file
        
            if (saveData.activityList.length >= 6) {
                event.target.remove();
            } else {
                event.target.innerHTML = "+"; // clear the inner html and put in the +
                activitiesList.innerHTML = /*html*/`<li>${activity}</li>` + activitiesList.innerHTML
            }
            
            addActivityHasClicked = false;
        });
    }
});

document.body.addEventListener("click", async function (e) {
    if (e.target.tagName == "LI" && e.target.id != "addActivity") {
        hasBeenSelected = true;
        let saveData;
            
        try {
            await fs.access("./save.json"); // check if the the file exists
        } catch {
            saveData = { selectedTime: "", activityList: [], selectedActivity: "" }; // give saveData default values if the file doesnt exist
        }
    
        if (!saveData) {
            saveData = JSON.parse(await fs.readFile("./save.json", "utf8")); // if the file exists then read the contents of the file and save it to saveData
        }

        saveData.selectedActivity = e.target.innerHTML;


        await fs.writeFile("./save.json", JSON.stringify(saveData, null, 2), 'utf8'); // save data to JSON file
        
        const activeElm = document.getElementById("active");
        if (activeElm) {
            activeElm.removeAttribute("id");
        }
        e.target.setAttribute("id","active");
    }
});

document.body.addEventListener("click", async function (e) {
    if (e.target.id == "active") {
        let saveData;
            
        try {
            await fs.access("./save.json"); // check if the the file exists
        } catch {
            saveData = { selectedTime: "", activityList: [], selectedActivity: "" }; // give saveData default values if the file doesnt exist
        }
    
        if (!saveData) {
            saveData = JSON.parse(await fs.readFile("./save.json", "utf8")); // if the file exists then read the contents of the file and save it to saveData
            console.log(saveData);
        }

        saveData.selectedActivity = "null";
        const index = saveData.activityList.indexOf(e.target.innerHTML);
        saveData.activityList.splice(index, 1);
        e.target.remove();

        await fs.writeFile("./save.json", JSON.stringify(saveData, null, 2), 'utf8'); // save data to JSON file

        location.reload();
    }
});

onStart();

I am using electron with this HTML code:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
    <link rel="stylesheet" href="./home.css">
</head>

<body>
    <div class="wrapper">
        <div class="time-select" id="timeSelect">
            <form id="timeSelectForm">
                <input id="timeSelectInput" type="text" pattern="dd:dd:dd" placeholder="00:10:00"
                    oninput="this.value = this.value.replace(/[^0-9.]/g, ':').replace(/(..*?)..*/g, '$1');" />
            </form>
        </div>

        <div class="activity-select">
            <ul id="activitiesList">
                <li id="addActivity">
                    +
                </li>
            </ul>
        </div>
    </div>

    <script src="./home.js"></script>
</body>

</html>

This code is being called when I click on a div and it aims to remove that div from the screen and the JSON file. (e.target is the div I have clicked on)

After running this code and clicking on a div, my JSON file ends up looking like this:

{
  "selectedTime": "12:34:56",
  "activityList": [
    "test5",
    "test6"
  ],
  "selectedActivity": "test4"
}y": "test4"
}

EDIT: (a little more info) I have tested saving the new data to a different file which works fine and does not cause any issues. I have also read the file both in a text editor and inside the console and both give the same messy result.

EDIT 2: After further testing, I have discovered that there is something somewhere else in my js file that is interfering with the saving to the JSON file causing the resultant file to be a big mess. I have now added the full code to my file and am not exactly sure where the issues are and how to prevent them. Any pointers as to this would be much appreciated, thanks! Furthermore, I am using electron meaning I can use the Node.js fsPromises inside of my plain js code so when testing out my code please be mindful of that. Thanks!

Advertisement

Answer

After a lot of testing, I have discovered that when I am checking for a click on any of the LI elements, that is reading to the JSON at the same time as the delete function is writing to the JSON and this leads to a mess up in the JSON file.

In short, when reading and writing from and to a JSON file make sure that you are not doing both at the same time, to troubleshoot I added console.log statements after each read and write and saw that was sending overlapping requests that lead to the messy resultant JSON file.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement