i want to pass value to chrome.storage.sync.get() function.
chrome.storage.sync.get('privateKey', function(data, e) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(e.detail.encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
but e.detail.encryptedVal is showing me as undefined.
The callback of .get() expects exactly 1 parameter.
By passing a function that takes 2 parameters (i.e. function(data, e) {...}), you do the following:
The function is called with one parameter. It is assigned to a callback-local variable data.
The second parameter stays undefined. It is assigned to a callback-local variable e.
If there was a variable e in the outer scope, it is no longer accessible.
I assume the part 3 is exactly your problem. You had a variable e in the scope where you called .get(), but you made it inaccessible.
Generally, due to the concept called closures, you don't actually need to pass e inside the scope - you just use the variable from the outer scope, and it will be retained in memory until the function executes. Think of it as a "locally global" variable, if that makes any sense. If it doesn't, there are better explanations.
With that in mind:
chrome.storage.sync.get('privateKey', function(data) { // just don't mention e here
/* ... */
// Just use e inside if it comes from outer scope
var uncrypted = decrypt.decrypt(e.detail.encryptedVal);
/* ... */
});
Better yet, let's make that into a function:
function decryptValue(value, callback) {
chrome.storage.sync.get('privateKey', function(data) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var decrypted = decrypt.decrypt(value);
callback(decrypted);
}
}
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something
});
/* ... */
Note that callback variable? While you can use decrypted inside the callback of .get(), due to the fact it's asynchronous you can't use it outside. There is a very good overview of the problem, and another one here. Basically, .get() is asynchronous so you HAVE to use a callback.
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something with decrypted
});
// Here, decrypted is not yet computed
/* ... */
Most of Chrome API is asynchronous. I would recommend to read You Don't Know JS book on the topic.
So, from the comments bellow, I suppose you'd like to pass the value to get callback in order to user it in the callback. Unfortunately, this can't be done the way you want it to be done. But, what you can do is write a decrypt function that will take the encryptedVal as an argument, and simply use it
function decrypt(encryptedVal) {
chrome.storage.sync.get('privateKey', function (data) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
}
Do note that this function uses asynchronous code and you may not return from it as you'd expect.
Related
I've a question about subsequent function calls or somehow. I've this code here:
let socket = new WebSocket("localhost:8181");
socket.subscribe("abc").bind("test", function (response) {
console.log(response);
});
subscribe(channel) {
//Here I do some things
return this;
}
bind(eventName, callback) {
//Here I need the "abc" value
}
Currently I'm calling a second function after another to first subscribe something and then bind it. The problem is that I need the value passed to the subscribe function in the following bind function.
Currently I'm returning this because otherwise .bind() would be undefined because of the scope bla bla so because of this I can't just return the channel. Does someone has an idea how I can get this done without changing the function call structure?
You can't return this and also pass a variable. I think your best bet may be wrap your subscribe call in a closure so that you can keep local state.
function createAndSubscribe(abc) {
// You can create other local variables here
let otherLocal = 'foo';
let socket = new WebSocket("localhost:8181");
socket.subscribe(abc).bind("test", function (response) {
// Use abc or foo here
});
}
createAndSubscribe('abc');
Every time you call the function createAndSubscribe, it creates a unique closure that holds the value of abc and any other variables that you create.
I am refactoring javascript and have a lot of similar POST calls to the same PHP url.
It would be nice to pass the postdata and callback function (defined in JiraChangeStatus), to a common function (SendPost).
I'm new to javascript, and was under the impression that it was possible to use a pointer / reference if the variable was the property of an object.
Have also tried using a variable for "xhr" instead of an object property, declaring "xhr" within JiraChangeStatus instead of SendPost, and even declaring it globally as a sanity check.
function JiraChangeStatus(index) {
var postdata = "&status="+document.getElementById("jiraT"+(index).toString()).value;
SendPost("changestatus.php",postdata, function(obj) {
alert("readyState: "+obj.xhr.readyState+"\r\nstatus: "+obj.xhr.status);
});
}
function SendPost(module,postdata,fn)
{
var obj = {xhr: new XMLHttpRequest()}
var issuekey = GetJson(document.getElementById("issue").value,'key');
obj.xhr.open("POST", "modules/jira/"+module, true);
obj.xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
obj.xhr.onreadystatechange = fn(obj);
obj.xhr.send("username=user&issuekey="+issuekey+postdata);
}
When the callback function is executed I always see readystate 1 and status 0. I expect to see 4 and 200.
It appears javascript is passing a copy of the xhr object to the callback rather than the actual object.
These functions work when merged. Unless the properties of "xhr" are set within the scope of the callback function for "xhr", the callback doesn't get the value.
Please let me know what I'm doing wrong.
Thanks to Pointy and Bergi.
When it comes to solving my user story, there were 2 problems with the code.
The first was that when I used obj.xhr.onreadystatechange = fn(obj), it instantly evaluated the fn. That instant evaluation caused "this" to have a mouse click as the event trigger, rather than onreadystatechange.
The second was redundancy. There was no need to pass xhr as a parameter when "this" references xhr.
This code doesn't work (irrelevant lines omitted):
function JiraChangeStatus(index) {
SendPost("changestatus.php",postdata, function(pass) {
console.log("This:\r\n"+this); //This: [object Window]
});
}
function SendPost(module,postdata,fn) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = fn();
}
This code works fine (irrelevant lines omitted):
function JiraChangeStatus(index) {
SendPost("changestatus.php",postdata, function(pass) {
console.log("This:\r\n"+this); //This: [object XMLHttpRequest]
});
}
function SendPost(module,postdata,fn) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = fn; //no parentheses here fixed my use case
}
Therefore I would accept Pointy and Bergi's comments as they solved my use case.
However, the question I posted was about passing a reference into a callback function and I want to give useful info to people who find it in a search.
The answer to my question of how to pass reference to a callback when parentheses cause immediate evaluation was here: How can I pass a parameter to a function without it running right away?
To validate that it "worked" for my use case I wrote some really ugly and unnecessary code which shows that you can pass a parameter into a callback function with parenthesis by simply having its immediate evaluation return a function.
Since JavaScript allows objects to be assigned by reference, and "xhr" is an object, as Bergi said I would not have needed an object wrapper (irrelevant lines omitted):
function SendPost(module,postdata,fn)
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = fn(xhr); //immediately evaluates fn
}
function JiraChangeStatus(index) {
SendPost("changestatus.php",postdata, function(pass) {
//the result of immediate evaluation is a function
//with the parameter "pass" in its scope
return function() {
console.log("This:\r\n"+this); //This: [object XMLHttpRequest]
console.log(this.responseText); //returns the expected response text
console.log("Passed Reference:\r\n"+pass); //Passed Parameter: [object XMLHttpRequest]
console.log(pass.responseText);
//Both of these stop future callbacks
//this.abort();
//pass.abort();
}
});
}
I'm trying to call a js function within another one, but use the argument to specify the function. ie depending on the argument passed, it will call a different function
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
check+n();
}
else
}
So, for example, if the argument 'Balloons' was passed as n, then it will call the function checkBalloons(). "check+n();" is not currently working here. Sorry for my lack of simple js syntax!
If the function is defined in the global scope (browser) you can do:
window["check"+n]();
or some tenants like Node.js you would access it from global object.
global["check"+n]();
if it is a part of some other object then you would do the same.
obj["check"+n]();
Functions and properties defined on an object can be accessed using [] convention as well. i.e obj["propFuncName"] will give you reference to it, so in case of methods you add () to invoke it.
If the function is global, you would do this:
window["check" + n]();
or, you could put your function in an object like so:
myNamespace = {};
myNamespace.checkSomething = function(){ /* ... */ }
// call it like this:
myNamespace["check" + n]();
The answers thus far are correct, but lack explanation.
In JavaScript, you cannot call a function by name when that name is a string. What you can do is retrieve a value from an object by name, and if that value happens to be a function, you can then call it. For example:
var myObject = {};
myObject.myFunction = function() { alert('test!'); };
// Get the property on `myObject` called `myFunction`
var theFunctionLookup = myObject['myFunction'];
// Since that property was a function, you can call it!
theFunctionLookup();
In the browser, functions that are defined in the global scope are attached to the window object. For example, this works:
function myFunction() { alert('test'); }
var theFunctionLookup = window['myFunction'];
theFunctionLookup();
You can shorten the last two lines into one:
function myFunction() { alert('test'); }
// Look up and call the function in one line.
window['myFunction']();
For the same reasons, you can use a dynamically-calculated string to look up functions.
function checkBalloon() {
alert('checking balloon');
}
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
window['check' + n]();
check+n();
}
}
toggle('Balloon');
if you do this way:
if (sessionStorage['toggle'+n]== 0){
window["check" + n]();
}
will work
In my code I need to call an object method, retrieve the data from its callback, and pass it to another method or function.
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
However, the callback does not recognize any functions/objects/variables outside its scope.
What I've tried to do right now is wrap everything around a function.
var myData = '';
(function(myData) {
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
myData = data;
}
);
});
doAwesomeStuff(myData);
However that doesn't work either.
Anybody know how to properly accomplish this?
You haven't really given us enough to go on there, but this statement:
However, the callback does not recognize any functions/objects/variables outside its scope.
...is incorrect. A function has access to everything in scope where it's defined, so for instance:
var a = 10;
function foo(b) {
bar(5);
function bar(c) {
alert(a + b + c);
}
}
foo(12); // alerts "27"
Note how bar had access not only to c, but also to b (from the call to foo) and a (from the outermost scope shown).
So in your example, the anonymous function you're passing in as the callback has access to everything that's in scope where it's defined; doAwesomeStuff having been defined elsewhere presumably has access to different information, so you'll have to have the callback pass it any data it needs.
So I'm guessing your code looks something like this:
function doAwesomeStuff(data) {
// ...
}
function doSomethingNifty() {
var a = 10,
b = 20;
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
}
...and you want doAwesomeStuff to have access to a and b from the call to doSomethingNifty. If so, your only options are to pass them into it as arguments (probably best) or export them to variables some scope that doSomethingNifty and doAwesomeStuff share (probably not ideal, too much like globals).
You can bind required variables to the function passed into the async method.
Also, this SO question has a good treatment of the topic.
Your second version is not going to work at all, since you are trying to immediately access the data that are not yet available (not until the callback has been invoked.)
Your first method:
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
looks fine. Please provide more details on what is not working.
One problem could be that getSomeData() does not actually call the callback function.
doAwesomeStuff() can modify many different variables from the received data. The variables which can be accessed by doAwesomeStuff() are those that were available to it (in its scope) where it was created..
I want to write my own function in JavaScript which takes a callback method as a parameter and executes it after the completion, I don't know how to invoke a method in my method which is passed as an argument. Like Reflection.
example code
function myfunction(param1, callbackfunction)
{
//do processing here
//how to invoke callbackfunction at this point?
}
//this is the function call to myfunction
myfunction("hello", function(){
//call back method implementation here
});
You can just call it as a normal function:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction();
}
The only extra thing is to mention context. If you want to be able to use the this keyword within your callback, you'll have to assign it. This is frequently desirable behaviour. For instance:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction.call(param1);
}
In the callback, you can now access param1 as this. See Function.call.
I too came into same scenario where I have to call the function sent as parameter to another function.
I Tried
mainfunction('callThisFunction');
First Approach
function mainFuntion(functionName)
{
functionName();
}
But ends up in errors. So I tried
Second Approach
functionName.call().
Still no use. So I tried
Third Approach
this[functionName]();
which worked like a champ. So This is to just add one more way of calling. May be there may be problem with my First and Second approaches, but instead googling more and spending time I went for Third Approach.
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction(); // or if you want scoped call, callbackfunction.call(scope)
}
object[functionName]();
object: refers to the name of the object.
functionName: is a variable whose value we will use to call a function.
by putting the variable used to refer to the function name inside the [] and the () outside the bracket we can dynamically call the object's function using the variable. Dot notation does not work because it thinks that 'functionName' is the actual name of the function and not the value that 'functionName' holds. This drove me crazy for a little bit, until I came across this site. I am glad stackoverflow.com exists <3
All the examples here seem to show how to declare it, but not how to use it. I think that's also why #Kiran had so many issues.
The trick is to declare the function which uses a callback:
function doThisFirst(someParameter, myCallbackFunction) {
// Do stuff first
alert('Doing stuff...');
// Now call the function passed in
myCallbackFunction(someParameter);
}
The someParameter bit can be omitted if not required.
You can then use the callback as follows:
doThisFirst(1, myOtherFunction1);
doThisFirst(2, myOtherFunction2);
function myOtherFunction1(inputParam) {
alert('myOtherFunction1: ' + inputParam);
}
function myOtherFunction2(inputParam) {
alert('myOtherFunction2: ' + inputParam);
}
Note how the callback function is passed in and declared without quotes or brackets.
If you use doThisFirst(1, 'myOtherFunction1'); it will fail.
If you use doThisFirst(1, myOtherFunction3()); (I know there's no parameter input in this case) then it will call myOtherFunction3 first so you get unintended side effects.
Another way is to declare your function as anonymous function and save it in a variable:
var aFunction = function () {
};
After that you can pass aFunction as argument myfunction and call it normally.
function myfunction(callbackfunction) {
callbackfunction();
}
myfunction(aFunction);
However, as other answers have pointed out, is not necessary, since you can directly use the function name. I will keep the answer as is, because of the discussion that follows in the comments.
I will do something like this
var callbackfunction = function(param1, param2){
console.log(param1 + ' ' + param2)
}
myfunction = function(_function, _params){
_function(_params['firstParam'], _params['secondParam']);
}
Into the main code block, It is possible pass parameters
myfunction(callbackfunction, {firstParam: 'hello', secondParam: 'good bye'});
callbackfunction = () => {}
callbackfunction2(){
}
function myfunction1(callbackfunction) {
callbackfunction();
}
//Exe
myfunction1(callbackfunction);
myfunction1(callbackfunction2.bind(this));
Super basic implementation for my use case based on some excellent answers and resources above:
/** Returns the name of type member in a type-safe manner. **(UNTESTED)** e.g.:
*
* ```typescript
* nameof<Apple>(apple => apple.colour); // Returns 'colour'
* nameof<Apple>(x => x.colour); // Returns 'colour'
* ```
*/
export function nameof<T>(func?: (obj: T) => any): string {
const lambda = ' => ';
const funcStr = func.toString();
const indexOfLambda = funcStr.indexOf(lambda);
const member = funcStr.replace(funcStr.substring(0, indexOfLambda) + '.', '').replace(funcStr.substring(0, indexOfLambda) + lambda, '');
return member;
}