How to read back data from LocalStorage - javascript

Once checkbox is active there are various <p> tags that get class "result". What I do with them is following:
function submit(){
alert("in submit");
var user_choice = document.getElementsByClassName("result");
for (var i = 0; i < user_choice.length; i++){
console.log(user_choice[i].innerHTML);
}
localStorage.setItem('storage',user_choice);
}
I hope this makes an HTMLcollection. After that, at submitted.html page (redirect there after pressing submit button) I wanna console.log all the items. So I write this:
window.onload = function() {
if ( localStorage.getItem('storage')) {
var got_user_choice = localStorage.getItem('storage');
for (var i = 0; i < got_user_choice.length; i++){
console.log(got_user_choice[i].innerHTML);
}
}
}
As long as it's a HTMLcollection (read array) I operate with it in terms of array. But what I get in console is just undefined. What's wrong with my code?

Local storage can only contain strings, not DOM elements. You should make an array of all the elements, and convert that to JSON.
function submit(){
alert("in submit");
var user_choice = document.getElementsByClassName("result");
var html = [];
for (var i = 0; i < user_choice.length; i++){
console.log(user_choice[i].innerHTML);
html.push(user_choice[i].innerHTML);
}
localStorage.setItem('storage',JSON.stringify(html));
}

Related

Printing List to DOM from array in Local Storage

I feel like I am very close on this.
Have a checklist which I'm pushing to an array, and setting to local storage. I want to reprint the list from local storage when the browser is re-instantiated
<script>
localStorage.clear();
var Array_ToDoList = [];
var toDoCount = 0;
$("#add-to-do").on("click", function(event) {
event.preventDefault();
var toDoTask = $("#to-do").val().trim();
Array_ToDoList.push(toDoTask)
localStorage.setItem("STR_Tasks", JSON.stringify(Array_ToDoList))
console.log(Array_ToDoList);
var toDoItem = $("<p>");
toDoItem.attr("id", "item-" + toDoCount);
toDoItem.append(" " + toDoTask);
var toDoClose = $("<button>");
toDoClose.attr("data-to-do", toDoCount);
toDoClose.addClass("checkbox");
toDoClose.append("✓");
toDoItem = toDoItem.prepend(toDoClose);
$("#to-dos").append(toDoItem);
$("#to-do").val("");
toDoCount++;
});
$(document.body).on("click", ".checkbox", function() {
var toDoNumber = $(this).attr("data-to-do");
$("#item-" + toDoNumber).remove();
Array_ToDoList.splice(toDoNumber, 1);
console.log(Array_ToDoList);
localStorage.setItem("STR_Tasks", JSON.stringify(Array_ToDoList))
});
var StoredToDos = Array_ToDoList.length;
for (var i = 0; i < StoredToDos; i++) {
$("#to-dos").append(localStorage.getitem(STR_Tasks[i]));
}
</script>
I know that I have to read the array and reprint, it may be something to with de-stringifying what I have in store.
according to my understanding on the literally code:
it's 'localStorage.getItem' not 'getitem'
the key store in localStorage was "STR_Tasks", it's just string, not iterable type
i think you should push the object 'todoItem' into 'Array_ToDoList', then 'JSON.stringify' it then storge into the localStorage
at last, you can do like this:
var tasks = JSON.parse(localStorage.getItem("STR_Tasks"));
for (var i = 0; i < StoredToDos; i++) {
$("#to-dos").append(tasks[i]);
}
In the first line of the script you clear all the keys in the local storage so you can not use the previous list instead replace localStorage.clear() with :
var Array_ToDoList = JSON.parse(localStorage.getItem('STR_Tasks') || '[]');
This will make your script use the currently saved STR_Tasks.

How to clear innerHTML of spans

I have a basic form in html, when user leave blank fields I show a message in spans that I created via javascript, so far so good. But if I click 'submit' button again and again, the messages are printed again and again Above the message that has already been printed, I mean overlapping.
I tried the element.innerHTML = ''; and this. Maybe I'm implementing it badly since it does not work.
var myForm = document.getElementsByTagName('form')[0];
var formFields = document.getElementsByTagName('label');
myForm.addEventListener('submit', function(){
event.preventDefault();
var statusMessageHTML = [];
// create empty spans
for(i = 0; i < formFields.length; i++){
statusMessageHTML[i] = document.createElement('span');
statusMessageHTML[i].className = 'status-field-message';
formFields[i].appendChild(statusMessageHTML[i]);
}
// print a string in empty spans
for(i = 0; i < formFields.length; i++){
statusMessageHTML[i].innerHTML = "Error Message"
}
return false;
});
PD: I want to solve this using pure javascript.
CODEPEN
To prevent this, you can create and append those spans in advance, and just modify their text when the submit button is clicked.
For example, rearrange your code as following:
var myForm = document.getElementsByTagName('form')[0];
var formFields = document.getElementsByTagName('label');
// create empty spans in advance
var statusMessageHTML = [];
for(var i = 0; i < formFields.length; i++) {
statusMessageHTML[i] = document.createElement('span');
statusMessageHTML[i].className = 'status-field-message';
formFields[i].appendChild(statusMessageHTML[i]);
}
myForm.addEventListener('submit', function(event) {
event.preventDefault();
// change the text of spans
for(var i = 0; i < formFields.length; i++)
statusMessageHTML[i].textContent = 'Error Message';
});
Note:
You have to include corresponding variable name (i.e., event) in the function's parameters before using it.
span.textContent may be preferable to span.innerHTML in your case.
It is pointless to return a value in the addEventListener's callback function. The returned value is simply discarded.
It is a good practice to declare all variables (e.g., i) before using them.
You can also construct those spans directly in HTML, since they are kind of "static" in the structure.
Updated
If I understand it correctly, you prefer:
Create those spans as placeholders when it is the first time the user submits.
Rewrite values in spans when the response of the ajax request is received.
If the submit button is clicked multiple times, just clear previous values in spans, and the following process remains the same.
Then I believe you just need to wrap the whole part in a if-else block:
var myForm = document.getElementsByTagName('form')[0];
var formFields = document.getElementsByTagName('label');
var statusMessageHTML = [];
var isFirstSubmit = true;
myForm.addEventListener('submit', function(event) {
event.preventDefault();
if(isFirstSubmit) {
// create empty spans
for(var i = 0; i < formFields.length; i++) {
statusMessageHTML[i] = document.createElement('span');
statusMessageHTML[i].className = 'status-field-message';
formFields[i].appendChild(statusMessageHTML[i]);
}
isFirstSubmit = false;
} else {
// clear previous values
for(var i = 0; i < formFields.length; i++)
statusMessageHTML[i].textContent = '';
}
});
And rewrite the values when you get the response (possibly wrapped in a callback function, since it is an AJAX request):
function callback(response) {
for(var i = 0; i < formFields.length; i++)
statusMessageHTML[i].textContent = /*values in response*/;
}

Javascript HTML include results in duplicate includes in random places

This problem has me absolutely stumped. I'm trying to include HTML snippets with Javascript and it works, but for some reason it decides to also include duplicate snippets in various other locations.
Here is a screenshot of what I mean:
It also varies the number and location of these random includes.
This is the function I use to include. It searches through the document and finds div elements with the attribute include="x.html"
function include() {
var allElements;
var fileName;
var includeRequest;
allElements = document.getElementsByTagName("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].getAttribute("include")) {
fileName = allElements[i].getAttribute("include");
includeRequest = new XMLHttpRequest();
includeRequest.open("GET", fileName, true);
includeRequest.onreadystatechange = function() {
if (includeRequest.readyState == 4 && includeRequest.status == 200) {
allElements[i].removeAttribute("include");
allElements[i].innerHTML = includeRequest.responseText;
include();
delete includeRequest;
includeRequest = null;
}
}
includeRequest.send();
return;
}
}
}
This is the function that gets tags from an html file containing articles, and adds them to the list of tags in the box on the right. As you can see, in one place the footer is added to the list instead of the tag. I don't know why.
function getTags() {
var taglist = document.getElementById("taglist");
var tagsRequest = new XMLHttpRequest();
tagsRequest.open("GET", "blogstubs.html", true);
tagsRequest.responseType = "document";
tagsRequest.onreadystatechange = function() {
if (tagsRequest.readyState == 4 && tagsRequest.status == 200) {
var tagsResponse = tagsRequest.responseXML;
var tags = tagsResponse.getElementsByClassName("tag");
var tags = getUnique(tags);
var len = tags.length;
for (var i = 0; i < len; i++) {
var li = document.createElement("li");
li.appendChild(tags[i]);
taglist.appendChild(li);
}
delete tagsRequest;
tagsRequest = null;
}
}
tagsRequest.send();
}
Javascript only solution please. Ideas?
I copied your website (I hope you don't mind) and tested it with my changes, it seems to be working now without this bug. Here's what I did:
1) I created a new function, don't forget to change the name to whatever you prefer:
function newFunction(allElements, includeRequest) {
allElements.removeAttribute("include");
allElements.innerHTML = includeRequest.responseText;
include();
delete includeRequest;
includeRequest = null;
}
2) I changed the include() function to look like this:
function include() {
var allElements;
var fileName;
var includeRequest;
allElements = document.getElementsByTagName("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].getAttribute("include")) {
var element = allElements[i];
fileName = element.getAttribute("include");
includeRequest = new XMLHttpRequest();
includeRequest.open("GET", fileName, true);
includeRequest.onreadystatechange = function() {
if (includeRequest.readyState == 4 && includeRequest.status == 200) {
return newFunction(element, includeRequest);
}
}
includeRequest.send();
return;
}
}
}
I think the problem was caused by async nature of AJAX requests, like I said in the comment. So you need to pass the variables to your AJAX call instead of using the global scope, that's why you need this new callback function.
In other words, in the original code the AJAX variable allElements[i] wasn't in sync with your loop's allElements[i], so while in your loop it would be 5, in AJAX function (which executed separately and not in order with the loop) it would be 3, 6 or whatever else. That is why it would append the html to the element that seems random. Think of AJAX as of someone who doesn't care about the order of your loops, someone who really doesn't like to wait while someone else is counting and does everything in his own order.

Extending a google spreadsheet into a google web app

I was coding using the google scripts, when I came across a problem I've been struggling with for a couple days now. I am using Code.gs (a default page in creating a web app in google), when I called in data from a google spreadsheet to try and display it on a webpage. I had no problems with calling in the data add storing it into a array but now I am struggling with trying to return it to my javascript code. Can this be done or is there something else I can do to fix it? My code is below.
function getContents()
{
var sheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xum5t4a83CjoU4EfGd50f4ef885F00d0erAvUYX0JAU/edit#gid=0&vpid=A1');
var range = sheet.getDataRange();
var values = range.getValues();
for (var i = 0; i < values.length; i++) {
var education = [];
for (var j = 0; j < values[i].length; j++) {
if (values[i][j]) {
if(j==1){
education[education.length] = values[i][j];
}
}
}
}
Logger.log(education);
return education;
}
From that Code.gs code i want it to return it to a Javascript function that says this:
function onNew(){
var input = google.script.run.getContents();
for(var = 0; i<input.length; i++)
{
$("#main").append("<div id='class'>"+input[i]+"</div>);
}
}
and whenever I try to run it says that it causes an error because it is undefined. Thanks in advance! Anything helps!
You need to use the withSuccessHandler(). Your variable input will not receive the return from google.script.run.getContents()
Separate out the client side code into two functions:
HTML Script
function onNew() {
google.script.run
.withSuccessHandler(appendEducationHTML)
.getContents();
};
function appendEducationHTML(returnedInfo) {
console.log('returnedInfo type is: ' + typeof returnedInfo);
console.log('returnedInfo: ' + returnedInfo);
//If return is a string. Convert it back into an array
//returnedInfo = returnedInfo.split(",");
for (var = 0;i < returnedInfo.length; i++) {
$("#main").append("<div id='class'>"+returnedInfo[i]+"</div>);
};
};

HTML rendering before for-loop finishes executing, only first item in for-loop showing

I am trying to render an html page that contains all of the posts that a user has received. Right now the issue I am having (shown under Way 1) is that when I call the function renderPosts after the web socket is received, only the first post in the array is rendered (the array has more than one post in it).
On the other hand, Way 2 in which I have no for loop and instead manually render each post works in that all four posts are rendered. But I need to be able to work with an arbitrary number of posts which is why I need to use the for loop.
I am using socket.io and javascript.
Way 1:
socket.on('postsToRender', function(arrayOfPostsToRender) {
renderPosts(arrayOfPostsToRender);
});
function renderPosts(arrayOfPostsToRender) {
for (var index = 0; index < arrayOfPostsToRender.length; index++) {
renderPost(arrayOfPostsToRender[index]);
}
}
function renderPost(postToRender) {
var feed = document.getElementById("feed");
var postContent = document.createTextNode(postToRender.content);
var post = document.createElement("div");
post.appendChild(postContent);
feed.appendChild(post);
}
Way 2:
socket.on('postsToRender', function(arrayOfPostsToRender) {
renderPost(arrayOfPostsToRender[0]);
renderPost(arrayOfPostsToRender[1]);
renderPost(arrayOfPostsToRender[2]);
renderPost(arrayOfPostsToRender[3]);
});
function renderPost(postToRender) {
var feed = document.getElementById("feed");
var postContent = document.createTextNode(postToRender.content);
var post = document.createElement("div");
post.appendChild(postContent);
feed.appendChild(post);
}
Try this:
function renderPosts(arrayOfPostsToRender) {
for (var index = 0; index < arrayOfPostsToRender.length; index++) {
(function(i){
renderPost(arrayOfPostsToRender[i]);
})(index);
}
}

Categories

Resources