Here's a function I have written to add words to local storage using Javascript. In case you're wondering, this is my attempt at building a search history functionality for a simple dictionary lookup site.
function add2local(entry){
var l = localStorage.length;
if(l==0){
var lu = [entry];
localStorage.setItem("w", JSON.stringify(lu));
}
else {
var lu = JSON.parse(localStorage.getItem("w")); alert(lu);
lu.push(entry); alert(lu);
}}
My understanding is the this function would keep appending its argument to local storage every time it's called. So, the first time I call it, I send it the word pirate. This gets added to the array and subsequently to the local storage as expected. The first alert() (the alert() functions are solely being used for testing) confirms this. The second time, I call it with the word vampire. Now, going by the function's logic, vampire should be appended to the array and thus the second alert() should output "pirate, vampire." And so it does.
But the third time around, say, I call the function with the word foo. This time around, it should output "pirate, vampire, foo" but instead shows "pirate, foo". Every subsequent call simply replaces the second word with the new word instead of appending it. What might I be doing wrong here? Am I misunderstanding how push() works?
The if condition and logic is incorrect; it is irrelevant how many items localStorage has, but it is very important to re-save the modified array.
In any case, I suspect an impl. might look as so:
function add2local(entry){
// load entries - if there are none, we simulate an empty array to load
var lu = JSON.parse(localStorage.getItem("w") || "[]");
// add new entry
lu.push(entry);
// write back - so change is not lost between function calls
localStorage.setItem("w", JSON.stringify(lu));
// return all local entries saved - for use from the caller
return lu;
}
Why check the storage length? You don't care. Fetch the key and if it's null then default to empty array.
function add2local (entry) {
var key = "w"
var value = localStorage.getItem(key)
if (value) {
value = JSON.parse(value)
} else {
value = []
}
value.push(entry)
localStorage.setItem(key, JSON.stringify(value))
}
Related
Issue Description
I'm currently trying to make updates on passwords using sequelize.fn.
I've seen numerous sites, including the Sequelize's manual, yet I found too few articles that approaches my case, and none of them seems to solve it.
Moreover, the function to encrypt the passwords need nested function, so I need to gradually construct the nested function
by putting the successive arguments into variables.
I have not found anything on constructing the functions, thus using sequelize.fn outside the arguments of the functions find and updates.
Additional context
In my case, " crypt('password', gen_salt('bf', 4)) " (in Postgres) needs to become
sequelize.fn('crypt', 'password', sequelize.fn('gen_salt', 'bf', 4)) and to be stored into a variable
When I inject it into the update function, an Fn Object is injected, and the result in the database seems to be a memory address instead of the result of the crypt function.
I may post a code example so you can have a better understanding of what I'm trying to do and I think should be added into the documentation
I did not made this doc issue to resolve my issue, only to point out what I think is lacking in the documentation
I will ask StackOverflow for help regarding my issue.
//Take a format and a value, and applies the functions inside the format onto the value
function recursSequelizeFn (format, value) {
const sequelize = db.sequelize;
let nextId = 0;
let matches;
let finalArgs = {};
//The RegEx finds the function calls of which parameters aren't functions themselves
//As the format string is modified on each loop, I need to initialize the RegEx on each loop
while ((matches = (/(\w+)\(([^(,)]+)?(?:,([^(,)]+))*\)/g).exec(format)) !== null) {
//matches[0] is the whole expression
//matches[1] is the function's name
//matches[>=2] are the arguments
let func = matches[1];
let args = matches.slice(2);
for (let argNo in args) {
//Transforms DB's columns into Sequelize-interpreted columns
//I do not check the column that is found, because I do not have others columns than the one that is being treated
args[argNo] = args[argNo].replace(/seqCol_(\w+)/g, (correspondance, p1, decalage, chaine)=>{return value;});
//If the parameter was previously saved, we replace its reference by its value
args[argNo] = args[argNo].replace(/(#\d+)/g, (correspondance, p1, decalage, chaine)=>{return finalArgs[p1];});
}
//finally, we save the value of the function and replace the whole expression by a reference
finalArgs['#'+nextId]=sequelize.fn(func, ...args);
format = format.replace(matches[0], '#'+nextId);
nextId++;
}
//When the treatment is finished, we return the last value saved into the array
//Or we return the original value if we have not made any change (the array will be empty)
return finalArgs['#'+(nextId-1)]||value;
}
Object.keys(req.message.attributes).map((key)=>{
//req.message.attributes[key] contains the formatting needed to be put onto the value
//e.g. crypt(password, gen_salt('bf', 4))
//req.body[key] contains the value
//e.g. '1234'
let seqValue = util.recursSequelizeFn(req.message.attributes[key], req.body[key]);
req.body[key] = seqValue;
});
//mainModel is a sequelize model
mainModel.update(req.body, {where: {id:req.params.id}, logging:console.log})
.then() //...
Is there a better way of doing the following. I have a JSON array that gets passed in a javascript object, the object doesn't have key value pairs so i need to manual set each point in the array and bind it to a variable.
While the example bellow is only 1 item there are 80+ that need to be set.
If i try to put in item[key][2][1] as a peramiter for a function the code fails as it trys to access the array before passing off to the try catch function. Also all the try catch's happen within a loop that can run up to 200 times per page load.
The below works for everything, but when dealing with i.e 8 or below it begins to bottleneck fast. I have also isolated that it is this checking function that bottlenecks and not other parts of the code.
var someArr = "";
for(i=0;i<data.length;i++){
var item = data[i];
for(key in item){
try{someArr = item[key][2][1]}
catch(err){}
final{someArr = checkData(someArr)}
}
}
function checkData(value){
if(!value){value = "";}
return value;
}
You could exchange your try catch block with a check if the parts of variable are set.
if (item && item[key] && item[key][2]) {
someArr = item[key][2][1];
}
I have a function:
// Get the value out of Chrome local storage
chrome.storage.local.get(sourcePath, function(result) {
// Test the result
alert(JSON.stringify(result.sourcePath));
});
And a call to check it:
chrome.storage.local.set({'userAcceptanceAgreement': true});
Right now, I would like to know how to get my function, when called with the above argument, to pass that value into the result.sourcePath alert. As is, it shows result with the correct storage value of {'userAcceptanceAgreement': true}, but result.sourcePath comes up as undefined because it isn't trying to locate the key:value pair for the argument, but for a literal sourcePath.
Basic JavaScript here.
var sourcePath = 'userAcceptanceAgreement';
result.sourcePath; // Accesses literally "sourcePath"
result[sourcePath]; // Accesses "userAcceptanceAgreement"
Note that you buried the problem under a lot of noise. Please consider constructing a minimal example next time.
There is something wrong with my code, but I can't find what it is. The first time I call registerStartDateValidation, the value of the startDateValidation variable in the defineKeyword closure is of course the same than what was affected outside the closure. But the second time, the variable is reaffected with another value, but the value of startDateValidation in the defineKeyword is still equal to the value of the first time we call registerStartDateValidation. Does the closure cache the variable?
Tv4.prototype.registerStartDateValidation = function (attributes) {
var helper = this;
var dateNames = Object.keys(attributes);
var startDateName = dateNames[0];
var startDateString = attributes[startDateName];
var endDateName = dateNames[1];
var endDateString = attributes[endDateName];
var startDateValidation = helper.startDateValidation(startDateString, startDateName, endDateString, endDateName);
console.log(startDateValidation)//First time equal "true", second time equal "false"
tv4.defineKeyword('startDate', function (data, value) {
if (value === 'startDate') {
console.log(startDateValidation)//First time equal "true", second time still equal "true"
return startDateValidation
}
});
};
Note that there is nothing making an ajax request, that could mess up the order the functions are called.
Short answer: no, a closure won't cache the variable, so there is something else going on in your code. Reducing the problem to a simple complete example that demonstrates the problem will usually make it obvious where the problem is coming from, or at least help other people figure it out.
However, since it looks like you're referring to is this project, it may be possible to figure out what's going on. Tv4.defineKeyword() appends new functions to a list if it is called multiple times for the same keyword. Since you're calling tv4.defineKeyword (note the lower-case 't') and not helper.defineKeyword or this.defineKeyword, it looks like each call to registerStartDateValidation will affect the same instance, so you are almost certainly adding a validation function when you meant to replace it.
How do I increment an integer inside a variable, every time that variable is called? Javascript.
var a=0;
var t=loadXMLDoc("http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist="+x[a].getElementsByTagName("name")[0].childNodes[0].nodeValue+"&api_key=83e386b0ba08735e3dee9b118478e56d&lang=en").getElementsByTagName("bio");
for (i=0;i<20;i++)
{
document.write("<div><button type='button' onclick='document.getElementById("+i+").innerHTML=t[0].getElementsByTagName(\"summary\")[0].childNodes[1].nodeValue;'>Open Bio</button></div>");
}
I'm not sure how I would go about incrementing variable a. I need it to increase by 1 every time variable t is called in the for loop.
When I put all of the code in the for loop I get [object node list] returned so this method is not desired.
If I understood your question correctly, you could define your own getters and setters for the property.
var o = {}
o.__defineSetter__('property', function(value) { this._counter = 0; this._holder = value; })
o.__defineGetter__('property', function() { console.log(this._counter++); return this._holder; })
The counter would be reset every time o.property is assigned a value
o.property = 'Some value'
and then increase every time the property is accessed.
So,
console.log(o.property)
would print
0
Some value
to the console. And if you do it again, it would print
1
Some value
After your edit I think I can see your problem now. You will need to put the loadXMLDoc statement in the loop (since you want to load 20 different XML files), but you can't assign the result of every call to the same variable t - as once the button is clicked, the handler will evaluate t and get only the last value.
Instead, use an array:
var bios = []; // empty array
for (var i=0; i<20; i++) {
var artist = x[i].getElementsByTagName("name")[0].childNodes[0].nodeValue,
doc = loadXMLDoc("http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist="+artist+"&api_key=83e386b0ba08735e3dee9b118478e56d&lang=en"),
bio = doc.getElementsByTagName("bio")[0].getElementsByTagName("summary")[0].childNodes[1].nodeValue;
bios[i] = bio; // store it in the array
document.write("<div><button type='button' onclick='document.getElementById("+i+").innerHTML=bios["+i+"];'>Open Bio</button></div>");
}
Of course, while that will work it's a bunch of bad practises, including
unsecured accessing of DOM nodes/properties. If the xml changes its format, you will get lots of exceptions here. You might be sure now that this never happens, but wrapping artist and bio in try-catch might not be a bad idea.
snychronous Ajax. One can do better than that.
loading 20 documents (and that sequentially!) even if you don't need them. It might be worth to try loading each of them only when the respective button is clicked.
document.write
Inline attribute event handlers
…and creating them even by JS.