localStorage save HTML Clone - javascript

I want to use the localStorage to save an Object which contains HTML-Clones.
var myObject["test"] = document.getElementByID("someElement").cloneNode(true);
myObject["test2"] = document.getElementByID("someOtherElement").cloneNode(true);
localStorage.saveObject = JSON.stringify(myObject);
But the Object saveObject still equals {}. It seems, that stringify can't stringify an HTML Node and if, in any way, I happen to solve the problem to save it, is it possible to parse this Object back to an HTML node?
Someone knows a solution?

Your node references will be removed from the stringified object because JSON, by definition, cannot contain functions or node references - only primitives or sub-arrays/objects. In other words, there's no way you can keep references to nodes in your local storage. You would instead need to log references to them by ID, class or some other means.
[EDIT, in response to OP's comment]
JSON and JS objects are not the same thing. The former is derived from the latter, but they are not the same. JSON is a storage means, and so cannot contain references to anything dynamic. HTML elements do not exist permanently; they exist as runtime (DOM) concepts that disappear once the page is left. Thus, they cannot be stored in any meaningful way.
JSON is therefore able to store only primitive data - strings, numbers and booleans - along with structures that allow it to nest - arrays and sub-JSON definitions.
So what happens when you run stringify on your object is the unsuitable parts are stripped out. In your case, that's both properties. So instead, you need to store references to the elements in a more permanent, revisitable format - by ID or class, or some other reminder mechanism.
var obj = {el1: '#some_element', el2: '.some_other_element'};
localStorage.saveObject = JSON.stringify(obj);
There I save my two elements as references to their IDs (first) and class (second).
Then, when you come to reload your local storage, you look up the elements based on those factors, by feeding them, for example, to a jQuery selector.

One workaround is to:
Get the outerHTML of the node you want to clone
Store the outerHTML (a string) in local storage.
On load create a new element, append it to the document.
Assign the outerHTML saved in your localstorage to the new element.
Quick example:
window.saveArray = new Array();
var clone = document.getElementByID("someElement").cloneNode(true);
saveArray.push(clone.outerHTML);
function save(){
localStorage["elements"] = JSON.stringify(saveArray);
}
function load(){
var tempsave = JSON.parse(localStorage["elements"]);
for (var i = 0; i < tempsave.length; i++){
var element = document.createElement('div');
document.getElementById('element-container').appendChild(element);
element.outerHTML = tempsave[i];
}
}

To save an HTML node as string you can use XMLSerializer.
var node = document.getElementByID("elementID");
var serializer = new XMLSerializer();
var htmlStr = serializer.serializeToString(node);
localStorage.setItem("saved", htmlStr);
Now you can set it as innerHTML of a node.
document.getElementById("elementContainerID").innerHTML = localStorage.getItem("saved");
Notice! If you are copying input elements that have been given new values, they will not be saved. As the node will be copied with the value attribute inputElement.getAttribute("value") and not with the new given one inputElement.value. To work around this, you may copy all input values to the value attribute before you serializer the node.
document.querySelectorAll("input").forEach((el) => el.setAttribute("value", el.value));

Related

How do I return an image source as a string?

I'm trying to turn an image source into a string so I can run substring() on it. I used the following JavaScript to get the source:
function ShowQuizAnswers(quiz) {
var QuizImage = document.getElementById(quiz);
var ImageType = QuizImage.attributes.src;
console.log(ImageType);
}
Of course, as I soon found out, this returned an object instead of a string. I tried running .toString() on the ImageType variable, but that didn't work. Is there something I'm missing?
Use Element#getAttribute or directly get src property from dom object.
function ShowQuizAnswers(quiz) {
var QuizImage = document.getElementById(quiz);
var ImageType = QuizImage.src;
console.log(ImageType);
}
or
function ShowQuizAnswers(quiz) {
var QuizImage = document.getElementById(quiz);
var ImageType = QuizImage.getAttribute('src');
console.log(ImageType);
}
FYI : The attributes is an array like structure(NamedNodeMap). It actually helps to iterate over all attributes an element, but you can't access the attribute directly from it.
From the MDN docs:
The Element.attributes property returns a live collection of all attribute nodes registered to the specified node. It is a NamedNodeMap, not an Array, so it has no Array methods and the Attr nodes' indexes may differ among browsers. To be more specific, attributes is a key/value pair of strings that represents any information regarding that attribute.
Try:
const imageURL = document.getElementById(quiz).src

Replacing Object keyname in an Object reports "is not a function" error

This answer how to change json object name (key)?
provides a method of replace a name/key in a JSON object but I am running into problems getting it to work.
I am obtaining some fields from a library, such as getColumnTitle etc that have numbers appended that identify which column the Title comes from. Because I need the values associated with a row and have a unique column grouping identifier, the appened numbers cause difficulty at the server side. hence I need to remove the numeric suffix or appended numeric value.
This is what I am trying to do with the code below, however I get a
TypeError: getTaskCellData.remove is not a function
error.
Here is the code.
var getColumnTitle = "hour231";
var getTaskCellData = {"hour231":23,"name":"hello world","other":"fields"};
var alphaTitle = getColumnTitle.replace(/[0-9]/g, '');
getTaskCellData.put(alphaTitle, getTaskCellData.remove(getColumnTitle));
console.log(getTaskCellData)
The answer you linked to is for JAVA, not JavaScript... An object literal, as you have it stored in getTaskCellData, doesn't have remove on its prototype, so you can't use that. Personally I don't think it's worth the code to rename an object's property, simply add a new property holding the same value. If you really insist on renaming, you can do the same and additionally use delete.
var getColumnTitle = "hour231";
var getTaskCellData = {"hour231":23,"name":"hello world","other":"fields"};
var alphaTitle = getColumnTitle.replace(/[0-9]/g, '');
getTaskCellData[alphaTitle] = getTaskCellData[getColumnTitle];
delete getTaskCellData[getColumnTitle];
console.log(getTaskCellData)

What is a good way to create a JavaScript array with big indices?

I'm making a web app where a user gets data from PHP, and the data consists of MySQL rows, so I want to save the used ones in a global variable, something like a buffer, to prevent extra AJAX requests.
I'm doing this right now :
window.ray = []; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
but when the id is big, say 10 for now, window.ray becomes this :
,,,,,,,,42
so it contains 9 unnecessary spots. Or does it? Is it only visible when I'm doing console.log(window.ray);
If this is inefficient, I want to find a way like PHP, where I can assign only indices that I want, like :
$array['420'] = "abc";
$array['999'] = "xyz";
Is my current way as efficient as PHP, or does it actually contain unnecessary memory spots?
Thanks for any help !
Use an object instead of an array. The object will let you use the id as the key and be more efficient for non-sequential id values.
window.ray = {}; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
You can then access any element by the id:
var text = window.ray[myId];
If you are assigning values directly by property name, then it doesn't make any difference in terms of performance whether you use an Array or an Object. The property names of Arrays are strings, just like Objects.
In the following:
var a = [];
a[1000] = 'foo';
then a is (a reference to) an array with length 1,001 (always at least one greater than the highest index) but it only has one numeric member, the one called '1000', there aren't 1,000 other empty members, e.g.:
a.hasOwnProperty['999']; // false
Arrays are just Objects with a special, self–adjusting length property and some mostly generic methods that can be applied to any suitable object.
One feature of sparse arrays (i.e. where the numeric properties from 0 to length aren't contiguous) is that a for loop will loop over every value, including the missing ones. That can be avoided and significant performance gains realised by using a for..in loop and using a hasOwnProperty test, just like an Object.
But if you aren't going to use any of the special features of an Array, you might as well just use an Object as suggested by jfriend00.

jQuery parsing html into JSON

I am currently using the following code:
jQuery('#book-a-service').click(function(){
var selectedServices = jQuery('.selected').parent().parent().html();
console.log(selectedServices);
});
and that returns:
<td rowspan="3">Brakes</td>
<td class="service-title">BRAKES SET</td>
<td class="service-description"><p>Setting of front and rear brakes for proper functioning (excluding bleeding)</p></td>
<td class="service-price">R <span id="price-brakes-set">R75</span><div id="select-brakes-set" class="select-service selected"></div>
</td>
which is what i want, except i need an array of all the elements with '.selected' class in JSON.. i just want to know how i could almost parse it in a way that i only get the contents of the td tags and as for the "service-price" only the numeric value and then how would i insert those values into a json object?
Any Help Greatly Appreciated..
jQuery is not my most formidable frameworks, but this seems to do the trick.
jQuery('#book-a-service').click(function(){
var selected = jQuery('.selected');
selected.each( function() {
var children = jQuery(this).parent().parent().find('td');
var json = {};
console.log(children);
json.type = jQuery(children[0]).text();
json.title = jQuery(children[1]).text();
json.description = jQuery(children[2]).find('p').text();
json.price = jQuery(children[3]).find('span#price-brakes-set').text();
console.log(json);
console.log(JSON.stringify(json));
});
});
in action: http://jsfiddle.net/3n1gm4/DmYbb/
When various elements share the same class and you select them with $(".class"), you can iterate through all of them using:
$(".selected").each(function() {
var element = $(this); // This is the object with class "selected" being used in this iteration
var absoluteParent = $(this).parent().parent();
// Do whatever you want...
var title_element = $(".service-title", absoluteParent); // Get service-title class elements in the context provided by "absoluteParent", I mean, "inside" of absoluteParent
var title = title_element.html();
});
In the specific case of prices, I don't know exactly what is the price (probably R75?). Anyway, it should be inside a div and then select that div to obtain the price. If it is R75, then note that the "id" property should be unique for every DOM object in your HTML.
Also note that, when getting HTML, you're only getting a string, not the actual element, so it will probably not be useful for getting new values in an easy way (you won't be able to navigate through DOM elements with an ordinary string, even if it represents HTML from an actual object). Always get jQuery objects and work with them, unless you actually need the HTML.
For generating a JSON string, just create a global array and add the objects/values you need there. Then you can obtain a JSON string using var jsonText = JSON.stringify(your_array);
Consider not doing this in Javascript, as it's not useful in the majority of cases. Just send the values through POST value to a script (PHP, for example) and in the PHP you will get the actual value. The other way (PHP to Javascript) will be useful to return JSON (using json_encode($a_php_array)) and then, in Javascript, transform to a JS array using var my_array = JSON.parse(the_string_returned_by_php);.

Javascript pushing objects into array changes entire array

I'm using a specific game making framework but I think the question applies to javascript
I was trying to make a narration script so the player can see "The orc hits you." at the bottom of his screen. I wanted to show the last 4 messages at one time and possibly allow the player to look back to see 30-50 messages in a log if they want. To do this I set up and object and an array to push the objects into.
So I set up some variables like this initially...
servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),
and when I use this command (below) multiple times with different data called by an event by manipulating servermessage.color1 ... .message1 etc...
servermessagelist.push(servermessage)
it overwrites the entire array with copies of that data... any idea why or what I can do about it.
So if I push color1 "RED" and message1 "Rover".. the data is correct then if I push
color1"yellow" and message1 "Bus" the data is two copies of .color1:"yellow" .message1:"Bus"
When you push servermessage into servermessagelist you're really (more or less) pushing a reference to that object. So any changes made to servermessage are reflected everywhere you have a reference to it. It sounds like what you want to do is push a clone of the object into the list.
Declare a function as follows:
function cloneMessage(servermessage) {
var clone ={};
for( var key in servermessage ){
if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
clone[key]=servermessage[key];
}
return clone;
}
Then everytime you want to push a message into the list do:
servermessagelist.push( cloneMessage(servermessage) );
When you add the object to the array, it's only a reference to the object that is added. The object is not copied by adding it to the array. So, when you later change the object and add it to the array again, you just have an array with several references to the same object.
Create a new object for each addition to the array:
servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);
There are two ways to use deep copy the object before pushing it into the array.
1. create new object by object method and then push it.
servermessagelist = [];
servermessagelist.push(Object.assign({}, servermessage));
Create an new reference of object by JSON stringigy method and push it with parse method.
servermessagelist = [];
servermessagelist.push(JSON.parse(JSON.stringify(servermessage));
This method is useful for nested objects.
servermessagelist: new Array() empties the array every time it's executed. Only execute that code once when you originally initialize the array.
I also had same issue. I had bit complex object that I was pushing in to the array. What I did; I Convert JSON object as String using JSON.stringify() and push in to the Array.
When it is returning from the array I just convert that String to JSON object using JSON.parse().
This is working fine for me though it is bit far more round solution.
Post here If you guys having alternative options
I do not know why a JSON way of doing this has not been suggested yet.
You can first stringify the object and then parse it again to get a copy of the object.
let uniqueArr = [];
let referencesArr = [];
let obj = {a: 1, b:2};
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
obj.a = 3;
obj.c = 5;
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
//You can see the differences in the console logs
console.log(uniqueArr);
console.log(referencesArr);
This solution also work on the object containing nested keys.
Before pushing, stringify the obj by
JSON.stringify(obj)
And when you are using, parse by
JSON.parse(obj);
As mentioned multiple times above, the easiest way of doing this would be making it a string and converting it back to JSON Object.
this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
Works like a charm.

Categories

Resources