trying to write a javascript quiz for my coding bootcamp. having some issues with retrieving and saving previous high scores from local storage. can someone please explain to me why the below code writes the newScore TWICE to the highScores arrayItems array into local storage? obviously i would not like duplicates. everything else works great except for this! please help me. thank you so much!
// load any existing high scores from local storage as array
let scoresArray = localStorage.getItem('highScores') ? JSON.parse(localStorage.getItem('highScores')) : [];
// save the score and intials to local storage in array
let newScore = [document.querySelector("#initialsInput").value, '' + countdownTimer + ''];
scoresArray.push(newScore);
localStorage.clear("highScores");
localStorage.setItem('highScores', JSON.stringify(scoresArray));
// run the high scores function which will show all high scores, storted and give the user a chance to play again
showHighScores();
thanks for your quick replies. im sorry i was able to supply you with all of the info you needed, but i thought i gave you enough to work with.
i was just writing to let you know i did figure out a work around. while i'm still getting the duplicate entries into the array, before writing it to localstorage i am using a very simple jquery method to remove any duplicates from my array. here's what i ended up doing:
var uniqueNames = [];
$.each(scoresArray, function (i, el) {
if ($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
})
The clear() method of the Storage interface clears all keys stored in
a given Storage object.
https://developer.mozilla.org/en-US/docs/Web/API/Storage/clear
I guess you don't need to clear the localStorage.
I believe you need to add the scenario of how triggering this implementation of adding array to the local storage, as I think you might add it twice instead (I mean if the code you showed us is inside a function or how it's executed exactly)
but from the code above, everything seems to be working fine, I'd like to have more code from your side please to better understand what's going on. also you can remove localStorage.clear as localStorage.setItem will override any existing key with new value
lame work around using jquery to remove duplicates from the array:
var uniqueNames = [];
$.each(scoresArray, function (i, el) {
if ($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
})
I'm trying to debug some code that another programmer has left for me to maintain. I've just attempted to upgrade from node.js 5 to node.js 8 and my database queries are for some requests coming back with key not found errors
We're using couchbase for the database and our document keys are "encrypted" for security. So we may have a key that starts like this "User_myemail#gmail.com" but we encrypt it using the following method:
function _GetScrambledKey(dbKey)
{
//select encryption key based on db key content
var eKeyIndex = CalculateEncryptionKeyIndex(dbKey, eKeys.length);
var sha = CalculateSHA512(dbKey + eKeyIndex);
return sha;
}
function CalculateEncryptionKeyIndex(str, max)
{
var hashBuf = CalculateSHA1(str);
var count = 0;
for (var i = 0; i < hashBuf.length; i++)
{
count += hashBuf[i];
count = count % max;
}
return count;
}
We then query couchbase for the document with
cb.get("ECB_"+encryptedKey, opts, callback);
In node5 this worked but in node8 we're getting some documents return fine and others return as missing. I outputted the "ECB_"+encryptedKey as an int array and the results have only confused me more. They are different on node5 to node8 but only by one character right in the middle of the array.
Outputting the encryptedKey as an int array on both versions shows this
188,106,14,227,211,70,94,97,63,130,78,246,155,65,6,148,62,215,47,230,211,109,35,99,21,60,178,74,195,13,233,253,187,142,213,213,104,58,168,60,225,148,25,101,155,91,122,77,2,99,102,235,26,71,157,99,6,47,162,152,58,181,21,175
Then outputting the concatenated string, in the same way, shows slightly different results
This is the node8 output
Node8 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
And this is the node5 output
Node5 key: 69,67,66,95,65533,106,14,65533,65533,70,94,97,63,65533,78,65533,65533,65,6,65533,62,65533,47,65533,65533,109,35,99,21,60,65533,74,65533,13,65533,65533,65533,65533,65533,65533,104,58,65533,60,65533,65533,25,101,65533,91,122,77,2,99,102,65533,26,71,65533,99,6,47,65533,65533,58,65533,21,65533
I had to run it through a diff tool to see the difference
Comparing that to the original pre-append array it looks like the 225 has just been dropped in node8. Is 225 significant? I can't understand how that would be possible otherwise unless it's a bug. Does anyone have any ideas?
Looks like this was a change in v8 5.5 https://github.com/nodejs/node/issues/21278
A lot of the issues you are facing, including the concatenation can be cleaned up using newer features from ES6 that are available in node 8.
In general, you should avoid doing string concatenations with the + operator and should use string literals instead. In your case, you should replace the "ECB_"+encryptedKey with `ECB_${encryptedKey}`.
Additionally, if you want to output the contents of the integers values from this concatenated string, then you are better off using .join, the spread operator (...) and the Buffer class from Node as follows:
let encKey = `ECB_${encryptedKey}`;
let tmpBuff = Buffer.from(encKey);
let buffArrVals = [...tmpBuff];
console.log(buffArrVals.join(','));
Also, if you can help it, you really should avoid using var inside of function blocks like it exists in your sample code. var performs something called variable hoisting and causes the variable to become available outside the scope it was declared, which is seldom intended. From node 6+ onward the recommendation is to use let or const for variable declarations to ensure they stay scoped to the block they are declared.
I`m writing a script to generate a form in Google Apps Script.
The idea is, that the user should select his/her name from a dropdown list, and then be transferred to the question block for him/her.
Although the questions are the same, there are slight changes in the choices if the dropdowns for some of the questions.
I have an array with the names of the users, and I've defined the questions for every single user.
This is not ideal, as if there is any change in the questions I have to rewrite every block oone by one.
I want to use a loop which generates the question blocks by creating the variables names using the array of the usernames.
I tried the following (this is not the actual code, but throws the same error)
for (a=0; a < 10; a++)
{
eval('var beginning'+a);
}
for (b=0;b<10; b++)
{
eval('beginning' + b) = 1;
}
The first for loop runs fine, but when I try to assign any value it throws an error. (I use here two for loops for debugging only.)
E.g.:
eval('beginning' + b) = 1; //Throws: We're sorry, a server error occurred. Please wait a bit and try again.
eval('beginning' + b + '= 1;'); //Throws: We're sorry, a server error occurred. Please wait a bit and try again.
eval('beginning' + b = 1); //Throws: Invalid assignment left hand side. (line 1, file "Code")
Using eval like this is also fine: choices = eval('lCountries' + Names[i]).getChoices();.
How can I assign values to these variables in a for loop?
Thank you very much in advance.
As far as I read up so far, eval() is almost always a bad choice, should be handled with caution and mostly never used. Using dynamic variables in such way is also a bad programming logic. I've never seen a case where it is a must, and your case obviously isn't. You can easily get around it with an object, just define a generic object var myVariables = {}, and then start assigning its properties dynamically for your variables.
var myVariables = {};
myVariables[ "beginning" ] = 1;
for( i = 0; i < 10; i++){
myVariables[ ("beginning" + i) ] = i;
}
Logger.log( myVariable[ "beginning5" ] ); //Loggs 5
I read some stackOverflow questions and answers more then ten times per day, and... it looks its first time i feel its okey to post something, as i didnt find accurate enought answer.
Im writing some code in nodeJS. Its web interface for big softswitch based on custom asterisk, where in one place i need to get data from post message from website.
The problem is, that that post message containts numerous info named in fashion:
peer1
peer2
peer3
peer4 etc
Instead of dealing with every single one, i did a loop:
var array = [];
var i = 0;
while (typeof eval("req.body.peer" + i) !== 'undefined' && eval("req.body.peer" + i) !== '') {
console.log('petla wisielca');
//console.log(eval("req.body.peer" + i));
array.push(eval('req.body.peer' + i));
i++;
}
Number filled inputs (actually its html select) is variable.
After creating that array, I deal with rest of things (write peers to file etc) in traditional, non-eval loops.
Am i missing something here, or it's proper way of dealing with such situation?
Thanks in advance!
EDIT:
Looks like i had some kind brain malfunction :).
Solution is very easy,
as kyle cleared it out, to access object variables and for example iterate, all is needed is to use [].
Solution:
var array = []
var i = 0
while (req.body['peer' + i]) {
array.push(req.body['peer' + i])
i++
}
Thanks once more Kyle.
JavaScript objects can be accessed like they're associative arrays:
var array = []
var i = 0
while (req.body['peer' + i]) {
array.push(req.body['peer' + i])
i++
}
Use of eval is ever evitable, i wrote a plugin that make some dynamic calls of functions, you can check how you can access the object without using eval:
https://github.com/HaSuKrOnOs/jquery-dynFn
How do I remove an items from a data bound array? My code follows.
for(var i = 0; i < listBox.selectedIndices.length; i++) {
var toRemove = listFiles.selectedIndices[i];
dataArray.splice(toRemove, 1);
}
Thanks in advance!
Edit Here is my swf. The Add Photos works except when you remove items.
http://www.3rdshooter.com/Content/Flash/PhotoUploader.html
Add 3 photos different.
Remove 2nd photo.
Add a different photo.
SWF adds the 2nd photo to the end.
Any ideas on why it would be doing this?
Edit 2 Here is my code
private function OnSelectFileRefList(e:Event):void
{
Alert.show('addstart:' + arrayQueue.length);
for each (var f:FileReference in fileRefList.fileList)
{
var lid:ListItemData = new ListItemData();
lid.fileRef = f;
arrayQueue[arrayQueue.length]=lid;
}
Alert.show('addcomplete:' + arrayQueue.length);
listFiles.executeBindings();
Alert.show(ListItemData(arrayQueue[arrayQueue.length-1]).fileRef.name);
PushStatus('Added ' + fileRefList.fileList.length.toString() + ' photo(s) to queue!');
fileRefList.fileList.length = 0;
buttonUpload.enabled = (arrayQueue.length > 0);
}
private function OnButtonRemoveClicked(e:Event):void
{
for(var i:Number = 0; i < listFiles.selectedIndices.length; i++) {
var toRemove:Number = listFiles.selectedIndices[i];
//Alert.show(toRemove.toString());
arrayQueue.splice(toRemove, 1);
}
listFiles.executeBindings();
Alert.show('removecomplete:' + arrayQueue.length);
PushStatus('Removed photos from queue.');
buttonRemove.enabled = (listFiles.selectedItems.length > 0);
buttonUpload.enabled = (arrayQueue.length > 0);
}
It would definitely be helpful to know two things:
Which version of ActionScript are you targeting?
Judging from the behavior of your application, the error isn't occurring when the user removes an item from the list of files to upload. Looks more like an issue with your logic when a user adds a new item to the list. Any chance you could post that code as well?
UPDATE:
Instead of: arrayQueue[arrayQueue.length]=lid
Try: arrayQueue.push(lid)
That will add a new item to the end of the array and push the item in to that spot.
UPDATE 2:
Ok, did a little more digging. Turns out that the fileList doesn't get cleared every time the dialog is opened (if you're not creating a new instance of the FileReferenceList each time the user selects new files). You need to call splice() on the fileList after you add each file to your Array.
Try something like this in your AddFile() method...
for(var j:int=0; j < fileRefList.fileList.length; j++)
{
arrayQueue.push(fileRefList.fileList[j]);
fileRefList.fileList.splice(j, 1);
}
That will keep the fileList up to date rather than holding on to previous selections.
I see one issue. The selected indices are no longer valid once you have spliced out the first element from the array. But that should only be a problem when removing multiple items at once.
I think we need to see more code about how you are handling the upload before we can figure out what is going on. It looks to me like you are holding a reference to the removed FileReference or something. The described problem is occurring when you upload a new file, not when you remove the selected one.
Do you mean to use listBox and listFiles to refer to the same thing?
I'm stepping out on a limb here, because I don't have a ton of experience with JavaScript, but I'd do this the same way that I'd do it in C, C++, or Java: By copying the remaining array elements down into their new locations.
Assuming that listFiles.selectedIndices is sorted (and its contents are valid indices for dataArray), the code would be something like the following:
(WARNING: untested code follows.)
// Don't bother copying any elements below the first selected element.
var writeIndex = listFiles.selectedIndices[0];
var readIndex = listFiles.selectedIndices[0] + 1;
var selectionIndex = 1;
while(writeIndex < (dataArray.length - listFiles.selectedIndices.length)) {
if (selectionIndex < listFiles.selectedIndices.length) {
// If the read pointer is currently at a selected element,
// then bump it up until it's past selected range.
while(selectionIndex < listFiles.selectedIndices.length &&
readIndex == listFiles.selectedIndices[selectionIndex]) {
selectionIndex++;
readIndex++;
}
}
dataArray[writeIndex++] = dataArray[readIndex++];
}
// Remove the tail of the dataArray
if (writeIndex < dataArray.length) {
dataArray.splice(writeIndex, dataArray.length - writeIndex);
}
EDIT 2009/04/04: Your Remove algorithm still suffers from the flaw that as you remove items in listFiles.selectedIndices, you break the correspondence between the indices in arrayQueue and those in listFiles.selectedIndices.
To see this, try adding 3 files, then doing "Select All" and then hit Remove. It will start by removing the 1st file in the list (index 0). Now what had been the 2nd and 3rd files in the list are at indices 0 and 1. The next value taken from listFiles.selectedIndices is 1 -- but now, what had been the 3rd file is at index 1. So the former File #3 gets spliced out of the array, leaving the former 2nd file un-removed and at index 0. (Using more files, you'll see that this implementation only removes every other file in the array.)
This is why my JavaScript code (above) uses a readIndex and a writeIndex to copy the entries in the array, skipping the readIndex over the indices that are to be deleted. This algorithm avoids the problem of losing correspondence between the array indices. (It does need to be coded carefully to guard against various edge conditions.) I tried some JavaScript code similar to what I wrote above; it worked for me.
I suspect that the problem in your original test case (removing the 2nd file, then adding another) is analogous. Since you've only shown part of your code, I can't tell whether the array indices and the data in listFiles.selectedIndices, arrayQueue, and fileRefList.fileList are always going to match up appropriately. (But I suspect that the problem is that they don't.)
BTW, even if you fix the problem with using splice() by adjusting the array index values appropriately, it's still an O(N2) algorithm in the general case. The array copy algorithm is O(N).
I'd really need to see the whole class to provide a difinitive answer, but I would write a method to handle removing multiple objects from the dataProvider and perhaps assigning a new array as the dataProvider for the list instead of toying with binding and using the same list for the duration. Like I said, this is probably inefficient, and would require a look at the context of the question, but that is what I would do 9unless you have a big need for binding in this circumstance)
/**
* Returns a new Array with the selected objects removed
*/
private function removeSelected(selectedItems:Array):Array
{
var returnArray:Array = []
for each(var object:Object in this.arrayQueue)
{
if( selectedItems.indexOf(object)==-1 )
returnArray.push( object )
}
return returnArray;
}
You might be interested in this blog entry about the fact that robust iterators are missing in the Java language.
The programming language, you mentioned Javascript, is not the issue, it's the concept of robust iterators that I wanted to point out (the paper actually is about C++ as the programming language).
The [research document]() about providing robust iterators for the ET++ C++ framework may still e helpful in solving your problem. I am sure the document can provide you with the necessary ideas how to approach your problem.