I am experementing with javascript objects for the first time and need some help. I want to store generated user input in objects, push them into an array and later on reuse them. So far I have come to this:
function changeColors() {
//get the numbers from the html
var rd = parseInt(document.getElementById("red").value);
var gr = parseInt(document.getElementById("green").value);
var bl = parseInt(document.getElementById("blue").value);
var op = parseFloat(document.getElementById("opacity").value);
//convert the decimal into hexadecimal
var rdhex = (rd < 16) ? "0" + rd.toString(16) : rd.toString(16);
var grhex = (gr < 16) ? "0" + gr.toString(16) : gr.toString(16);
var blhex = (bl < 16) ? "0" + bl.toString(16) : bl.toString(16);
//concatenate all hex to generate a color
var hexcode = "#" + rdhex + grhex + blhex;
//view the change in the browser
document.getElementById("div").style.backgroundColor = hexcode;
document.getElementById("colordisplay").innerHTML = hexcode;
//change opacity
document.getElementById("div").style.opacity = op;
Here I get all the input that I need to store and in the next function I am trying to store it in an object and array:
function Save(){
var colors = {};
var nextColor = []
colors.nextColor = nextColor;
console.log(colors);
var rgb = document.getElementById("colordisplay").innerHTML;
var opacity = document.getElementById("div").style.opacity;
var name = document.getElementById("name").value;
var nextColor = {
"name": name,
"rgb": rgb,
"opacity": opacity
}
colors.nextColor.push(nextColor);
console.log(colors);
}
My question is: is how wrong is that and how it can be corrected?
Thank you!
I am unsure what your question exactly is, but looking at your code for Save I assume you're inquiring how to best store data in the context of an application. Looking at the Save-method body:
var colors = {};
var nextColor = [];
These variables are only available in the scope of the Save function. As such the "colors"-Object will only ever contain one single color Object, i.e. the "nextColor" Object created in the Save function. On top of this, the "colors"-Object is not accessible outside of the Save function, rendering it... well, useless.
Ideally you hold the contents of the "colors"-Object in a global variable (or reference it in another Object available to your application, i.e. a "Model") and fill the colors Object with the return of the Save-method, i.e.:
function Save() {
var rgb = document.getElementById("colordisplay").innerHTML;
var opacity = document.getElementById("div").style.opacity;
var name = document.getElementById("name").value;
var nextColor = {
"name": name,
"rgb": rgb,
"opacity": opacity
};
return nextColor;
}
// assume an event handler invoked after a form is submitted, this
// creates a nextColor and pushes it into the existing colors Object
function someEventHandler( e ) {
colors.nextColor.push( Save() );
}
This implies that the Save-methods sole function is to gather the values entered in the HTML document, and translate it into a new value Object. The Save-method now has no business knowing about any remaining data belonging to your application. (i.e. the creation of the "colors" Object and its "nextColor"-Array should be left to another function, ideally executed when your application launches).
I guess what I'm saying is you're on the right track, but you can get a lot of mileage by investing some time into creating separate functions to handle your data layer. After all, that's all JSON is, data.
If for instance you want to enter validation in your Save()-method (let's say to make sure that the "name" Input element actually contains a valid String), you just modify it there in that one function. If you additionally wish to make sure that the same color isn't added to the "nextColor"-Array twice, you can make another function that checks whether a color with the same values is already present in the data Object and either removes it or prevents pushing the duplicate value into the Array. This is logic that shouldn't be in the Save()-method, as such you can structure your program to organize your data neatly.
I hope this is the answer you were looking for.
Try this:
var colors = {
"nextColor": []
};
function Save() {
colors.nextColor.push({
"name": document.getElementById("name").value,
"rgb": document.getElementById("colordisplay").innerHTML,
"opacity": document.getElementById("div").style.opacity
});
console.log(colors);
}
Notice that the colors variable should be outside the scope of the function in order to retain the variable beyond individual runs of the Save() function.
I've also simplified the code quite a bit.
Related
I am trying to save my variables in an array. Theses variables are written in by the user and saved to localStorage when a button is pressed. On my other html page i reach these variables and put them in 3 different arrays(the variables, that go in three arrays). Then the user writes in new text and save to the variables. Now to the problem. The newly created variables don't add to the array, they replace. I'm thinking this is due to to the same variable name however I can't find an solution.
I have tried to change variable names etc for saving the new variable but cant find solution.
//This is html page 2 (gets the items from localhost)
var TankaKostnadVar = localStorage.getItem("StorageKostnadVar");
var TankaLiterVar= localStorage.getItem("StorageLiterVar");
var TankaDatumVar = localStorage.getItem("StorageDatumVar");
var arrayKostnad = [];
var arrayLiter = [];
var arrayDatum = [];
arrayKostnad.push(TankaKostnadVar,);
arrayLiter.push(TankaLiterVar,);
arrayDatum.push(TankaDatumVar,);
document.write(arrayLiter,arrayKostnad,arrayDatum); //Ignore this, just test
//This is the code where the user is writing and it saves to localStorage.
//Html page 1 that saves the variables
var TankaKostnadVar = document.getElementById("tankaKostnad").value;
var TankaLiterVar = document.getElementById("tankaLiter").value;
var TankaDatumVar = document.getElementById("tankaDatum").value;
localStorage.setItem("StorageKostnadVar", TankaKostnadVar);
localStorage.setItem("StorageLiterVar", TankaLiterVar);
localStorage.setItem("StorageDatumVar", TankaDatumVar);
I expect the array to add the variable. So if the user writes an 5 the array should first be [5] then when the user writes an 8 the array should be [5,8]
If you don't want use JSON, you can save string comma separated and, when necessary, transform the items to numbers. To transform in numbers you can use map function or a for. Localstorage only save strings, so if you need to be back to numbers you need to use JSON.parse or use function parseInt, that is global.
//Retrieve saved items from localstorage
var TankaKostnadVar = localStorage.getItem("StorageKostnadVar"); // "1,2"
var TankaLiterVar = localStorage.getItem("StorageLiterVar");
var TankaDatumVar = localStorage.getItem("StorageDatumVar");
TankaKostnadVar += "," + document.getElementById("tankaKostnad").value;
TankaLiterVar += "," + document.getElementById("tankaLiter").value;
TankaDatumVar += "," + document.getElementById("tankaDatum").value;
localStorage.setItem("StorageKostnadVar", TankaKostnadVar);
localStorage.setItem("StorageLiterVar", TankaLiterVar);
localStorage.setItem("StorageDatumVar", TankaDatumVar);
// if you want to transform TankaKostnadVar and others two, just do like this
TankaKostnadVar.split(','); // result: ['1', '2']
// if you want to transform to number
TankaKostnadVar = TankaKostnadVar.split(',').map( function(number) {
return parseInt(number)
} );
The split function of string, breaks a strings in parts separated by one string. In this case, breaks a string separated with comma. So "1,2" turns into ['1', '2'].
If you want to keep adding to the array you'll need to push the entire array you're holding in memory up to localStorage after appending a new element. Alos, localStorage only stores string values so if you want to maintain the Array structure you'll have to use JSON.stringify() before running setItem() and then JSON.parse() next time you access those values with getItem().
//This is the code where the user is writing and it saves to localStorage.
//Html page 1 that saves the variables
var TankaKostnadVar = document.getElementById("tankaKostnad").value;
var TankaLiterVar = document.getElementById("tankaLiter").value;
var TankaDatumVar = document.getElementById("tankaDatum").value;
localStorage.setItem("StorageKostnadVar", JSON.stringify( [TankaKostnadVar] ));
localStorage.setItem("StorageLiterVar", JSON.stringify( [TankaLiterVar] ));
localStorage.setItem("StorageDatumVar", JSON.stringify( [TankaDatumVar] ));
//This is html page 2 (gets the items from localhost)
var TankaKostnadVar = localStorage.getItem("StorageKostnadVar");
var TankaLiterVar = localStorage.getItem("StorageLiterVar");
var TankaDatumVar = localStorage.getItem("StorageDatumVar");
var arrayKostnad = JSON.parse(TankaKostnadVar);
var arrayLiter = JSON.parse(TankaLiterVar);
var arrayDatum = JSON.parse(TankaDatumVar);
// Now you have arrays with data, but I don't know what you want to do with them...
// you could add more values like this (still page 2)...
arrayKostnad.push('new value 1')
arrayLiter.push('new value 2')
arrayDatum.push('new value 3')
localStorage.setItem("StorageKostnadVar", JSON.stringify( arrayKostnad ));
localStorage.setItem("StorageLiterVar", JSON.stringify( arrayLiter ));
localStorage.setItem("StorageDatumVar", JSON.stringify( arrayDatum ));
// now check the values again
var TankaKostnadArr = JSON.parse(localStorage.getItem("StorageKostnadVar"));
var TankaLiterArr = JSON.parse(localStorage.getItem("StorageLiterVar"));
var TankaDatumArr = JSON.parse(localStorage.getItem("StorageDatumVar"));
document.write(TankaKostnadArr, TankaLiterArr, TankaDatumArr)
And this is what I would do to clean things up a little...
// Import these functions and variables to any file that needs to interact with LocalStorage
var storageKeys = ["StorageKostnadVar","StorageLiterVar","StorageDatumVar"];
function addToArray(key, val, arrObj) {
arrObj[key].push(val)
}
function storeAllLocalStorage(arrayObject) {
Object.keys(arrayObject).forEach(key=>{
localStorage.setItem(key, JSON.stringify(arrayObject[key]));
})
}
// Use above functions when needed
var storedArrays = storageKeys.reduce((acc,key)=> {
var val = JSON.parse(localStorage.getItem(key));
if (typeof val === 'array') return {...acc, [key]:val};
return {...acc, [key]:[val]};
},{})
addToArray("StorageKostnadVar", document.getElementById("tankaKostnad").value, storedArrays);
addToArray("StorageLiterVar", document.getElementById("tankaLiter").value, storedArrays);
addToArray("StorageDatumVar", document.getElementById("tankaDatum").value, storedArrays);
storeAllLocalStorage(storedArrays)
You are simply using localStorage.setItem which saves your values with the given key. If the key exists, it will replace the value. Before you do a .setItem, get the value from the local storage first, then parse it to array so that you can finally push the new user inputs to that parsed array. Then you can .setItem to replace the "outdated" value from the localStorage.
UPDATE Example:
Sorry for leaving this hangin without an example. Here it is:
// Get array from local storage
const stringifiedArray = localStorage.getItem('myCollection');
// If there is no 'myCollection' from localStorage, make an empty array
const myCollection = stringifiedArray ? JSON.Parse(stringifiedArray) : [];
myCollection.push('My new item added'); // update array
localStorage.setItem('myCollection', JSON.stringify(myCollection)); // save
I'm trying to return a value in acrobat depending on two other fields - one text and one a value.
Users select from a drop down box the frequency in box F1, I then need to turn this text into a number to then multiply by another box (X1) , depending on the text selected in F1.
So far I have attempted this but can't get the result I would expect. Your assistance would be appreciated, I've very new to javascript! Many thanks.
var frequency_values= new Array();
frequency_value["Monthly"]=12;
frequency_value["Quarterly"]=4;
frequency_value["Semi-annually"]=2;
frequency_value["Annually"]=1;
document.getElementById("F1").value = frequency_value;
g.value = this.getField('frequency_value');
h.value = this.getField("X1");
event.value = (h.value * g.value)/52;
Try this:
function getField(f) {
// not sure what getField does in your app, but i'm just defining it here and return a number for debugging in console
return 20;
}
var frequencyValues = {
'Monthly': 12,
'Quarterly': 4,
'Semi-annually': 2,
'Annually': 1
};
// lets get the user selection form the select drop down
// var f1 = document.getElementById('F1').value;
var f1 = 'Monthly'; // for debugging in our console, lets just set it to monthly
// not sure what g and h are, but we'll just define them here
var g = {},
h = {};
g.value = frequencyValues[f1];
h.value = this.getField('X1');
var value = (h.value * g.value) / 52;
console.log(value);
The idea is to create an object named frequencyValues, not array.
And when you access it, you access it using obj[field].
Since I don't have your code, so I created the getField function and commented our the document.getElementById, but I think you get the idea.
BTW, not sure what your language background is, but try to stick to camel standard you code Javascript, ie. frequencyValues instead of frequency_values. Try to avoid underscore in variables and function names at all costs.
Good luck.
In my Notes Database, I perform an audit when the document is saved. Pretty easy in LotusScript. I grab the original document (oDoc) from the server, then in the document I modified (mDoc), I do a Forall loop that gets the names of each item; forall item in mDoc.items. Grab the same item from oDoc, execute a function with the new item as an argument that will run down a case statement that will see if its a field we care about. if so, I update a set of list values in the document with "When", "Who", "What field", and the "New Value".
I'm doing this in a server side script. In trying this, I discovered a couple of interesting things;
currentDocument is the NotesXSPDocument that contains everything that was just changed.
currentDocument.getDocument() contains the pre-change values. It also returns a NotesDocument which has the "items" field that I can run through.
Thing is, I need something similar in the NotesXSPDocument. Is there a way in an iterative loop to grab the names and values of all items from there?
Here's the broken code. (Currently it's walking through the NotesDocument items, but those are the old values. I'd rather walk down the XSP document items)
function FInvoice_beginAudit() {
var original_doc:NotesDocument = currentDocument.getDocument();
var oItem:NotesItem;
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
item = currentDocument.getItemValue(oItem.getName());
if (oItem == undefined) {
var MasterItem = ScreenAudit(doc,item,True)
if (MasterItem) { return true }
} else {
if (item.getValueString() != oItem.getValueString()) {
var MasterItem = ScreenAudit(doc,Item,True);
if (MasterItem) { return true }
}
}
}
}
You can get both versions of a document after submit - the original and the one with changed/new values:
original: var original_doc:NotesDocument = currentDocument.getDocument();
changed: var changed_doc:NotesDocument = currentDocument.getDocument(true);
This way you can compare the items for changes.
But, there is a pitfall: after assigning "changed_doc" to currentDocument.getDocument(true) the "original_doc" has the changed values too because both variables point to the same document. That's why we have to copy all items from currentDocument.getDocument() to a new temporary document first and only after get the changed values with currentDocument.getDocument(true). As an alternative you could read the original document from server like you do in LotusScript.
This is a code for detecting changed items as a starting point:
var original_doc:NotesDocument = database.createDocument();
currentDocument.getDocument().copyAllItems(original_doc, true);
var changed_doc:NotesDocument = currentDocument.getDocument(true);
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
var itemName = oItem.getName();
var cItem:NotesItem = changed_doc.getFirstItem(itemName);
if (cItem.getText() !== oItem.getText()) {
print("changed: " + itemName);
}
oItem.recycle();
cItem.recycle();
}
original_doc.remove(true);
original_doc.recycle();
This is annoying me.
I'm setting an array in beginning of the doc:
var idPartner;
var myar = new Array();
myar[0] = "http://example.com/"+idPartner;
And I'm getting a number over the address, which is the id of partner. Great. But I'm trying to set it without success:
$.address.change(function(event) {
idPartner = 3;
alert(idPartner);
}
Ok. The alert is giving me the right number, but isn't setting it.
What's wrong?
Changing the value of the variable does not re-set the values within the array. That is just something javascript can't do automatically. You would have to re-generate the array for it to have the new id. Could you add the id to the value where you use the array instead of pre-setting the values in the array containing the id?
Edit: For example, you would do:
var myArray = [];
var myId = 0;
myArray[0] = "http://foo.com/id/";
and when you need to use a value from the array, you would do this:
var theVal = myArray[0] + myId;
Try this:
var myvar = ["http://site.com/"];
$.address.change(function(event) {
myvar[1] = 3;
}
then use myvar.join () where you need the full url.
The problem here is that at the line
myar[0] = "http://site.com/"+idPartner;
..you perform a string concatenation, meaning you copy the resulting string into the array at index position 0.
Hence, when later setting idPartnerit won't have any effect on the previously copied string. To avoid such effect you can either always construct the string again when the idPartnervariable updates or you create an object and you evaluate it when you need it like...
var MyObject = function(){
this.idPartner = 0; //default value
};
MyObject.prototype.getUrl = function(){
return "http://site.com/" + this.idPartner;
};
In this way you could use it like
var myGlblUrlObj = new MyObject();
$.address.change(function(event){
myGlblUrlObj.idPartner = ... /setting it here
});
at some later point you can then always get the correct url using
myGlblUrlObj.getUrl();
Now obviously it depends on the complexity of your situation. Maybe the suggested array solution might work as well, although I prefer having it encapsulated somewhere in an object for better reusability.
myar[0] = "http://site.com/" + idPartner;
After this line, myar[0] = "http://site.com/undefined" and it has nothing to do with the variable idPartner no more.
So, after that changing the value of idPartner will affect the value of myar[0].
You need to change the value of myar[0] itself.
I've built a data-driven google map with different icons that get assigned to the map depending on the type of item located. So if I have 5 types of landmark, and each gets a different icon (store, library, hospital, etc.)-- what I'd like to do is generate the google icon objects dynamically. I was thinking something like this:
types = array('hospital','church','library','store',etc);
var i=0;
while (i<=types.length) {
var landmark + i = new google.maps.Icon();
landmark.image = "icon" + i + ".png";
i++;
}
however, as you've probably guessed, this doesn't work. I also tried using eval, like this:
while (i<=types.length) {
doIcon(i);
i++;
}
function doIcon(i){
eval("var landmark" + i + " = new.google.maps.Icon();");
return eval("landmark" + i);
}
but it didn't work either-- I'd appreciate any pointers on generating javascript variables dynamically. It's got to be pure js, I could do it in PHP but that's not an option here.
Thanks!
It's really easy to do: object["variablename"] = whatever;
So for example you could have an object: var Landmarks = {} and you could add to it like so: Landmarks["landmark" + i] = new google.maps.Icon(); and pass it that way.
If you need these variables to be global (why would you?) you can access the global object directly using window.
If you're going to do it using a declared object such as Landmark["landmark" + i], you really may as well use an index array rather than an associative, it's much easier for iteration. Objects aren't really used with indexed properties because Arrays do a much better job of it:
var myObj = // object version
{
"item0": "blah",
"item1": "blah"
// etc
}
var myArr = // array version
[
"blah",
"blah"
// etc
]
Much more sensible to use the array:
landmarks = []; // new array
types = array('hospital','church','library','store',etc);
var i=0;
while (i<=types.length) {
landmarks.push(new google.maps.Icon());
landmarks[i].image = "icon" + i + ".png";
i++;
}
It makes more sense to do it that way and for...in loops on objects can get a bit messy with prototyped properties being enumerable, etc.
If you're trying to make a variable global, add it to the window object:
var myCustomVar = "landmark" + i;
window[myCustomVar] = new google.maps.Icon();
alert(landmark0);
But this would be polluting the global namespace with many unnecessary variables. So you'd still be better with an array:
window.landmarks = [];
landmarks.push(new google.maps.Icon());
// etc...
Just to answer your question directly (although please note that this is not the solution you want. Check out the other answers. This is just for documentation!), here's a copy-paste from a JavaScript console:
> window["myNamedVar"] = "Hello, World!";
> console.log(myNamedVar);
"Hello, World!"
You'd be better off creating a javascript object which you can use somewhat like an associative array is used in PHP:
var types = ['hospital','church','library','store'];
var landmarks= {};
for (var i in types) {
landmarks[types[i]]= new google.maps.Icon();
landmarks[types[i]].image = "icon" + i + ".png";
}
alert(landmarks['hospital'].image); // displays "icon0.png"
Do you really need those variables? Can't you do with this:
var types = ['hospital','church','library','store'];
for(var i =0; i < types.length; i += 1) (new google.maps.Icon()).image = "icon" + i + ".png";
Modifications done based on comment:
icon name pattern changed from icon + index + .png to icon + type + .png
and saving the results of the loop.
types = ['hospital','church','library','store'];
var landmarks = {};
// images names are of the form icon + type + .png
function createIcon(type)
{
var icon = new google.maps.Icon();
icon.image = "icon" + type + ".png";
return icon;
}
// mapping of landamarks by type and icon
for (var i = 0, len = types.length; i < len; i++)
{
landmarks[types[i]] = createIcon(types[i]);
}
the result is :
{
hospital : icon,
church : icon,
...
}
where icon is a google map icon that has an image attribute that is a string of the form "icon{type}.png" , e.g, iconhostpital.png, iconchurch.png.
To use the icons write landmarks.type where type is one the names in the array of types, e.g. landmarks.hospital.
if the image names are of the form icon + number + .png, and the number for each type is equivalent to its index in the array replace the call createIcon(type[i]) for createIcon(i).