this function gets a question from a database and is supposed to return it.
The database is a Parse object(https://www.parse.com/docs/js_guide). As indicated in the comments in the code the question is accessible from within the success function of the db call but not from outside it and simply putting the return statement inside the success block doesn't work either.
Code below. Any suggestions?
function getQuest(){
var Question = Parse.Object.extend("Question");
var query = new Parse.Query("Question");
var questlist = [];
var newquestion;
//get list of questions if chosen track is python or java. track is set globally
if (track == "python")
{
query.equalTo("track", "xstsysysus7");
} else if (track == "java"){
query.equalTo("track", "XAWqBgxFAP");
}
query.find({
success: function(questions){
// return list of questions
var i = Math.floor(Math.random()*10);
newquestion = questions[i].get('question');
console.log(newquestion); // works here
},
error: function(error){
console.log(error.message);
}
});
console.log(newquestion); //returns undefined here
return newquestion;
}
You cannot return from the callback method like this, this is an async issue, you should use a callback method to get your variable out from the method
function getQuest(callback){
var Question = Parse.Object.extend("Question");
var query = new Parse.Query("Question");
var questlist = [];
var newquestion;
//get list of questions if chosen track is python or java. track is set globally
if (track == "python")
{
query.equalTo("track", "xstsysysus7");
} else if (track == "java"){
query.equalTo("track", "XAWqBgxFAP");
}
query.find({
success: function(questions){
// return list of questions
var i = Math.floor(Math.random()*10);
newquestion = questions[i].get('question');
//call the callback method here and pass your variable as a param
if(callback != null && callback != undefined){
callback(newquestion);
}
},
error: function(error){
console.log(error.message);
}
});
}
Now you can call your getQuest method just like this instead of using var newQ = getQuest()
getQuest(function(newQuestion){
// do your stuff with newQuestion
})
The callbacks (success and error), are asynchronous. They have probably not been executed before your function returns.
Related
i am trying to build this function data get an JavaScript object and process that some time it's need a call back function so i am trying pass that function inside the object but when i call this it's says function dosen't exist and yet still this function exist and when i pass this as parameter it's working this only happen when i get callback function name from JavaScript Object
function Ajax(data){
//ajax stuff
var filtered_respons = response_from_ajax;
//tryed this all not working
data['callback'](filtered_response,'loading');
var fun_name = data['callback'];
fun_name(filtered_response,'loading');//
}
Updated
and from html page i am calling this function as this
let data = {
url:'./assets/php/category.php',
type:'POST',
callback :'toprender',
data:{all_cats:1},
element_name:'cat'
}
Ajax(data);
And when i try this way it's working
AjaxCaller(data,topfunction,true);
This is the whole function
AjaxCaller(data,callback,need){
var loader= "";
if(typeof data['loader'] !== "undefined"){
loader = $("#"+data['loader']);
}else{
loader = $("#loading");
}
loader.show();
if(typeof data['url'] !== "undefined" && typeof data['type'] !== "undefined"){
var $self = this;
$.ajax({
url:data['url'],
type:data['type'],
data:data['data'],
success:function(response){
loader.hide();
var response = JSON.parse(response);
var filtered_response = $self.ajaxError(response);
if(need==true){
callback(filtered_response,data['element_name']);
}
}
});
}else{
console.log('Please Re Check The Objects');
}
}
You're trying to use a string as a function. You can't do that.
You probably just want to change callback :'toprender' to callback :toprender:
let data = {
url:'./assets/php/category.php',
type:'POST',
callback :toprender,
data:{all_cats:1},
element_name:'cat'
}
Ajax(data);
That sets callback to the fucntion, rather than a string.
Live Example:
function toprender() {
console.log("toprender called");
}
function Ajax(data) {
data.callback();
}
let data = {
url:'./assets/php/category.php',
type:'POST',
callback :toprender,
data:{all_cats:1},
element_name:'cat'
}
Ajax(data);
I'm a little new to Javascript, and am having a hard time with the asynchronous aspect of it. My program checks values of two objects, where the second object doesn't have a vital property I need in order to complete the check. So I made a promise to get that value/property (the ID), and now I need to pass that ID value along to a check function. The check function should simply return a true/false to see if the ID's match. The value of the check function is passed to another function which then acts appropriately and edits the thing if necessary. So I basically can't access the value of tick outside it's brackets. I've included the snippet of my code where all of this is happening, as all of this is easier to visualize with it. Can someone provide me with a solution to this issue? Any advice would help immensely! I want to minimize the modification of the script as much as possible.
var Q = require('q');
getID = function(instance, person, callback){
var = deferred = Q.defer();
var url = 'www.blah.com';
var options = {
'url': url
};
request.get(options, function(error, response, body){
if (error) {
deferred.reject(error);
}else{
var res = body;
var obj = JSON.parse(res);
var id = obj.id;
deferred.resolve(id);
} else deferred(obj);
});
check = function(instance, thing1, thing2){
var tick = true;
getID(instance, thing2).then(function(id)){
var id_1 = thing1.id; // thing1 passed into check with ID
var id_2 = thing2.id; // thing 2 now has id attached to it
if( id_1 == id_2 ){
tick = true; // VALUE 1
}else{
tick = false; // VALUE 2
});
// NEED VALUE 1 OR 2 OF TICK HERE
if(thing1.name == thing2.name){
tick = true;
else{
tick = false;
}
// similar checks to name but with ADDRESS, EMAIL, PHONE NUMBER
// these properties are already appended to thing1 and thing 2 so no need to call for them
};
editThing = function(instance, thing, callback){
var checked = check(instance, thing1, thing2);
if(checked){
// edit thing
}else{
// don't edit thing
};
Since you're making a promise of work to be done, and you need output from that work, you'll need pass that promise along to the code who's wanting the final output.
I'm not going to try to rewrite the code from your post, so allow me to paraphrase:
getThing = function(thing){
var deferred = Q.defer();
...
request.get(options, function(error, response, body){
if (error) {
deferred.reject(error);
} else {
...
deferred.resolve(thingMadeFromResponse);
}
});
return deferred;
}
check = function(thingWeHave, thingWeNeedFetched){
return getThing(thingWeNeedFetched).then(function(thingWeFetched)){
// check logic
checked = thingWeHave.id == thingWeFetched.id;
...
return checked;
});
};
editThing = function(instance, thing, callback){
check(thingWeHave, thingWeNeedFetched).then(function(checked) {
if(checked){
// edit thing
}else{
// don't edit thing
}
});
};
Promises
“thenable” is an object or function that defines a then method.
p.then(function(value) {
// fulfillment
console.log(value + ' is now available and passable via function argument');
}, function(reason) {
// rejection
});
I was wondering if there is a way to pull and use JSON data from two different sources. Currently, the code looks like this:
//JSON1
$.getJSON('url1',function(data){
$.each(data,function(key,val){
//code
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
//code
});
});
When I do this, i seems that variables created from one JSON function aren't available in the other one, which makes it hard for them to be useful together.
Is there a better way to have these two work together?
This function takes an array of urls and a callback as parameters:
function getMultiJSON(urlList,callback) {
var respList = {};
var doneCount = 0;
for(var x = 0; x < urlList.length; x++) {
(function(url){
$.getJSON(url,function(data){
respList[url] = data;
doneCount++;
if(doneCount === urlList.length) {
callback(respList);
}
});
})(urlList[x]);
}
}
You would use it like this:
getMultiJSON(['url1','url2'],function(response) {
// in this case response would have 2 properties,
//
// response.url1 data for url1
// response.url2 data for url2
// continue logic here
});
You might want to add a timeout as the function will never call your handler should any of the URLs fail to load
Variable declared within the functions using var (or blocks, using let) are not available outside of the functions (or blocks).
$.getJSON('url1',function(data){
$.each(data,function(key,val){
var only_accessible_here = key;
});
});
So if you want variables that are accessible outside the scope of the function they are declared in, you need to declare them outside of the function they are used in.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
As Marc B says, there is no way to know which order the combined_stuff variable will be updated, either by JSON1 first, or by JSON2 first, or by only one, if one of the getJSON calls fail, or by neither if both fail.
If the order of updating is important, call the one you want to use second in the function of the one you want to call first.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
});
});
Easily using the open source project jinqJs (http://www.jinqJs.com)
var data1 = jinqJs().from('http://....').select();
var data2 = jinqJs().from('http://....').select();
var result = jinqJs().from(data1, data2).select();
The example does a sync call, you can do an async call by doing something like this:
var data1 = null;
jinqJs().from('http://....', function(self){ data1 = self.select(); });
Result will contain both results combined.
If you control the endpoint, you could make it return all of the data you want in one shot. Then your data would look like:
{
"url1_data": url1_json_data,
"url2_data": url2_json_data
}
If you still have 2 endpoints you need to hit, you can pass the result of your first ajax call to the second function (but this makes your 2 ajax calls synchronous):
function getJson1(){
$.getJSON('url1',function(data){
getJson2(data);
});
}
function getJson2(json1Data){
$.getJSON('url2',function(data){
//Do stuff with json1 and json2 data
});
}
getJson1();
I would recommend you to use $.when function available in jquery to execute both the methods in parallel and then take the action. See the code snipped below,
var json1 = [], json2 = [];
$.when(GetJson1(), GetJson2()).always(function () {
//this code will execute only after getjson1 and getjson2 methods are run executed
if (json1.length > 0)
{
$.each(json1,function(key,val){
//code
});
}
if (json2.length > 0)
{
$.each(json2,function(key,val){
//code
});
}
});
function GetJson1()
{
return $.ajax({
url: 'url1',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json1 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json1 = [];//just initialize to avoid js error
}
}
function GetJson2()
{
return $.ajax({
url: 'url2',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json2 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json2 = [];//just initialize to avoid js error
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
The returned data from each AJAX call are not available outside its own callback function. I'm sure there are more elegant (complex?) solutions, but a couple of simple, Occamic, solutions include global variables, or storing the received data in hidden input elements.
Within each callback function, just loop until the data from the other call is present:
function getJson1(){
$.getJSON('url1',function(data){
var d2 = '';
$('#hidden1').val(data);
while ( d2 == '' ){
//you should use a time delay here
d2 = $('#hidden2').val();
}
getJson2();
});
}
function getJson2(){
$.getJSON('url2',function(d2){
var d1 = '';
$('#hidden2').val(d2);
while ( d1 == '' ){
//you should use a time delay here
d1 = $('#hidden1').val();
}
//Do stuff with json1 and json2 data
});
}
getJson1();
I have a the following java script object
function eventTypeObj() {
allEventTypes = [];
// When the object is created go and get all the event types that can be included in journey or clusters.
$.ajax({
url: "/ATOMWebService.svc/GetDisplayEventTypes",
dataType: "json",
success: function(result) {
allEventTypes = eval("(" + result.d + ")");
}
});
// Returns a list of all the event type IDS.
this.getEventTypeIds = function() {
var eventTypeIDs = [];
for (var i = 0; i < allEventTypes.length; i++) {
eventTypeIDs.push(allEventTypes[i].Id);
}
return eventTypeIDs;
};
}
I was wondering if there is a way stop some one calling the eventTypeObj.getEventTypeIds(); before the ajax call in the constructor has succeeded, and there is no data in the allEventTypes array?
Something like this would be way better (im not guaranteeing this is 100% working, but the concept is sound):
function eventTypeObj() {
this.allEventTypes = [];
this.hasLoadedEventTypes = false;
var loadEventTypes = function(cb) {
$.ajax({
url: "/ATOMWebService.svc/GetDisplayEventTypes",
dataType: "json",
success: function(result) {
this.allEventTypes = eval("(" + result.d + ")");
this.hasLoadedEventTypes = true;
cb();
}
});
};
this.getEventTypeIds = function(updateEventTypes, callback) {
var _getEventTypeIds = function() {
var eventTypeIDs = [];
for (var i = 0; i < this.allEventTypes.length; i++) {
eventTypeIDs.push(this.allEventTypes[i].Id);
}
return eventTypeIDs;
};
if (!this.hasLoadedEventTypes || updateEventTypes) {
loadEventTypes(function(){ callback(_getEventTypeIds()); });
}
else callback(_getEventTypeIds());
};
}
Example usage:
var eto = new eventTypeObj();
eto.getEventTypeIds(false, function(eventTypeIdArray) {
// do stuff with the id array
});
/*
somewhere later on you want to get an updated eventTypeId array
in case the event types have changed.
*/
eto.getEventTypeIds(true, function(eventTypeIdArray) {
// do stuff with the updated ids
});
var allowCall = false;
function eventTypeObj() {
allEventTypes = [];
// When the object is created go and get all the event types that can be included in journey or clusters.
$.ajax({
url: "/ATOMWebService.svc/GetDisplayEventTypes",
dataType: "json",
success: function(result) {
allEventTypes = eval("(" + result.d + ")");
allowCall = true;
}
});
// Returns a list of all the event type IDS.
this.getEventTypeIds = function() {
if(!allowCall) return; // or pop up a message
var eventTypeIDs = [];
for (var i = 0; i < allEventTypes.length; i++) {
eventTypeIDs.push(allEventTypes[i].Id);
}
return eventTypeIDs;
};
}
Or just check if allEventTypes is empty or not.
There is no way to prevent someone from calling it too soon. What would you want to have happen if they call it too soon?
It looks like your code now currently returns an empty array if allEventTypes hasn't yet been filled in. You can decide whether the empty array is the right result or if you should throw an exception when it's called too early to make it absolutely clear to the caller that the data is not yet available.
You could provide some helper code for people who need that information, but it might not yet be available. For example, you could allow them to register a callback that would get called from the success handler after the data had been filled in. You could allow them to query whether the data is available yet.
If you don't want the responsibility for the timing to be on the callers, then you cannot offer a synchronous way to get this information. Instead, you would only offer a callback mechanism for getting the data. If the data is ready, the callback would get called immediately. If the data is not ready, the callback would get called when the ajax function completes. In either case, the caller would have to process the data in the callback only and getEventTypeIds would not be a normal call to get the data like it is now, but rather a call to register a callback that would be called with the data when was ready. This would relieve the caller from having to know implementation details of when the data was ready, but would force them to use the asynchronous nature of the callback mechanism.
this.getEventTypeIds = function(callback) {
if (allEventTypes.length > 0) {
// data is ready call the callback with the data now
} else {
// store the callback to be called later from the success handler
}
}
You can check if the eventType array is empty, right?
if(allEventTypes.length == 0)
{
return;
}
Thanks for reading this.
I imagine this is really a javascript question, and my title probably does not get at the heart of what I am trying to do, but I want to store the result of my ajax request in a global variable. This would allow me to test the var before making the ajax call...and avoid repeated ajax calls for the same data. I need to be able to pass the variable name from the click event down through the populateSelect function into the ajaxCall function.
It seems like I could pass a function as a parameter, but I have not been able to make that work.
I like to include working examples in my questions, but in this case the latency in the call to the server is part of the problem.
Thanks
$('#getSelectOptions').bind("click", function() {
populateSelect(this);
});
function populateSelect(whatWasClicked) {
var thisSelect = $(whatWasClicked).parents("div").find("select") ;
var before = function() { $(loading).show() ; } ;
var complete = function() { $(loading).hide() ; } ;
var data = {'_service' : 'myService', '_program' : 'myProgram' } ;
var error = function(){alert("Error"); } ;
var success = function(request) { $(thisSelect).html(request) ; };
var waitTime = 20000 ;
ajaxCall(thisSelect, waitTime, before, complete, data, success, error ) ;
}
function ajaxCall(elementToPopulate, waitTime, whatToDoBeforeAjaxSend,
whatToDoAfterAjaxSend, dataToSendToTheServer,
whatToDoAfterSuccess, whatToDoAfterError) {
$.ajax({
type: "post",
url: "http://myURL/cgi-bin/broker",
dataType: "text",
data: dataToSendToTheServer,
timeout: waitTime,
beforeSend: whatToDoBeforeAjaxSend,
error: whatToDoAfterError(request),
success: whatToDoAfterSuccess(request)
});
}
EDIT Further education in how to write a good question... I should have mentioned that I call populateSelect to populate multiple selects..so I need way to reference the results for each select
jQuery has a $.data method which you can use to store/retrieve items related to any element on the page.
//e.g. create some object
var inst = {};
inst.name = 'My Name'
var target = $('#textbox1');
//save the data
$.data(target, 'PROP_NAME', inst);
//retrieve the instance
var inst = $.data(target, 'PROP_NAME');
It looks like in the example you gave, you only have one type of AJAX request, POSTed to the same URL with the same data every time. If that's the case, you should just need something like :
var brokerResponse = null; // <-- Global variable
function populateSelect(whatWasClicked) {
var thisSelect = $(whatWasClicked).parents("div").find("select") ;
if (!brokerResponse) { // <-- Does an old response exist? If not, get one...
var before = function() { $(loading).show() ; } ;
var complete = function() { $(loading).hide() ; } ;
var data = {'_service' : 'myService', '_program' : 'myProgram' } ;
var error = function(){alert("Error"); } ;
var success = function(request) { // <-- Store the response before use
brokerResponse = request;
$(thisSelect).html(brokerResponse);
};
var waitTime = 20000 ;
ajaxCall(thisSelect, waitTime, before, complete, data, success, error ) ;
}
else { // <-- If it already existed, we get here.
$(thisSelect).html(brokerResponse); // <-- Use the old response
}
}
If you have multiple possible items for whatWasClicked which each need a different AJAX response cached, then you need to have some string with which to identify whatWasClicked, and use that to store multiple values in your global variable. For example, if you have a unique id on whatWasClicked, this would work:
var brokerResponse = {}; // Global variable is a simple object
function populateSelect(whatWasClicked) {
var whatWasClickedId = $(whatWasClicked).attr('id'); // Get the unique ID
var thisSelect = $(whatWasClicked).parents("div").find("select") ;
if (!brokerResponse[whatWasClickedId]) { // Check that ID for a response
var before = function() { $(loading).show() ; } ;
var complete = function() { $(loading).hide() ; } ;
var data = {'_service' : 'myService', '_program' : 'myProgram' } ;
var error = function(){alert("Error"); } ;
var success = function(request) {
brokerResponse[whatWasClickedId] = request; // Using ID
$(thisSelect).html(brokerResponse);
};
var waitTime = 20000 ;
ajaxCall(thisSelect, waitTime, before, complete, data, success, error ) ;
}
else {
$(thisSelect).html(brokerResponse[whatWasClickedId]); // Etc...
}
}
JavaScript's scoping is such that if you just declared a global variable, you should be able to access it from within the ajax success function and the click function as well.
var _global_holder = null;
$('#getSelectOptions').bind("click", function() {
if(_global_holder==null) { whatever }
populateSelect(this);
});
function populateSelect(whatWasClicked) {
if(_global_holder !== null) {
whatever
} else { whatever else }
ajaxCall(thisSelect, waitTime, before, complete, data, success, error ) ;
}
function ajaxCall(elementToPopulate, waitTime, whatToDoBeforeAjaxSend,
whatToDoAfterAjaxSend, dataToSendToTheServer,
whatToDoAfterSuccess, whatToDoAfterError) {
...
}