my requirements are to send an object method as a response using express. This is so that I can create dynamic onClick js code in front-end.
const data = {
message: "Hi",
click: () => {
console.log("Hello world");
}
};
res.send(data);
I tried to send it, but the method won't send. The log for the above sample code in front-end JS is as below.
{message: "Hi"}
My workaround was to send the whole function as a string and then use Function Constructor to parse the string. It worked, but I read other forum entries where it said it is very bad practice to parse a string as a function.
Kindly suggest the ways through which I can solve this problem.
You basically have two choices:
Use the Function constructor as you are. It's fine if you can trust who you're getting the string from that you're converting into code. What you shouldn't do is use it when you don't need to convert a string to a function (e.g., there's a better way), or with a string from a source you can't trust.
Don't send dynamic handlers at all. Instead, have a set of standard handlers in a script that you include in your page:
const handlers = {
sayHi() {
alert("Hello world");
},
doSomething() {
// ...
},
doSomethingElse() {
// ...
}
};
and send back the name of a handler ("sayHi", "doSomething", "doSomethingElse") rather than the code of the handler. Then you use the handler via handlers[name].
Related
Reworded:
A common pattern is to pass callback functions, such as with Mongoose's save (just for example and simplified - no error handling):
someMethod(req:Request, res:Response){
document.save( function(err){ res.status(200).send({message: 'all good'})});
}
I'd like to externalize the callback. You can do this this way:
var respond = function(err:any, res:Response){
res.status(200).send({message: 'all good'});
}
someMethod(req:Request, res:Response){
document.save( function(err){ respond(err, res)});
}
...but ideally I'd like to do this by just passing a function like respond without having to create a call back function to enclose respond. I wanted to know if this is possible. Since the anonymous function has access to res, I thought there might be some way to gain access to res in a function defined externally. It appears there is not a way to do this so I'll live with wrapping it.
My original question was trying to isolate the specific issue I was interested in - which is to gain access to the caller's variables implicitly. Doesn't seem like that is possible. Fair enough.
Original Question:
I'd like to externalize a bit of code I use frequently and I'm having trouble understanding closure in the context of a Typescript method. Take a look:
var test = function(){
console.log("Testing external: "+JSON.stringify(this.req.body));
}
class Handler {
static post(req: Request, res: Response){
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
test();
}
}
Besides the fact that this does nothing useful, in this bit of code, the inline anonymous function has access to the req object, but the test() function does not. this in test is undefined. Removing this to match the inline function doesn't help.
I believe if I were to bind on this for the call I'd just end up with a reference to the Handler class when I really want to bind on the post method.
My motivation for doing this is that I want to make a function that can be passed as a callback to a bunch of different request handlers. When I write the functions inline it all works, but when I externalize it I can't get a closure over the variables in the enclosing method. I've read "You Don't Know JS: this & Object Prototypes", and in pure Javascript I can manage to make these sorts of things work but I'm obviously doing something wrong here (it may not be Typescript related, maybe I'm just messing it up).
So bottomline - is there a way I can externalize the handler and get access to the method variables as if I were writing it inline? I could just create an inline anonymous function as the callback that calls the external function with all the variables I need, but I want to really understand what is happening here.
This is not an answer, but will hopefully give me enough feedback to give you one because its not at all clear what you're actually trying to accomplish here and whether or not you actually understand what the terms mean is an open question since you use them correctly one minute and sketchily the next.
var test = function(){
console.log("Testing external: " + JSON.stringify(this.req.body));
}
In strict mode this will throw an error, in sloppy it will try to access the req property of the global object which is not likely what you want.
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
The IFFE wrapper is completely unnecessary, it literally adds nothing to the party. So why include it?
static post(req: Request, res: Response){
console.log("TESTING anon: "+JSON.stringify(req.body));
test(); // is this the spot where you are 'in-lining?'
}
What I think you want is this:
var test = function(reqBody) {
console.log("Testing external: " + JSON.stringify(reqBody));
};
class Handler {
static post(req: Request, res: Response) {
test(req.body);
}
}
My question is simple. Can you call a C# webservice from the Success function of another webservice? I think that the answer is no.
I have a login webservice which is called when a user tries to do something that requires the user to be logged in. This then calls another webservice, when the action is complete it does not go into the onSuccess function. I am assuming that it is not able to do so? Is this correct?
Example code, not actual code.
webservice.login(onLoginSuccess)
function onLoginSuccess(){
webservice.doSomething(onDoSomethingSuccess)
}
function onDoSomethingSuccess(){
.... does not get here.
}
This is the code to it's bare bones.
On client JavaScript call, success of login webservice.
function onLoginSuccess(result){
negotiateWithUser(true,
activeUser.id,
negotiation.dateID,
activeUser.showChat,
true);
}
function negotiateWithUser() {
<code>
if (justLoggedIn) updateDateData();
<code>
}
function updateDateData(){
if (populate==false){
populate=true;
WebService.Negotiations.DatesGet(activeUser.id,SucceededtoCallbackDateRefresh, ErrorHandler);
}
}
Does not go into the function SucceededtoCallbackDateRefresh even though data is returned and there are no errors.
I think I know what the problem is, in the negotiateWithUser function the updateDateData is called, execution control is given back to the negotiateWithUser function instead of going into the SucceededtoCallbackDateRefresh success funtion, as it is an asynchronous call. I think some kind of callback function is required.
I have got round the problem by calling the updataDateData function in a setInterval() in the onLoginSuccess function instead.
function onLoginSuccess(result){
if (negotiate) {
timerInterval = setInterval("updateDateData()", 300);
}
}
It works. If someone has a more graceful approach, I would be very interested.
Thanks.
How about to use jQuery.ajax()?
function Func1() {
$.ajax({
url:'MyWebService.asmx/Func1',
success:Func1Success,
error: function () {
alert('there was an error!');
},
});
return false;
}
function Func1Success(output){
$.ajax({
url:'MyWebService.asmx/Func2',
success:Func1SuccessToSuccess,
error: function () {
alert('there was an error!');
},
});
}
function Func1SuccessToSuccess() {
return false;
}
You definitely can.
Just to give a suggestion/advice theoretically, you can have 1 local variable for the status response of the first web service method, you can have it as boolean, representing the success of the first invocation. Then sequentially, you can call the other web service method if your local variable matches your success condition.
What I provided is just an idea, for a more specific answer, I recommend you posting the actual code you're working on.
Thanks.
I am assuming you are using .cs files on your server and then calling them from android.
If this is what you are doing then there is one way to call a method on success of another method. Just make two .cs files say x and y and store it on your server. Then call one of them from android (x) and then make object of y in x and that will be all.
for eg. This is my one .cs file named abc.cs which il call from android.
[WebMethod]
public xyz IsLoggedIn()
{
xyz example = new xyz();
//do something
.
.
return example;
}
now xyz.cs will be:
[WebMethod]
public void onSuccessofIsLoggedIn()
{
//do something
.
.
}
i hope this helps.... All this is just based on assumption though...please be clear about what you are using and we will be also more clear in our answers.
Before anyone marks it as duplicate, this post does not actually answer the question but suggests a different way altogether to solve that particular issue.
Mine is a different issue. Please let me explain.
In my case, there are various .js files (plugins) which are being loaded with jquery getscript and stored in variables. Then whenever required they will be executed (more than once)
The code for loading script (this code will only run once at the init of the system for each plugin js file)
var storedFunc;
$.getScript(pathToPluginJSFile, function( data, textStatus, jqxhr ) {
storedFunc = data;
});
All the plugins are in this format
(function(){
//lots of code here
})()
But when I checked the storedFunc variable in console, I found out that it has been stored as String variable. Like this,
"(function(){
//lots of code here
})()"
Now to execute this, I used eval, like this (this code can be executed multiple times based on the need)
eval(storedFunc)
Everything is working fine and i am happy with it, but here comes the problem, I read in somewhere that the usage of eval is kind of like a bad thing to do. So now I am afraid that thought everything is working fine, all these negativity of using eval spread on the internet might scare my client away. :(
So, please tell me how I can run that stored function (which has become a string) without using eval.
Or should I use anything else than $.getScript which does not convert a function into a string ?
Or if there is any other way altogether rewriting this plugin functionality?
Please show me the way. I am in need of this solution badly.
Any help will be appreciated.
Thanks in advance.
Understanding how $.getScript works
Seems there is some confusion on how $.getScript works. If you notice jQuery's documentation on the method, and as #Pointy made mention of in the comments, this is stated:
Load a JavaScript file from the server using a GET HTTP request, then execute it.
Here's an example: Let's pretend the contents of the file being returned is only this:
// Contents of yourExternalFile.js
console.log('Executed!');
Now, when you use $.getScript:
$.getScript(pathToPluginJSFile, function( data, textStatus, jqxhr ) {
// The script you retrieved has already executed at this point, and you will find "Executed!" in the console.
console.log('All Done');
});
Console output:
> Executed!
> All Done
The $.getScript method is not meant to be used to return a string of the content of the file. However, while that data is available in the callback, the contents of the file have already been executed. So by taking the string version of the file, and re-executing it with either new Function, or even eval, you are executing it twice on the page (jQuery does it once, and so do you).
Original Post:
Use the Function constructor instead of using eval.
// Your function as a string stored to a variable
var stringFunction = "(function(){console.log('Executed');})()";
// Use the Function constructor to create a new function:
var executableFunction = new Function(stringFunction);
// Now you can execute it
executableFunction(); // logs "Executed"
This snippet from this SO question/answer addresses the difference between eval and new Function.
eval() evaluates a string as a JavaScript expression within the current execution scope and can access local variables.
new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot access local variables because the code runs in a separate scope.
Additional Information (Based on comments)
Yes, you can just get the string contents of the file and store them to a variable without the contents of the file executing. You can have that function to execute anytime. You just need to use the regular get method using jquery, and set the dataType to text. This way, the script will not execute, and you can execute it as you see fit:
var storedFunction;
$.get({url: pathToPluginJSFile, dataType: 'text'})
.done(function (data) {
// Turn the script into a new function and store it
// The information in the script file has not done anything yet
storedFunction = new Function(data);
})
.fail(function () {
console.log('Failed :(');
});
The only thing you will have to watch out for, is making sure that the function was assigned to the storedFunction variable as you are making an api call, and you have to wait for that to finish before attempting to make the function execute.
// Later on, call that function anytime, and as often as you want:
storedFunction();
I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});
I have a function that calls another function over the server and returns a string back which i want to be printed in the browser's log windows, The function looks like:
function getErrorInfo() {
setTimeout(function () {
$.getJSON('Get/ErrorInfo', function (responseText) {
console.log("Log: "+responseText);
});
}, 5000);
}
getErrorInfo();
The function on the server sides does gets hits and returns a valid string But nothing is being displayed in the browser's windows Moreover the function on the server side must get hit after every 5 secs. but it only gets his on time and not again.
Please explain what am i doing wrong here.
Your basic issue is that you need to have properly formatted JSON in order to get back any result. Your result (per above) is:
3/8/2014 5:27:16 PMSystem.NullReferenceException: Object reference not set to an instance of an object. at movie.Models.Genre.GetPosts(Int32 min)
Not only is this an exception text, but it isn't valid JSON. JSON format is fully described here. Rather than calling a real service, I would recommend starting by just getting a static JSON file from the server. Then you know the data is correct.
Side Note:
The other issue here is how you print the OBJECT result from getJSON. When you try to print an object using "Console.log" it converts it to a string, which isn't probably going to show what you want. You should probably change your log statement to:
console.log(responseText);
In chrome at least, the console window will let you browse the contents of the object which can be really helpful. Between the note and the solution above I think you should have it. Best of luck!
When using $.getJSON(), the return result is required to be a valid JSON string, meaning it needs to be parsable into an object or array. In this situation, you can probably simply use $.get(), which will autodetect the return data type, or use $.ajax() and set the dataType: plain if you want to skip the JSON requirement.
On the second issue of keeping the log running, you can call getErrorInfo() from inside the setTimeout() or the callback, and it will keep running:
function getErrorInfo() {
setTimeout(function () {
$.getJSON('/echo/json/', function (responseText) {
console.log("Log: "+responseText);
getErrorInfo();
});
}, 5000);
}
getErrorInfo();
http://jsfiddle.net/Er5Lg/
In my opinion, in this situation, it is better than setInterval(), since that can get backed up and end up overriding calls, and the errors might display out of order.