How to call JQuery function from JavaScript (after asynchronous call) - javascript

The idea of the code I´m developing right now is extracting data from a JSON file (which I get from a server) and then show the results using a beautiful and nice graphic. The problem is I can't retrieve the object where I save the JSON results in the Jquery code so I can load them in the graphic.
To simplify, my code is like this (Javascript part)
var obj; //I initialize it here in order to make it global though it doesn't work
function handle_json() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
var json_data = http_request.responseText;
obj = eval("(" + json_data + ")");
//at this point I have the information I want in "obj"
} else {
alert("A problem ocurred.");
}
http_request = null;
}
}
But now I want to send "obj" to my jQuery code so I can access to the information and show it.
But if try this (jQuery part)
$(function () {
alert(obj.results.bindings[0].a.value); //<-- this doesn't work, obj isn't initialized
var fert = [];
fert = [[1990, 1.28], [1995, 1.25], [2000, 1], [2005, 1.3], [2010, 1.83]];
var plot = $.plot($("#placeholder"),
[ { data: fert, label: "Fertility"} ], {
series: {
lines: { show: true },
points: { show: true }
},
grid: { hoverable: true, clickable: true },
yaxis: { min: 0, max: 2}
});
I see what the problem is, I've made an asynchronous Ajax call and I need to execute jQuery right after I evaluate de json info ( obj = eval("(" + json_data + ")") ) but I just don't know how!
If it helps I've used a library called "flot" to do the graphics.
Thanks a lot! Any help would be apreciated :)

Currently your jQuery code is in a document ready handler, so (obviously) it runs as soon as the document is ready - timing that isn't related to your Ajax call at all. Instead, put your jQuery code in its own function and call it from right after you set obj. Or just move the jQuery code directly into the function where you set obj:
var json_data = http_request.responseText;
obj = eval("(" + json_data + ")");
//at this point I have the information I want in "obj"
// either process obj directly here, or call a function to do it...
processData(obj);
...
function processData(obj) {
// your jQuery code here, using obj
}
Better though, since you're using jQuery anyway, would be to do the Ajax with one of jQuery's Ajax functions. I'd suggest $.getJSON().
$.getJSON("yourURLhere", function(obj) {
// your jQuery code using obj here
});

When you use jQuery's AJAX calls, you can provide a function to execute after the data has been received. It even has a variant that automatically parses JSON, like this:
$.getJSON(url, options, function(response) {
... do something with the data ...
});

Related

Cannot get (Footable) function to work from within AJAX call but it works elsewhere

EDIT: It seems that this issue is only happening in Chrome. Firefox is fine.
Footable is a JQuery plugin. https://fooplugins.com/plugins/footable-jquery/
The following function is used by the "Footable" plugin to make the .table class have a nice layout. :
jQuery('.table').footable({
"columns": result,
"rows": response
});
I want to run the function inside an AJAX call:
$.get('../php/campaignmanagement.php', function(response){
response = JSON.parse(response);
var columns = Object.keys(response[0]);
var result = columns.map(x => {
return {
title: x,
name: x
}//end return
});
//FUNCTION HERE
jQuery('.table').footable({
"columns": result,
"rows": response
});
//FUNCTION ABOVE
......... Other irrelevant code...
});
This gives me the following error:
jQuery(...).footable is not a function
However, if I move the function outside the AJAX function, it works.
e.g.
//FUNCTION HERE
jQuery('.table').footable({
"columns": result,
"rows": response
});
//FUNCTION ABOVE
$.get('../php/campaignmanagement.php', function(response){
response = JSON.parse(response);
var columns = Object.keys(response[0]);
var result = columns.map(x => {
return {
title: x,
name: x
}//end return
});
......... Other irrelevant code...
});
I need to be able to run the function from within AJAX.
Why would AJAX be causing everything to break?
FYI: The HTML document is calling the scripts like this:(campaignmanagement.js is the file which runs the above functions)
<script src="../vendors/jquery/jquery.js"></script>
<script src="../vendors/footable/js/footable.js"></script>
<script src="../vendors/foundation 6/foundation.js" type="text/javascript"></script>
<script src="../js/campaignmanagement.js"></script>
You're using two different jQuery objects here, your first is $ (unless you've assigned this to something else we can't see) and jQuery. You can just use $ object within itself, or grab a reference of the element that is available within the closure of the AJAX request.
// grab a reference to the table using jquery
var table = $('.table')
$.get('../php/campaignmanagement.php', function(response){
response = JSON.parse(response);
var columns = Object.keys(response[0]);
var result = columns.map(x => {
return {
title: x,
name: x
}//end return
});
table.footable({
"columns": result,
"rows": response
});
});

Why does AJAX json script return extra 0 (zero)

I have an AJAX function in WordPress that calls a PHP function to return the value of a transient record in the Database.
When I call the function using jQuery, I receive the result however it always has an extra 0 (zero) appended to the value.
Here is my jQuery function:
(function($) {
$(document).ready( function() {
var AdvancedDashboardWidget = function(element, options)
{
var ele = $(element);
var settings = $.extend({
action: '',
service: '',
countof: '',
query: '',
callback:''
}, options || {});
this.count=0;
var url='';
switch(settings.service)
{
case 'facebook':
if(settings.countof=='likes' || settings.countof=='talks')
{
ajaxCall(action,ele,settings);
}
}
};
var ajaxCall = function(action,ele,settings){
opts = {
url: ajaxurl, // ajaxurl is defined by WordPress and points to /wp-admin/admin-ajax.php
type: 'POST',
async: true,
cache: false,
dataType: 'json',
data:{
action: settings.action // Tell WordPress how to handle this ajax request
},
success:function(response) {
//alert(response);
ele.html(response);
return;
},
error: function(xhr,textStatus,e) { // This can be expanded to provide more information
alert(e);
//alert('There was an error');
return;
}
};
$.ajax(opts);
};
$.fn.advanceddashboardwidget = function(options)
{
return this.each(function()
{
var element = $(this);
// Return early if this element already has a plugin instance
if (element.data('advanceddashboardwidget')) return;
// pass options to plugin constructor
var advanceddashboardwidget = new AdvancedDashboardWidget(this, options);
// Store plugin object in this element's data
element.data('advanceddashboardwidget', advanceddashboardwidget);
});
};
});
})(jQuery);
There are more helper functions involved however this is the main jQuery function that communicates with WordPress and returns the value of the PHP function.
The issue is that if the value is returned as "99" for example it will be returned as "990"
Here is the PHP function that jQuery is calling:
/**
* Get Facebook Likes
*/
public function get_facebook_likes(){
echo 99;
}
If I change the above to return 99; I receive plain 0
Your function should use wp_send_json to encode the PHP as JSON and sent it back to the AJAX request handler. This will also stop executing of any following PHP too, so there is no need to use exit or die.
So for your specific example, you would use:
/**
* Get Facebook Likes
*/
public function get_facebook_likes(){
wp_send_json(99);
}
This is old question but I'm going to answer this. wp_send_json() function may help but not always. There could be some moments when you can't use this function. Like, when you load posts by ajax, you are getting some template part, you can use the function. That's why WordPress documentation suggests to make use of the die() function.
So in the end, your php function should look like this:
/**
* Get Facebook Likes
*/
public function get_facebook_likes() {
echo 99;
die();
}
Use Firebug and view the actual net data transmitted and received. Determine if the error is coming from the javascript side or the PHP side. Copy the net request and paste it into a separate browser window to see the raw result. If it is PHP, pursue that. if it is the javascript doing something, let us know.

Setting object properties using AJAX

I am newbie in OOP and I try to build an object using ajax request. What I need is to get 'responseArray' in JSON format and than work on it.
function adres(adres) {
this.adres_string = adres;
var self = this
$.ajax({
type: 'POST',
url: "http://nominatim.openstreetmap.org/search?q="+adres+"&format=json&polygon=0&addressdetails=0",
success: function(data) {
self.responseArray = eval('(' + data + ')')
}
})
//Method returning point coordinates in EPSG:4326 system
this.getLonLat = function() {
var lonlat = new OpenLayers.LonLat(this.responseArray.lon, this.responseArray.lat);
return lonlat;
}
}
The problem starts when in appilcation code I write:
var adr = new adres('Zimna 3, Warszawa');
adr.getLonLat();
This returns nothing as there is no time get the response from the server.
How to write it properly in the best way? I've read about when().then() method in jQuery. This may be OK for me. I just want to get know best practise
This is how AJAX works (notice the A-synchronous part). You are right, the moment you call adr.getLonLat() response did not yet came back. This is the design I would suggest: just pass callback function reference to adres constructor:
function adres(adres, callbackFun) {
//...
success: function(data) {
var responseArray = eval('(' + data + ')')
var lonlat = new OpenLayers.LonLat(responseArray[i].lon, responseArray[i].lat);
callbackFun(lonlat)
}
and call it like this:
adres('Zimna 3, Warszawa', function(lonlat) {
//...
})
Few remarks:
adres is now basically a function, you don't need an object here.
do not use eval to parse JSON, use JSON object.
Are you sure you can POST to http://nominatim.openstreetmap.org? You might hit the same origin policy problem
where is the i variable coming from in responseArray[i]?

Javascript - Trouble using for...in to iterate through an object

I have a dynamically-generated object that looks like this:
colorArray = {
AR: "#8BBDE1",
AU: "#135D9E",
AT: "#8BBDE1",
... }
I'm trying to use it to color a map by using this plugin and the 'colors' attribute during the call to the plugin. Like this:
$('#iniDensityMap').vectorMap({
backgroundColor: '#c2e2f2',
colors: colorArray,
... (some other params)
});
But it doesn't color in the countries. When I hard code this in, it works fine - but it must be dynamically generated for this project, so something like this won't work for me (although it does in fact color the map):
$('#iniDensityMap').vectorMap({
backgroundColor: '#c2e2f2',
colors: { AR: "#8BBDE1", AU: "#135D9E", AT: "#8BBDE1" },
... (some other params)
});
I've traced the issue far enough into the plugin to find it has something to do with this loop:
setColors: function(key, color) {
if (typeof key == 'string') {
this.countries[key].setFill(color);
} else {
var colors = key; //This is the parameter passed through to the plugin
for (var code in colors) {
//THIS WILL NOT GET CALLED
if (this.countries[code]) {
this.countries[code].setFill(colors[code]);
}
}
}
},
I've also tried iterating through the colorArray object on my own, outside of the plugin and I'm running into the same issue. Whatever sits inside the for ( var x in obj ) isn't firing. I've also noticed that colorArray.length returns undefined. Another important note is that I've instantiated var colorArray = {}; in a separate call, attempting to ensure that it is sitting at the global scope and able to be manipulated.
I'm thinking that the problem is either:
The way I'm dynamically populating the object - colorArray[cCode] =
cColor; (in a jQuery .each call)
I'm once again confusing the differences between Arrays() and Objects() in javascript
It is a scope issue perhaps?
Some combination of everything above.
EDIT #1: I've moved my additional question about Objects in the Console in Firebug to a new post HERE. That question deals more specifically with Firebug than the underlying JS problem I'm asking about here.
Edit #2: Additional info
Here's the code I'm using to dynamically populate the Object:
function parseDensityMapXML() {
$.ajax({
type: "GET",
url: "media/XML/mapCountryData.xml",
dataType: "xml",
success: function (xml) {
$(xml).find("Country").each(function () {
var cName = $(this).find("Name").text();
var cIniCount = $(this).find("InitiativeCount").text();
var cUrl = $(this).find("SearchURL").text();
var cCode = $(this).find("CountryCode").text();
//Populate the JS Object
iniDensityData[cCode] = { "initiatives": cIniCount, "url": cUrl, "name": cName };
//set colors according to values of initiatives count
colorArray[cCode] = getCountryColor(cIniCount);
});
}
});
} //end function parseDensityMapXML();
This function is then called on a click event of a checkbox elsewhere on the page. The Objects iniDensityData and colorArray are declared in the head of the html file - hoping that keeps them in global scope:
<script type="text/javascript">
//Initialize a bunch of variables in the global scope
iniDensityData = {};
colorArray = {};
</script>
And finally, here's a snippet from the XML file that is being read:
<?xml version="1.0" encoding="utf-8"?>
<icapCountryData>
<Country>
<Name>Albania</Name>
<CountryCode>AL</CountryCode>
<InitiativeCount>7</InitiativeCount>
<SearchURL>~/advance_search.aspx?search=6</SearchURL>
</Country>
<Country>
<Name>Argentina</Name>
<CountryCode>AR</CountryCode>
<InitiativeCount>15</InitiativeCount>
<SearchURL>~/advance_search.aspx?search=11</SearchURL>
</Country>
... and so on ...
</icapCountryData>
Solved it! Originally, I was calling the function parseDensityMapXML() and then immediately after it calling another function loadDensityMapXML() which took the object created dynamically in the first function and iterated through it. Problem was, it wasn't called as a callback from the first function, so was firing before the Object had even been built.
To fix, I just amended the first function mentioned above to call the second function after the .each() was finished creating the objects:
function parseDensityMapXML() {
$.ajax({
type: "GET",
url: "media/XML/mapCountryData.xml",
dataType: "xml",
success: function (xml) {
$(xml).find("Country").each(function () {
var cName = $(this).find("Name").text();
var cIniCount = $(this).find("InitiativeCount").text();
var cUrl = $(this).find("SearchURL").text();
var cCode = $(this).find("CountryCode").text();
//Populate the JS Object
iniDensityData[cCode] = { "initiatives": cIniCount, "url": cUrl, "name": cName };
//set colors according to values of initiatives count
colorArray[cCode] = getCountryColor(cIniCount);
});
/* and then call the jVectorMap plugin - this MUST be done as a callback
after the above parsing. If called separately, it will fire before the
objects iniDensityData and colorArray are created! */
loadDensityMapXML();
}
});
} //end function parseDensityMapXML();

Delay a function in dojo widget from being called until global variable is set

I have a custom pie chart being rendered from an external js file. I use xhrget to get the data i need to populate the pie chart. The url i am using includes a global variable but my problem is that the function in he script gets called before the global variable is set.
Here is my code:
var chart1 = new dojox.charting.Chart2D(this.id,{fill:"transparent"});
chart1.setTheme(dojox.charting.themes.MiamiNice,{fill:"transparent"});
chart1.addPlot("default", {
type: "Pie",
labels: false,
labelStyle: "rows",
precision: -10,
fontColor: "black",
labelOffset: -20,
radius: 150
});
console.log(this.getURLFunction(this.id ));
chart1.theme.plotarea.fill = undefined;
this.xhrDeferred = dojo.xhrGet({
url: this.getURLFunction(this.id)**,//"../traffic-analysis/get-ip-dist/format/json/ds/1/data/rate/tTime/1334787567/fTime/1334182767/time/604800/drilldown/true/displayedTime/enabled?dojo.preventCache=1334787568120",
sync: true,
handleAs: "json",
preventCache: true,
load: function(responseObj) {
var seriesData=[1,2,3,4,5,6,7];
chart1.addSeries("IP", dojo.map(responseObj.pieItems, function(p){
return {
y: p[1], // value
text: p[0], // label
tooltip:p[0] +": " + p[1]
};
}));
var anim_a = new dojox.charting.action2d.MoveSlice(chart1, "default");
var anim_b = new dojox.charting.action2d.Highlight(chart1, "default");
var anim_c = new dojox.charting.action2d.Tooltip(chart1, "default");
chart1.render();
var chartLegend = new dojox.charting.widget.Legend({
chart: chart1,
swatchSize: 12,
},
"chartLegend");
},
// error: function(error, args) { console.warn("error", error); }
error: function(error, args) {
_this.xhrError = true;
_this.chartStatusBar.innerHTML = chartErrorMsg(_this.id);
console.log(error);
}
});
the getURLFunction(this.id) under the xhrget for url refers to an element in the html that has an id that calls a specific function from the html file.
that function is getURL_IpDist() and it returns the url that the xhrget will use to get the data which is /traffic-analysis/get-ip-dist/format/json" + sc.toURL();
sc is the global variable that I need to be set before my function tries to grab the url. this is set in another external javascript file.
Does anyone know how to delay dojo or javascript from loading before the variable is set?
It is my understanding that the code you posted lives in a seperate js file and you are including it using a <script> tag.
Have you tried wrapping this code in a ready function?
require(["dojo/ready"], function(ready){
ready(function(){
// var chart1 = ...
});
});
Doing this will not execute the code until the browser has parsed the entire dom. Which should include the other code that sets the global variable.
Instead of using variables, use functions. The component that sets the "global variable" actually should invoke a function instead that sets the global variable in question.
Other parts of your application can then use dojo.connect() to connect to the function, so anytime it is called, dojo will call whatever handlers connected to the function. For example:
global.setVar = function(value) {
global.var = value;
}
...
dojo.connect(global, 'setVar', null, function() {
alert("Global variable has been set to: "+global.var);
});
You can use dojo's subscribe/publish facility to get a similar capability, or possibly even your own dojo.Deferred instance. Which method you employ to synchronize communication depends on how your application is designed and what your specific needs are.

Categories

Resources