Unable to set variable in a function calling it from another function - javascript

I'm currently running a node js file and I'm receiving a post like so.
app.post('/', function (req, res) {
var firstLine = req.body.firstLine;
var secondLine = req.body.secondLine;
var previewID = req.body.previewId;
takeWebshot(firstLine)
return res.end('<h1>Hello, Secure City World!</h1>');
});
when I console.log firstLine it's set to the req.body.firstLine let us say it's "Hello". So firstLine = "Hello".
I then pass this variable to takeWebshot(firstLine).
When I console log fLine in takeWebshot I can see "Hello".
function takeWebshot(fLine) {
console.log(fLine);
var options = {
onLoadFinished: {
fn: function() {
document.getElementById("user_input").value=fLine;
document.getElementById("second_user_input").value="AMAZON USERNAME";
document.getElementById("preview_btn").click();
}
},
takeShotOnCallback: true,
captureSelector: '.fancybox-outer'
};
webshot('example.com/testy.html', './example.png', options, function(err) {
if (err) return console.log(err);
console.log('OK');
});
};
Here is my problem in this line:
document.getElementById("user_input").value=fLine;
fLine is not read anymore. I tried passing fLine into the function here like so fn: function(fLine). fLine now equals "success". In my limited knowledge of JS it appears that the function fn: function() is a promise callback in the main node-module webshot. The goal is I need
document.getElementById("user_input").value=fLine; to equal firstLine that is being sent by the other function.
EDIT: webshot is calling a phantom js to open a url headless. I'm trying to pass the variable so it can fill out a form when it calls it to take a screen shot. That is why it has document.

The documentation for webshot mentions that the script will get serialised before being passed to Phantom
Note that the script will be serialized and then passed to Phantom as text, so all variable scope information will be lost. However, variables from the caller can be passed into the script as follows:
Cf https://www.npmjs.com/package/webshot#phantom-callbacks
So you should probably follow their instructions and have something like this:
onLoadFinished: {
fn: function() {
document.getElementById("user_input").value=this.fLineSnapshot;
document.getElementById("second_user_input").value="AMAZON USERNAME";
document.getElementById("preview_btn").click();
},
context: {
fLineSnapshot: fLine
}
},

you cannot pass fLine into fn: function(fLine) since it is a callback function of onLoadFinished, the scope of the variable is not reachable inside, you can try fn: () => {
document.getElementById("user_input").value=fLine;
} this might work as fat arrow function with allow access to use variable outside function.

Related

Can you set a function inside an object in chrome.storage.local?

Im building a chrome app and I am trying to add a function inside an object inside chrome.storage.local but when im doing it it does not appear if you try to get it (all the other things appear but not the function)
But if you try to do it on a normal object like
let a = {
b: function() {
return 'This is working'
}
};
then it works.
It wouldn't be a problem if I could just use eval but due to security on the chrome app it does not work.
What im trying to do is:
chrome.storage.local.set({
'obj': [{
example: 'hello',
fn: function() {
return 'This is not working'
}
}]
});
Then if you do
chrome.storage.local.get('obj', function(e) {
console.log(e.obj)
});
Then it will return with
Array (length 1): example: "hello"
and not the function,
Thanks.
Store arguments and the body like this
{function:{arguments:"a,b,c",body:"return a*b+c;"}}
Retrieve it and instantiate the function:
let f = new Function(function.arguments, function.body);

How do you (best) access 'this' in an object method passed as callback [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I'm writing a simple word game to practice my javascript (I'm new to it) using the NPM package prompt (https://www.npmjs.com/package/prompt) to query the user when I need a response.
Since I come from an OOP background (in other languages) I've been experimenting with encapsulating different functionalities in different objects. So I have all the prompt related code in one object, like this
function Prompter() {
this.getUserName = function (callback) {
var schema = {
properties: {
name: {
description: "Tu nombre por favor:",
pattern: /^[ñÑa-zA-Z\s\-]+$/,
message: 'Solo letras, por favor',
required: true
}
}
};
prompt.get(schema, callback);
};
}
and game logic in another object like this (this is the relevant part of the code)
function Game() {
this.qGenerator = null;
this.prompter = null;
this.user = "";
this.doNextRound = function () {
//// omitted for brevity
};
this.init = function () {
this.qGenerator = new QuestionGenerator();
this.prompter = new Prompter();
};
this.startGame = function () {
this.prompter.getUserName(this.storeUserName);
};
this.storeUserName = function (err, result) {
if (err) {
this.handleErr(err);
return;
}
this.user = result.name;
this.doNextRound();
};
}
and I start the game like this
const game = new Game();
game.init();
game.startGame();
The problem I have is that in the Game method storeUserName, which I've passed as a callback to prompt, I have no access to the Game object through this, and thus, when I call
this.doNextRound
inside of storeUserNameI get
TypeError: this.doNextRound is not a function
I understand why, as this refers to Node inside the callback. But I don't know how to keep a reference to the correct this inside the method I'm passing as callback. I understand how to do it in more 'vanilla' Javascript -- using that = this, or apply,etc, but I'm not sure what the best way to handle this inside Node callbacks is when you're passing another object's methods. Any advice much appreciated.
Use Function.prototype.bind:
this.prompter.getUserName(this.storeUserName.bind(this));
or an arrow function:
this.prompter.getUserName( _ => this.storeUserName() );
Either of those will work.

Calling a Dynamically set Function Object Property from within the Object

From within my webpage I am creating an object and trying to call a dynamically set function from within it. The dynamic function however, isn't being executed.
Here is a subset of the Object:
var LightBoxLogin = {
DialogBox: null,
SuccessFunction: null,
..........
Login: function(){
console.log(LightBoxLogin.SuccessFunction) // Displays "TestSubmit()"
LightBoxLogin.SuccessFunction(); // does nothing, should alert the page
}
}
LightBoxLogin.SuccessFunction is set with:
function SuperLightbox(functOnSuccess)
{
LightBoxLogin.SuccessFunction = functOnSuccess;
if(IsLightboxNeeded())
{
LightBoxLogin.Login();
}
else{
alert("Not needed");
}
}
And called like:
function TestSubmitHandler ()
{
SuperLightbox(TestSubmit);
}
function TestSubmit ()
{
alert('TEST SUBMIT ALL CAPS');
}
Let me know if im missing anything.
I just need to execute the function passed as a parameter initially.
Instead of the line
SuperLightBox(TestSubmit);
Use the function name as a String instead:
SuperLightBox("TestSubmit");
This means in the Login:function() this line:
LightBoxLogin.SuccessFunction();
Will be replaced with:
window[LightBoxLogin.SuccessFunction]();
This yields the results I was looking for, but beware; it only works if the desired function is accessible globally in the page.

Mootools Request.JSON dynamic callback

Developing an app where all tabular data is returned as an object.
Some cells will have onclick events on them.
The JSON object is coming back fine and there is a key in the object call 'cb'.
This is set by the logic on the server.
My question is the object key cb will contain a string, how can I run that as a valid function without using eval()
Example:
var archive = function() {
console.log('archiving');
}
new Request.JSON ({
...
onSuccess: function(r){
//r.cb: 'archive'
docuemnt.id(td).addEvent('click', r.cb);
}
...
});
docuemnt.id(td).addEvent('click', eval(r.cb)); // works looking for alternative
I know i am over thinking this and it should not be that difficult.
Must not have had enough coffee yet today.
Use square bracket notation. If your function is in the global scope, use window[r.cb]:
new Request.JSON ({
...
onSuccess: function(r) {
//r.cb: 'archive'
document.id(td).addEvent('click', window[r.cb]);
}
...
});
If your function is not in the global scope, move your functions into an object:
var callbacks = {
archive: function () { ... },
foo: function () { ... },
...
}
Then use callbacks[r.cb].

Code Structure with ExtJS

I'm trying to organize my ExtJS javascript a little better. I've an ExtJS object like this:
Ext.define('QBase.controller.ControlModelConfigurationController', {
extend: 'Ext.app.Controller',
views: [
'ControlModelConfiguration'
],
init: function() {
console.log('Initialized ControlModelConfigurationController');
this.control({
'#testBtn': {
click: this.loadModel
}
});
},
loadModel: function() {
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response)
{
if (success)
{
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml,parent);
Ext.Array.forEach(nodes,handleNode);
}
}
});
},
handleNode: function(items) {
console.log(item.name);
}
});
The posted code above is not working. Ext.Array.forEach(nodes,handleNode) causes trouble. Instead of using an anonymous function like :
...
Ext.Array.forEach(nodes,function(item) {
console.log(item)});
}
...
I'd like to extract the anonymous function as a named external one. Unfortunately I'm unable to figure out the right syntax to establish a code structure as shown above.
Meanwhile, I figured out, that putting
function handleNode(item) {
{console.log(item)}
}
at the very end of the file works. Is it possible to make the handleNode method an object - "member" of the controller?
Thanks in advance
Chris
handleNode is a member of the containing object. When loadModel is called, this contains the right object, but at the time the callback is invoked, it will not point to the one we are interested in. You can save this to the local variable self, and use it instead.
loadModel: function() {
var self = this
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response)
{
if (success)
{
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml,parent);
Ext.Array.forEach(nodes, self.handleNode);
}
}
});
},
The solution posted by vhallac is not entirely correct. It assumes that handleNode doesn't reference the current object through this variable. Maybe just a typo, but additionally it's not really the ExtJS way...
Whenever ExtJS provides a callback parameter, there is nearly always a scope parameter to set the value of this within the callback function.
loadModel: function() {
console.log('Load Model....');
var conn = new Ext.data.Connection;
conn.request({
url: 'partsV10.xml',
callback: function(options, success, response) {
if (success) {
alert("AHHH");
var dq = Ext.DomQuery;
var xml = response.responseXML;
var nodes = dq.select('part', xml, parent);
Ext.Array.forEach(nodes, this.handleNode, this);
}
},
scope: this
});
},
handleNode: function(node) {
// From within here you might want to call some other method.
// Won't work if you leave out the scope parameter of forEach.
this.subroutine();
}
Just like forEach uses a scope parameter, the request method uses a scope config option. This is ExtJS convention for passing around the scope. You can alternatively create an extra local variable and reference the scope from there, but in the context of ExtJS this style will feel awkward, plus (I'm pretty sure) it's a lot more bug-prone.

Categories