0

I created a note-taking front end page which saves the data from text field into the localStorage. The problem occurs when the user deletes one field using the Delete button, which corresopndents to DeleteT function.

For example if we have three textareas with id txt1, txt2, txt3 they apper with the sames names in the localStorage. After the user deletes for example txt2 using the Delete button, in the local Storage the left ones are txt1 and txt3 but on the next reload there are two textareas with id txt1 and txt2 because in the localStorage the number of textareas is saved by key AllNum. The data from txt3 in the localStorage should go to txt2 in the DOM on the page.

The problematic functions:

// Deletes textelemnt
function DeleteT(num) {
        localStorage.removeItem("txt" + num);
        localStorage.removeItem("h" + num);
        console.log('del');
        i=i-1;
        var now = localStorage.getItem("AllNum");
        if((now-1)<0){
            now=0;
                    localStorage.setItem("AllNum", (0));

        }else{
            localStorage.setItem("AllNum", (now-1));
        }
        $("div.textarea" + num).remove();
    }
//Loads all the text elemnts with a for loop until the number of areas is reached
function load() {
        if (document.getElementById("alltxt").childElementCount < localStorage.getItem('AllNum')) {
            for (var i = 1; i <= localStorage.getItem('AllNum'); i++) {
                $('#alltxt').append('<div class="textarea' + i + '"><input onkeyup="save()" id="h' + i + '"></input><textarea onkeyup="save()" id="txt' + i + '"></textarea></br><button onClick="cut(txt' + i + ')" class="f b">Cut</button>        <button onClick="copy(txt' + i + ')" class="f b">Copy</button>              <button onClick="speak(txt' + i + ')" class="f b">Speak</button>        <button onClick="download(' + i + ')" class="f a">Save</button><button onClick="textFull(' + i + ')" class="f">Fullscreen</button> <button onClick="DeleteT(' + i + ')" class="f">Delete</button> </div>');
                document.getElementById('txt' + i).innerHTML = localStorage.getItem("txt" + i);
                document.getElementById("h" + i).setAttribute('value', localStorage.getItem("h" + i));
            }
        }
    }

https://codepen.io/abooo/pen/NoqOXX?editors=1010

To experience the problem create three textareas using the + button. Then Enter data in the them. After this delete the latter. Finally reload the page and make sure the two textreas appeared. You can see the data from the second one is missing replaced with null value. How to fix this issue?

The result

LocalStorage values

Atanas
  • 83
  • 1
  • 1
  • 11

1 Answers1

2

The value "AllNum" only stores total number of items; it does not contain any information about which items were there before reloading. So in first load, if you add 3 items and remove the 2nd, your local storage will have "AllNum" equal 2, and the next time it loads, your load() function will iterate from 1 to 2, looking for data of text1 and text2. That's why only 1st item displays correctly.

Another problem that you might notice after fixing the above issue is that the iteration is not good for unique id; a simple test can prove it: you add 3 items, remove the 2nd - now you have text1 and text3 in localStorage, and AllNum is 2. If you add one more, the newest item will have id as 3 and all its data will be written on top of the existing text3 and h3.

2 suggestion for your code:

  • Use something else as unique id instead of iteration number. Use Math.random(), for example.
  • Store all your unique ids in localStorage, not AllNum. Rewrite your code to add and delete unique ids from localStorage.

A small example of how to modify the 2 function add() and save():

function add() {
        var newId = Math.random();
        // your render logic here. Replace i with newId
        save(newId);
    }

    function save(newId) {
        localStorage.setItem("txt" + newId, document.getElementById('txt' + a).value);
        localStorage.setItem("h" + newId, document.getElementById('h' + a).value);
        var allIds = JSON.parse(localStorage.getItem('AllIds'));
        allIds.push(newId);
        localStorage.setItem("AllIds", JSON.stringify(allIds));
    }
blaz
  • 3,981
  • 22
  • 37
  • How can I use Math.random() to associate localStorage data with visual elements? – Atanas Jan 24 '19 at 08:59
  • Thanks for the help. After implementing your code I faced a weird error. Do you know how to fix it? **Uncaught TypeError: Cannot read property 'push' of null** https://codepen.io/abooo/pen/MLwxeN?editors=0010 – Atanas Jan 24 '19 at 09:56
  • @Atanas `AllIds` is empty in localStorage at the first page load. You can perform a check at page load and initialize it with `JSON.stringify([])` – blaz Jan 24 '19 at 10:02
  • I have never used JSON before so please excuse me for my question. **if(localStorage.getItem('AllIds')==null){ JSON.stringify(localStorage.setItem("AllIds","()")); }** This code seems to not establish a value. – Atanas Jan 24 '19 at 10:24
  • @Atanas No you don't store JSON. Again, look into my code, I convert an array to string and store it. – blaz Jan 24 '19 at 10:29
  • Thanks, based on this answer https://stackoverflow.com/a/3357615/10945792 I made the conclusion that I must use some combinaion of localStorage and JSON. **if(localStorage.getItem('AllIds')==null){ localStorage.setItem("AllIds", JSON.stringify(allIds)); var allIds = JSON.parse(localStorage.getItem('AllIds')); }** This code should put the array into localStorage, right? Sorry in advance for my question. – Atanas Jan 24 '19 at 11:24
  • @Atanas localStorage only store string, so JSON.stringify is used to convert allIds to string – blaz Jan 25 '19 at 03:22