I apologise if this is a repeated question. I have done my research but I am still unable to come up with an answer:
I am writing a small JSONP API. The desired outcome:
The programmer creates an instance of the JSON class.
var json = new jsonpRequest (
"http://url.to.web_service",
searchParam //passed in as an associative array
);
The programmer then declares var myJSON = jsonpRequest.getJsonP()
This will return the JSONP into the myJSON variable to be processed.
The API successfully takes in the parameters when the instance of the class is constructed, generates a link to the services w/ the desired parameters and injects it into the DOM via script tags using this function:
jsonpRequest.prototype.fetchJsonp = function(){
var request = that.getRequest();
//creates a script element
var jsonpCall = document.createElement('script');
//gets jsonp request
jsonpCall.src = request;
//adds script to DOM, which goes on to request the JSONP from the service.
document.head.appendChild(jsonpCall);
};
EDIT: For the sake of clarity: this definitely does return the data set that is requested.
The function I am using as my callback is:
jsonpRequest.prototype.processCallback = function(data){
alert(data);
that.setListOfResults(data);
};
It is called in the link as: &callback=jsonpRequest.prototype.processCallback
The processCallback function takes in the data from the request and stores it in a variable within the class using the setListOfResults function.
After the data has been stored I would like to return the data from the request to the myJSON variable. This is the getJsonp function that the programmer invokes in step 2 of the process:
jsonpRequest.prototype.getJsonp = function(){
that.buildRequest();
that.fetchJsonp();
return that.listOfResults;
};
The issue:
Here is what I am calling after I define my JSON API class:
var myJSON = json.getJsonp();
console.log(myJSON);
Because it is asynchronous, it is moving on to the console log before the callback function is invoked, resulting in MYJSON to be undefined. I am not sure how I can daisy chain my code together in such a way where it runs the callback before moving on.
I tried to emulate the solution from How can I get this JSONP call to return a value?. I may be missing a step or I am perhaps ignorant of something! Any help to clarify this would be greatly appreciated. Thank you in advance :).
P.S. I would like to avoid using JQuery etc... It would be beneficial to keep this strictly as raw JavaScript.
I am not sure how I can daisy chain my code together in such a way where it runs the callback before moving on.
You can’t do that. You must rely on callbacks. Add a callback parameter to your jsonpRequest constructor, and invoke that callback after you do setListOfResults(data). You may also wish to allow for setting the this context in which the callback will be executed.
jsonpRequest.prototype.processCallback = function(data){
alert(data);
that.setListOfResults(data);
that.callback.apply(that.context, [data]);
};
Related
I can not figure out what could be the usefulness for this function:
// Quick function to retrieve the parameters in a format compatible with the ajax request
var getRequestParameters = function(params){
return params;
};
I'm seeing it in a web project, used before every $.ajax() call. Can anybody please enlighten me?
It's an extension point. It serves as a central point to add/remove/customize parameters at some point in the future if the needs of the project change. At present, it doesn't do anything, but apparently it's there on the theory that eventually it may do something.
You've said it's used before every $.ajax call, which suggests you're using jQuery. Which means it's a bit redundant with jQuery's own ajaxSend, but that's not a big deal.
For example, suppose at some point in the future you needed to add a unique identifier to every ajax request that was sent. You'd just have to modify that one function:
var id = 0;
var getRequestParameters = function(params){
params.__uniqueId = ++id; // Or perhaps copy params first
return params;
};
...and you'd have it on all of your ajax requests.
I'm working on a Meteor project and want to get the return value of Meteor.call in template helpers on client side. At very first, I just set a variable in the call back function and get the variable's value outside the Meteor.call. I found out the code after Meteor.call doesn't execute at all. Then I searched a bit and use Session, it works. But I don't really understand the reason. Here's my original code and modified code. Can anyone explain a bit for me? Thanks!!
Original wrong code: html
<div id="text-result-main">
<h2>{{title}}</h2>
</div>
js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
console.log(titles);
return titles;
}});
Collection text.js
Text = new Mongo.Collection("text");
Meteor.methods({
'getTitle': function(myindex){
return Text.findOne({index: myindex}).title;
}});
The working code: js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
Session.set("titles",result);
});
console.log(Session.get("titles"));
return Session.get("titles");
}});
Notice that I didn't publish Collection Text to the client at all because it's just so huge. Every time when I refresh the page when running the wrong code, I can't see the content of "title" or see it on the console. But when I set the session, it works. I don't really understand how it works here. Thanks
There is two issues Asynchronicity and Reactivity
This affectation
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
inside the meteor call is executed but in a asynch way. So the return of your helper is immediately called, and return a empty value.
Try it out in the console of your browser.
But then, why your template render correctly with {{title}} when you use a Session Variable ?
It's because the Session is a reactive data source, witch means that every change to it trigger a re-computation of all templates involving this piece of data.
Here is a timeline:
Methods is called
Return empty value
Method is executed, setting variable value
If the Variable is a reactive data source, template is re-computed. ( in your case, the session is a reactive data source. )
To go further
I would use a reactive var in that case, it's very close from a session variable, but the scope is limited to a template.
A good read on Reactive data source: http://richsilv.github.io/meteor/meteor-reactive-data-types/
The problem is the fact that Meteor.call() is asynchronous when paired with a callback.
So when title() starts executing, it does not wait for your Meteor.call() invocation to return a result (or possibly an error). It continues execution. This is called asynchronous execution.
In short, you are trying to log the value for the key titles which doesn't exist in Session (since the state of your asynchronous Meteor call is unknown, at this point of time).
Try moving the console log statement into the callback paired with your Meteor.call() and you can see the result once it has successfully been set in Session.
A workaround to your problem is to make your Meteor.call() synchronous like this:
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
var result = Meteor.call('getTitle', index); // <--- this is synchronous code now
Session.set("titles",result);
console.log(Session.get("titles"));
return Session.get("titles");
}});
Removing the callback makes Meteor.call() behave synchronously.
If you do not pass a callback on the server, the method invocation
will block until the method is complete. It will eventually return the
return value of the method, or it will throw an exception if the
method threw an exception.
(from http://docs.meteor.com/api/methods.html#Meteor-call)
Why not use something like this:
title: function(){
var index = Router.current().params.index;
var a = Text.findOne({index: myindex}).title;
console.log(a);
return a;
without methods
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 am having a problem, or perhaps a lack of understanding, with the jQuery execution order of $.get() function. I want to retrieve some information from a database server to use in the $.ready() function. As you all know, when the get returns, it passes the data to a return handler that does something with the data. In my case I want to assign some values to variables declared inside the ready handler function. But the problem is, the return handler of $.get() does not execute until after ready has exited. I was wondering if (a) am I doing this right/is there a better way or if (b) there was a way around this (that is, force the get return handler to execute immediately or some other fix I'm not aware of). I have a feeling this is some closure thing that I'm not getting about JavaScript.
As per request, I'll post an example of what I mean:
$(function() {
var userID;
$.get(uri, function(returnData) {
var parsedData = JSON.parse(returnData);
userID = parsedData.userID;
});
});
So as you can see, I'm declaring a variable in ready. Then using a get call to the database to retrieve the data needed. Then I parse the JSON that is returned and assign the userID to the variable declared before. I've tested it with a couple alerts. An alert after the get shows userID as undefined but then an alert in get's return handler shows it to be assigned.
$.get() is asynchronous. You have to use a callback to fill your variable and do the computation after the request is complete. Something like:
$(document).ready(function(){
$.get( "yourUrl", function( data, textStatus, jqXHR ) {
var myData = data; // data contains the response content
// perform your processing here...
registerHandlers( myData ); // you can only pass "data" off course...
});
});
// your function to register the handlers as you said you need to.
function registerHandlers( data ) {
// registering handlers...
}
$.get is an ajax request. A in AJAX stand for asynchronous, so script won't wait for this request to finish, but instead will proceed further with your code.
You can either use complete callback or you can use $.ajax and set async to false to perform synchronous request.
The $.get() function executes an async httprequest, so the callback function will be executed whenever this request returns something. You should handle this callback outside of $.ready()
Maybe if you explain exactly what do you want to do, it would be easier to help!
Are you looking for something like:
$(document).ready(function(){
var variable1, variable 2;
$.get('mydata.url', function(data){
variable1 = data.mydata1;
variable2 = data.mydata2;
});
});
If you declare the variables first, then you can set their values within the get call. You can add a function call at the end of the get handler to call a separate function using these values? Without some kind of example, its hard to go into any more detail.
Without seeing the full code, my guess is that you should declare your variable outside $.ready; initialize it in ready for the initial page load; then update it from the get callback handler.
for example
var x = ""; // declaration
$(document).ready(function() { x = "initial value"; });
$.get(...).success(function() { x = "updated from ajax"; });
I have a function which makes an AJAX request to a server and returns relevant information after it completes.
I have another function which manipulates some variables in its namespace based on the returned information.
Currently, I am appending a 'callback' argument to the first function, which is called when the request completes. This, however, blurs the purpose of the first function - instead of being a 'getInfo' function, it's become a 'getInfoAndDo' function.
Ideally, I'd like to call the second function (a 'do' function, which calls the first function, a 'get' function) and does its thing.
I have looked around and found jQuery methods such as .ajaxStop and .ajaxComplete, but they seem to only to work when bound to DOM elements. Is there any way to do this entirely in javascript?
e.g.
function _getEventAttendance(uid, callback) {
var attendQuery = FB.Data.query('SELECT eid,rsvp_status,start_time FROM event_member WHERE uid = {0}', uid);
FB.Data.waitOn( [attendQuery],
function (args){
callback(args[0]);
}
);
}
function logAttendance(attendance){
console.log(attendance);
}
Currently, I am doing:
_getEventAttendance(123456789, logAttendance);
which seems ridiculous to me.
Is there a way to write the code such that I can change the code snippet inside _getEventAttendance / remove the callback argument:
FB.Data.waitOn( [attendQuery],
function (args){
return args[0];
}
);
and then make calls that are equivalently as simple as :
logAttendance.ajaxComplete(_getEventAttendance(123456789));
(I'm just making up the syntax for this, I have no idea how it's supposed to be written.)
$.when(<AJAX Request>).then(function(response){...});
Optionally use $.pipe() to filter response first.