If I remove an item using localStorage.removeItem("key"); is there any way I can check if the removal was successful or not? Something like a callback or promise?
Right now I am doing like this:
if(localStorage.getItem("key"))
localStorage.removeItem("key");
else
console.log("Error");
Is this the right way to do it or could this be done in a "better" way?
The removeItem() call does not return any indication of failure1 of any sort (excerpt taken from a recent editor's draft of the W3C web storage specification, with my emphasis):
The removeItem(key) method must cause the key/value pair with the given key to be removed from the list associated with the object, if it exists. If no item with that key exists, the method must do nothing.
Hence, the only way to tell if the key was an actual removal (as opposed to the "do nothing" action in the second sentence above) is to check it first.
You should almost certainly use explicit checking of the getItem() return value against null (with === of course) but that doesn't change the fact that you can't detect failure with removeItem() itself1.
Of course, if you're worried about peppering your code with these snippets, you're quite able to define a function to do the heavy lifting for you, something like:
function removeExistingItem(key) {
if (localStorage.getItem(key) === null)
return false;
localStorage.removeItem(key);
return true;
}
and then call it with the more succinct:
if (! removeExistingItem("key"))
console.log("Error");
1 This is based on "failure" being defined as the key not existing (as seems to be the definition you're using in the question). In reality, removeItem() cannot fail simply because it will do nothing in the case where the item does not exist (see inset above).
A more accurate check will be as below, else if the value of the key was ""(empty string) then it will fail
if (localStorage.getItem("key") !== null) {
localStorage.removeItem("key");
} else {
console.log("Error");
}
Storage.getItem() will return null if the key is not found
I ran into this same issue today [06-23-2019], and adjusted #paxdiablo's answer to add a few more fail-safes to the solution. I really hope my version helps someone else save the time and headache I went through:
/* Conditional Function supplements localStorage.removeItem(...) to return a [Boolean] 'success' or 'failure' value. [BEGIN] */
if (typeof removeLocalStorageItem !== 'function')
{
function removeLocalStorageItem(key)
{
if (typeof (Storage) !== 'undefined')
{
if (localStorage.getItem(key) === null)
{
return false;
};
localStorage.removeItem(key);
if (localStorage.getItem(key) === null)
{
return true;
}
else
{
return false;
};
}
else
{
return false;
};
};
};
/* Conditional Function supplements localStorage.removeItem(...) to return a [Boolean] 'success' or 'failure' value. [END] */
Related
Let's say I have the following object with two functions as properties:
const foo = {
f1: () => {...},
f2: () => {...},
}
I would like to perform a specific action (for example, throw a custom error) when someone tries to execute a function that doesn't exist on the foo object.
I've tried using a get proxy, but that throws an error even when I'm not trying to execute f3, such as in the following code:
if (foo.f3) {...}
So how can I write my proxy in such a way that foo.f3 returns undefined as it usually would, but foo.f3() does throw an error?
Here's a partial solution, inspired by Unmiss.
const handler = {
get: function(obj, prop) {
if (prop in obj) {
return obj[prop];
} else {
return () => {
throw new Error(`Foo.${prop} is undefined`);
}
}
}
};
The problem with this is that while it accomplishes the goal of only throwing an error when you actually try to execute Foo.f3(), since Foo.f3 is now equal to that anonymous function is doesn't return undefined anymore, meaning that (as far as I can tell) if (Foo.f3) {...} will always return true.
Edit: as #paulpro points out:
You absolutely cannot do that. foo.f3 is either undefined or some
callable with custom logic; it cannot be both.
The best we could do is trap f3 in foo statements using the has trap, but this would mean if (f3 in foo) and if (foo.f3) would now have different results, which seems like a big red flag.
Is this what your asking for?
https://jsfiddle.net/MasterJames/bhesz1p7/23/
[obviously you need to F12 your dev tools to see the console output or change as desired]
Only real difference is to return undefined after throwing. It's as if the function executed without doing anything since it doesn't exist.
I'm sure there's a different solution based on the actual use case, but I like the idea/question. Keeps things more stable etc.
let foo = new Proxy(
{
f1: function (val) {
console.log(' F1 value:' + val);
return 'called OKAY with', val;
}
},
{
get: function(obj, prop) {
console.log("obj:", obj, " prop:", prop);
if (prop in obj) {
console.log("Found:", prop);
return obj[prop];
}
else {
console.log("Did NOT find:", prop);
throw new Error(`Foo.${prop} is undefined not called returning undefined`);
return undefined;
}
}
});
console.log("\nFoo Tester started");
console.log(' Does F1 exists', foo.f1 !== undefined);
console.log(' called F1 result:', foo.f1('passed') );
try {
console.log(' Does F2 exists', foo.f2 !== undefined);
console.log(' called F2 result:', foo.f2('passed') );
}
catch (err) {
console.log(' Error calling F2:', err );
}
console.log("Foo Tester finished");
Not sure you want to try-catch or not that's also up to you so in the end checking if it's real and a function is the same difference depending on how your going to handle the error.
if (foo.f2 && foo.f2.constructor === Function && foo.f2()) console.log("okay!");
Again you call build a safeCall wrapper more like this or something in between?
possible calling foo's 'customThrow' if it exists or what-have-you, so many possibilities with JS.
Okay so it took me sometime but I have a solution now.
I was not fully understanding your question, which I reformulated as a question within the question for myself to understand the issue better as it is complicated.
Basically you want to know if it's being called or not so the function you need in the proxies 'get' is 'isCalling'.
The solution is not clean in JS Fiddle because it's messy there at least for this kind of problem's solution.
Basically the solution is a sentence is, "you have to use an error to get a stack trace then retrace the source code that is calling and look for a right bracket or not.", to determine how it's being called and return whatever you want then).
[Please note this depends on your code and how you call it so you would adjust as needed.]
Since you have to find the location in the source code that's being called from it's way better if there is no inline script tag as is the case in this JSFiddle example. I'm using outerHTML to get the source, when arguments.callee.caller.toString() is better from an actual JS file. You'll also not the location from the stacktrace is skewed by odd behavior here, so with a normal JS file the code would align properly using other solutions are recommended. If anyone knows how to get a clean source that aligns with the error trace every time with script-tag blocks etc. Also note coming but not existing yet are things like Error.lineNumber.
[Please don't bother with the version history it was a nightmare to sort this one out. And again you would be better to use other npm packages to do the source code from stack trace parts.]
Anyway the example I believe achieves what you want but in principle demonstrates what you'd need to do better in a given real (no Fiddle) situation. I'm pretty sure doing this is not a great solution in production either and I've not tested the timing (performance speed) but if it really was that important to your cause (and no other better solution which I doubt) then it will work.
Originally I discovered this technique when I was doing something experimental, and instead of just sending another argument I was checking to see what was actually calling it and adjusting the functions action depending.
Usages are extensive when you start to think more about it as I did last year when I first did something like this. Examples are as an extra function execution Security Check, Realtime mystery-bug Debug Solution, a way to execute the function differently without passing more arguments, runaway recursive loops (how long is the stack), to name a few.
https://jsfiddle.net/MasterJames/bhesz1p7/90/
let foo = new Proxy(
{
f1: function (val) {
console.log(' F1 value:' + val);
return 'called OKAY with', val;
}
},
{
isCalling: function() {
let stk = new Error();
let sFrms = this.stkFrms(stk.stack);
console.log("stkFrms:", sFrms);
//BETTER From real pure JS Source
//let srcCod = arguments.callee.caller.toString()
let srcCod = document.getElementsByTagName('html')[0].outerHTML.split("\n");
let cItm = sFrms[(sFrms.length - 1)];
if(cItm !== undefined) {
let cRow = (parseInt(cItm[1]) - 3);
let cCol = (parseInt(cItm[2]) + 1);
let cLine = srcCod[cRow];
let cCod = cLine.substr(cCol, 1);
if(cCod === '(') return true;
}
return false;
},
stkFrms: function (stk) {
let frmRegex1 = /^.*at.*\(.*\:([0-9]*)\:([0-9]*)\)$/;
let frmRegex2 = new RegExp(frmRegex1.source, 'gm');
let res = [], prc, mtch, frms = stk.match(frmRegex2);
for(mtch of frms) {
prc = frmRegex1.exec(mtch);
res.push(prc);
}
return res;
},
get: function(obj, prop) {
if (prop in obj) {
console.log("Found:", prop);
return obj[prop];
}
else {
if(this.isCalling() === false) {
console.log("Did NOT find:", prop);
return undefined;
}
else {
console.log("Did NOT find return custom throw function:", prop);
return function() {throw new Error(`Foo.${prop} is undefined`);}
}
}
}
});
console.log("foo.f1:", foo.f1);
console.log("foo.f1('passed'):", foo.f1('passed'));
console.log("foo.f2:", foo.f2);
try {
console.log("foo.f2('passed2'):", foo.f2('passed2'));
}
catch(err) {
console.log("foo.f2('passed2') FAILED:", err);
}
console.log("'f2' in foo:", 'f2' in foo);
Okay so a verbal run through:
You want to check foo.f2 is undefined so it returns that because it's not being called.
If you do call it (f2) without simply checking first and erroring as needed, and you don't want to try-catch to throw your custom error based on the function name, you want it to return an actual function that will throw a custom error.
You also want to use 'in' to see that it's undefined, which is the same as false (maybe hack it further to send false instead of undefined via something like isCallingFromIn too.
Did I miss anything? Is this not what you all thought was impossible?
What I'm trying to do is the following:
Check if a record with a filter criteria exists
If it does, do nothing
If it does not, create it with some default settings.
Now I could do it with 2 queries:
function ensureDocumentExists(connection, criteria, defaults) {
return r.table('tbl')
.filter(criteria)
.coerceTo('array') // please correct me if there's a better way
.run(connection)
.then(([record]) => {
if (record) {
return Promise.resolve() // Record exists, we are good
} else {
return r.table('tbl') // Record is not there we create it
.insert(defaults)
.run(connection)
}
})
}
But the fact that r.branch and r.replace exists, suggest me that this would be possible in a single run. Is it? I was thinking something like this:
function ensureDocumentExists(connection, criteria, defaults) {
return r.table('tbl')
.filter(criteria)
.replace(doc => r.branch(
r.exists(doc), // If doc exists (I'm just making this up)
doc, // Don't touch it
defaults // Else create defaults
)).run(connection)
}
But I'm not sure if replace is the right method for this, and also no idea how to check if the given row exists.
Figured it out:
function ensureDocumentExists(connection, criteria, defaults) {
return r.table('tbl')
.filter(criteria)
.isEmpty() // isEmpty for the rescue
.do(empty => r.branch(
empty, // equivalent of if(empty)
r.table('tbl').insert(defaults), // insert defaults
null // else return whatever
).run(connection)
})
}
I am using the below function, I am trying to generalize the function without using hardcoded values. How i can achieve it?
function ChangeIDToString(strCondition,id)
{
if (strCondition.indexOf("AssignedTo") > -1)
return GetUserName(id)
else if (strCondition.indexOf("ClaimStatusId") > -1)
return GetClaimStatus(id)
else if (strCondition.indexOf("ClaimTypeId") > -1)
return GetClaimType(id);
else
return id;
}
It would be nice to see what your functions do.
But in your functions, you can declare:
var j={"id":"return of your function string here"};
JSON.stringify(j); // '{"id":"return of your function string here"}'
You could create an object of functions, and then call a function named by strCondition using bracket notation and dynamic property name. Something like this:
var objOfFunctions = {
GetUserName: function (id) {...},
GetClaimStatus: function (id) {...},
GetClaimType: function (id) {...}
};
function ChangeIDToString(strCondition,id) {
if (!objOfFunctions.hasOwnProperty(strCondition)) {
return id;
}
return objOfFunctions[strCondition](id);
}
In a case you already have a lot of calls to the functions in objOfFunctios somewhere else in your code, you can populate that object with references too.
A live demo using references in objOfFunctions at jsFiddle.
EDIT
After discovered that you've asked this same question before, it looks like my original answer still hardcodes too much. (Your comment to void's similar answer.)
The goal can still be achieved by passing a function reference instead of a string to ChangeIDToString. Though you will lose the ability to check, which function will be called. Like this:
function ChangeIDToString(refCondition,id) {
if (typeof refCondition !== 'function') {
return id;
}
return refCondition(id);
}
// Invoke example
console.log(ChangeIDToString(GetClaimType, 'some_ID'));
A demo at jsFiddle.
If the string can't be replaced with a reference, your last resort is to use eval(), but it's strongly recommended not to do so.
An eval demo at jsFiddle.
You weren't clear as to where/how you wanted JSON to fit into your solution, but if you are saying that there will definitely be one of those 3 strings passed into the function and which function gets called from there is based on which string is passed in, then you could leverage the fact that all arguments are optional in JavaScript. As long as your function only gets called with 2 arguments (id and one of the others), this would do it:
function ChangeIDToString(id, user, claimStatusId, claimTypeId)
{
if (user !== null)
return GetUserName(id)
else if (claimStatusId !== null)
return GetClaimStatus(id)
else if (claimTypeId !== null)
return GetClaimType(id);
else
return id;
}
https://jsfiddle.net/m271cpum/ for more complete example.
According to https://github.com/jquery/jquery/blob/9434e03193c45d51bbd063a0edd1a07a6178d33f/src/event.js#L21-L27
There are two functions in event.js in jquery that return true and false:
from events.js
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
I know they are good. But I don't understand the reasoning for this.
Did you look and see where they are used?
They are used as a stubs for assignments that need a function that returns a boolean.
For example on line 670 of the same document:
this.isDefaultPrevented = returnTrue;
isDefaultPrevented is a function. Thus it needs a function that returns true as the default functionality.
Consider their usage:
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented ||
// Support: Android < 4.0
src.defaultPrevented === undefined &&
src.getPreventDefault && src.getPreventDefault() ?
returnTrue :
returnFalse;
Do this or something similar across several functions. It's easier to type returnTrue, than have to spell out function() { return true; } every time, isn't it? Code reuse and readability.
I am creating a module that takes in several complicated JSON files and would like some code to give the user feedback if certain elements are absent.
Below is the way I am doing it now, but I cannot help to think there must be a cleaner, less hacky way.
var _und = require("underscore");
//this function takes a list of required attributes and ensures they are present
var check_req_attr = function(config, req_attr, callback) {
var config_attr = Object.keys(config);
var absent_attr = _und.difference(req_attr, config_attr); //slightly hacky code that checks to ensure config has correct vars
if (absent_attr.length !== 0) {
throw Error("missing following attributes from config:" + absent_attr);
} else {
callback();
};
};
It just feels...dirty. If there is no real elegant way to do it, I would be open to critiques on my code. Thanks!
Parse the JSON to JS.
var data = JSON.parse(theJson);
Use something like:
function hasKey(obj, key) {
return typeof obj[key] !== 'undefined';
};
function hasKeys(obj, keys) {
for (var i = 1, len = keys.length; i < len; i++) {
if (!hasKey(obj, keys[i])) {
return false;
};
};
return true;
};
Now you can simply do:
if (hasKeys(data, ["firstKey", "secondKey", "thirdKey"]) {
console.log("valid");
};
This should be the way to do it, using every and has:
if (_und.every(req_attr, function(attr) {
return _und.has(config, attr);
}))
throw new Error();
In a native environment, you would just use the in operator:
req_attr.every(function(attr){ return attr in config; })
I think your solution is actually quite elegant! No need for an anonymous function, and the loop (which must happen at some point, obviously) neatly abstracted away with difference.
Two suggestions:
I'd give the function a synchronous signature. No callback argument. There can't be any reason to go async if you honor the function signature (i.e. basing your answer on config and req_attr only).
I'd change the function to return the missing properties (attributes is wrong term). You could also add a requireProperties function that uses this "check" function that would throw if a property was missing. This allows for different kind of uses.
Why don't you try with something like:
obj = JSON.parse(json);
and then check
if(obj.YourProperty == undefined){
//do something..
}
Hope i understood your question.. It should work with complicated JSON files too.. Good luck ;)
You could also use the in operator (requiredAttr in obj):
function objHasAllRequiredAttrs(obj, attrNames) {
return attrNames.reduce(function(memo, attrName) {
return memo && (attrName in obj);
}, true);
}
objHasAllRequiredAttrs({foo:1}, ['foo']); // => true
objHasAllRequiredAttrs({bar:1}, ['foo']); // => false