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]?
Related
I have created a common Javascript file for all my ajax calls. I am trying to use this as a common way to keep track of all ajax calls. Below is the code for the same.
function doAjax(doAjax_params) {
var url = doAjax_params['url'];
var requestType = doAjax_params['requestType'];
var contentType = doAjax_params['contentType'];
var dataType = doAjax_params['dataType'];
var data = doAjax_params['data'];
var beforeSendCallbackFunction = doAjax_params['beforeSendCallbackFunction'];
var successCallbackFunction = doAjax_params['successCallbackFunction'];
var completeCallbackFunction = doAjax_params['completeCallbackFunction'];
var errorCallBackFunction = doAjax_params['errorCallBackFunction'];
//Make the ajax call
$.ajax({
url: getBaseURL() + url,
crossDomain: true,
type: requestType,
contentType: contentType,
dataType: dataType,
data: data,
success: function (data, textStatus, jqXHR) {
console.log(typeof successCallbackFunction);
debugger
//if (typeof successCallbackFunction === "function") {
successCallbackFunction(data);
//}
},
error: function (jqXHR, textStatus, errorThrown) {
if (typeof errorCallBackFunction === "function") {
errorCallBackFunction(errorThrown);
}
}
});
}
This code takes a list of parameters and creates an ajax request based on the parameteres. This code is saved in a file APIHandler.js.
I am trying to call this function from multiple files. An example call is below.
function RedirectToDashboard() {
var params = $.extend({}, doAjax_params_default);
params['url'] = `profile/5`;
params['successCallbackFunction'] = `testsuccess`
doAjax(params);
}
function testsuccess() {
alert("success");
}
When I run this function, I am able to make the call successfully. The only issue comes with the reference to callback function. console.log(typeof successCallbackFunction); returns string instead of function.
I thought maybe order of JS made a difference. I am loading APIHandler.js and then the page specific js. And this ajax call happens at button click, so both JS files are loaded before the ajax call is made.
Other than that, I think maybe I am sending the parameters wrong. That might be causing JS to consider function name as string. But I checked most of the google suggestions on how to pass function, and it seems it needs just the name.
Is there anything else that I might be missing here?
Damn it. I just figured out why it was causing the error. I used quotes when assigning the callback function. Right after posting the question, I realised what was wrong.
params['successCallbackFunction'] = 'testsuccess'
is supposed to be changed to
params['successCallbackFunction'] = testsuccess
I'm trying to auth a Last.fm session and am struggling to sign a request for a session key correctly.
I keep receiving Invalid method signature supplied However when I md5 hash what i believe the query should consist of outside of JS, I get the same signature. I must be including the wrong data in the string I guess, but can't figure out what.
I know there are a few other questions and i've ran through them all to see what's going wrong here, but I swear it looks right to me.
This is the signing algorithm and Ajax call. I've tried to leave enough sample data too.
// Set elsewhere but hacked into this example:
var last_fm_data = {
'last_token':'TOKEN876234876',
'user': 'bob',
'secret': 'SECRET348264386'
};
// Kick it off.
last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});
// Low level API call, purely builds a POSTable object and calls it.
function last_fm_call(method, data){
// param data - dictionary.
last_fm_data[method] = false;
// Somewhere to put the result after callback.
// Append some static variables
data['api_key'] = "APIKEY1323454";
data['format'] = 'json';
data['method'] = method;
post_data = last_fm_sign(data);
$.ajax({
type: "post",
url: last_url,
data: post_data,
success: function(res){
last_fm_data[method] = res;
console.log(res['key'])// Should return session key.
},
dataType: 'json'
});
}
function last_fm_sign(params){
ss = "";
st = [];
so = {};
Object.keys(params).forEach(function(key){
st.push(key); // Get list of object keys
});
st.sort(); // Alphabetise it
st.forEach(function(std){
ss = ss + std + params[std]; // build string
so[std] = params[std]; // return object in exact same order JIC
});
// console.log(ss + last_fm_data['secret']);
// api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
hashed_sec = unescape(encodeURIComponent($.md5(ss + last_fm_data['secret'])));
so['signature'] = hashed_sec; // Correct when calculated elsewhere.
return so; // Returns signed POSTable object
}
Anything anyone can see that i'm missing here? I'm absolutely stumped why this isn't returning a correctly signed POSTable object in the format requested here. Thanks for your time.
Edit: can't thank anyone for their time if i don't get any advice! No one had any experience with last.fm?
After investigating your code and other posts related to last.fm api call, I found that #george lee in fact is correct. You don't need to provide format while generating the auth_sign.
Apart from that you need to apply $.md5() to auth_sign string after applying encodeURIComponent() and unescape() functions. Like this.
hashed_sec = $.md5(unescape(encodeURIComponent(ss + last_fm_data['secret'])));
Also while making ajax call you need to pass api_key, token & api_sig as data. But seeing your code, reveals that you are passing api_key, token, format, method & signature.
So you need to remove format, method & signature from the data field of ajax call.
Instead you need to pass api_key, token & api_sig to the data field.
So the final code after commenting the data['format'] = 'json'; line will look like this.
// Set elsewhere but hacked into this example:
var last_fm_data = {
'last_token':'TOKEN876234876',
'user': 'bob',
'secret': 'SECRET348264386'
};
// Kick it off.
last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});
// Low level API call, purely builds a POSTable object and calls it.
function last_fm_call(method, data){
// param data - dictionary.
last_fm_data[method] = false;
// Somewhere to put the result after callback.
// Append some static variables
data['api_key'] = "APIKEY1323454";
//data['format'] = 'json';
data['method'] = method;
post_data = last_fm_sign(data);
$.ajax({
type: "POST",
url: last_url,
data: post_data,
success: function(res){
last_fm_data[method] = res;
console.log(res['key'])// Should return session key.
},
dataType: 'json'
});
}
function last_fm_sign(params){
ss = "";
st = [];
so = {};
so['api_key'] = params['api_key'];
so['token'] = params['token'];
Object.keys(params).forEach(function(key){
st.push(key); // Get list of object keys
});
st.sort(); // Alphabetise it
st.forEach(function(std){
ss = ss + std + params[std]; // build string
});
ss += last_fm_data['secret'];
// console.log(ss + last_fm_data['secret']);
// api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
hashed_sec = $.md5(unescape(encodeURIComponent(ss)));
so['api_sig'] = hashed_sec; // Correct when calculated elsewhere.
return so; // Returns signed POSTable object
}
Please refer to this link.
So on testing some of the responses, I found the solution. There were 2 issues.
EDITED see below (
The first was needing to remove
data['format'] = 'json';
as George Lee pointed out. Thanks George.
)
The other issue was that I'd named a variable incorrectly so was being POSTed with the wrong name. The line
so['signature'] = hashed_sec;
should have been
so['api_sig'] = hashed_sec;
I noticed this in Pankaj's answer but unfortunately the rest of his answer (i.e. including the method) was incorrect. Making these 2 changes resolved the call and signed it correctly.
Thanks for all the suggestions!
EDIT:
After some more playing, i've found that
data['format'] = 'json';
IS correct, however it DOESN'T get hashed with the signature.
Adding data['format'] = 'json'; to the POST object after hashing works, and in this instance will return JSON as opposed to XML - which was the preferred method. Adding after hashing is not documented anywhere that I can find, so there you go.
The new working code is as follows, and this shows the 2 lines indicated with --------------------
// Set elsewhere but hacked into this example:
var last_fm_data = {
'last_token':'TOKEN876234876',
'user': 'bob',
'secret': 'SECRET348264386'
};
// Kick it off.
last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});
// Low level API call, purely builds a POSTable object and calls it.
function last_fm_call(method, data){
// param data - dictionary.
last_fm_data[method] = false;
// Somewhere to put the result after callback.
// Append some static variables
data['api_key'] = "APIKEY1323454";
data['method'] = method;
post_data = last_fm_sign(data);
// THEN ADD THE FORMAT ---------------------------------------
post_data['format'] = 'json';
$.ajax({
type: "post",
url: last_url,
data: post_data,
success: function(res){
last_fm_data[method] = res;
console.log(res['key'])// Should return session key.
},
dataType: 'json'
});
}
function last_fm_sign(params){
ss = "";
st = [];
so = {};
Object.keys(params).forEach(function(key){
st.push(key); // Get list of object keys
});
st.sort(); // Alphabetise it
st.forEach(function(std){
ss = ss + std + params[std]; // build string
so[std] = params[std]; // return object in exact same order JIC
});
// console.log(ss + last_fm_data['secret']);
// api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
hashed_sec = unescape(encodeURIComponent($.md5(ss + last_fm_data['secret'])));
so['api_sig'] = hashed_sec; // RENAMED THIS ----------------------------
return so; // Returns signed POSTable object
}
i'm trying to develop Firefox extension
problem :
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "file.php",
onComplete: function (response) {
var List = response.json;
}
});
I want to use this request function to parse json to an array (List here) from php file.
The php my php file echo json form correctly, but I can't transform the data into javascript array to be able to use it in my addon.
if there is a better idea than using this function to do it please tell me :)
try this: MDN - JSON Object
JSON.parse and JSON.stringify
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "file.php",
onComplete: function (response) {
var List = JSON.parse(response.json);
}
});
it's very important to use double quotes.
If you are having a problem with JSON.parse. Copy your array to scratchpad and then run JSON.stringify on it and then make sure your php file matches the strignified result.
if Addon-SDK doesnt have JSON then you gotta require the module if there is one. If there isn't one than require('chrome') and grab the component HERE
There's a bug in Noitidarts code.
why JSON.parse the request.json? If you want to parse do it on request.text
However no need to json.parse as the request module tries to parse and if successful retuns request.json
see here:
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "https://api.twitter.com/1/statuses/user_timeline.json?screen_name=mozhacks&count=1",
onComplete: function (response) {
var tweet = response.json[0];
console.log("User: " + tweet.user.screen_name);
console.log("Tweet: " + tweet.text);
}
});
// Be a good consumer and check for rate limiting before doing more.
Request({
url: "http://api.twitter.com/1/account/rate_limit_status.json",
onComplete: function (response) {
if (response.json.remaining_hits) {
latestTweetRequest.get();
} else {
console.log("You have been rate limited!");
}
}
}).get();
so the likely problem is that your php is not outputting a json string that json.parse can read. make sure to use ". figure out what your php file should return by running json.stringify on a dummy object. ie:
var obj = {myarr:[1,8,9,7,89,0,'ji'],strr:'khhkjh',anothrtObj:{1:45,56:8}};
alert(JSON.stringify(obj)) //{"myarr":[1,8,9,7,89,0,"ji"],"strr":"khhkjh","anothrtObj":{"1":45,"56":8}}
so now in your php make sure your outputted text mateches this format
{"myarr":[1,8,9,7,89,0,"ji"],"strr":"khhkjh","anothrtObj":{"1":45,"56":8}}
if your php outputs something like below JSON.parse will fail on it so request.json will be null
{myarr:[1,8,9,7,89,0,"ji"],strr:"khhkjh",anothrtObj:{"1":45,"56":8}}
or
{'myarr':[1,8,9,7,89,0,"ji"],'strr':"khhkjh",'anothrtObj':{"1":45,"56":8}}
or
{'myarr':[1,8,9,7,89,0,'ji'],'strr':'khhkjh','anothrtObj':{'1':45,'56':8}}
As IE does not support cross domain issues, we have to use get or post method by using xdr, my problem is, I don't know how to pass data while using get method with xdr.
Code snippet for get method using jquery ajax is like -
$.ajax({
type: 'GET',
cache: false,
url: site_url,
data: params,
success: onsuccess,
error:onError
});
but suppose if I write this code for xdr it will be like -
var xdr = new XDomainRequest();
xdr.CacheControl = "no-cache";
xdr.open("get", site_url);
xdr.onload = function () {
var data = $.parseJSON(xdr.responseText);
onsuccess(data);
}
xdr.onerror = function() {alert('err');};
xdr.send();
Now in this, I do not know where to pass data!!!
Please help me out to solve this problem.
It all happens in the ".open" method.
Lets say you want to pass some JSON or an object to the request.
Do it like so...
var my_request_data = {
"whatever" : "whatever",
"again" : "whatever again",
"you get" : "the point..."
};
my_request_data = $.param(my_request_data);
xdr.open("get", "http://url.com/to/get/or/post/too/" + my_request_data);
jQuery turns the JSON object into URL friendly params and then it is sent to the server.
That is how you pass data!
I'm trying to query the OpenCalais service semanticproxy.com. Unfortunately, their url format is as follows:
http://service.semanticproxy.com/processurl/APIKEY/jsonp:handler_function/http://en.wikipedia.org/wiki/Germany
notice that the function callback, is not in a callback=? parameter, but rather follows the response format (jsonp:). This means that I can't use .getJSON, but rather need to use the .ajax method. So I have the following object definition:
function Subject() {
}
Subject.prototype.populate = function(page_title) {
var url = "http://service.semanticproxy.com/processurl/APIKEY/jsonp:handler/http://en.wikipedia.org/wiki/" + page_title;
$.ajax({url: url, dataType: "script", type: "GET", cache: false, callback: null, data: null});
};
var handler = function (data) {
// do stuff with the returned JSON
};
s = new Subject();
s.populate("Germany");
This works fine. But what I really want to do is set properties of my Subject object. But I don't know how to create a function in the context of the Subject that will be able to be used as the callback. i.e:
Subject.prototype.handler = function(data) { this.title = data.title }
Any ideas?
You'd have to set a function on the window object. This is essentially (I think) what jQuery does with its .getJSON method. The below is a bit hacky but hopefully it points you in the right direction:
function Subject() {
}
Subject.prototype.populate = function(page_title) {
// Save context object
var subject = this;
// Create function name like subjectHandler1281092055198
var functionName = "subjectHandler" + new Date().getTime();
window[functionName] = function(data) {
// Invoke function with saved context and parameter
subject.handler.call(subject, data);
}
var url = "http://service.semanticproxy.com/processurl/APIKEY/jsonp:" + functionName + "/http://en.wikipedia.org/wiki/" + page_title;
$.ajax({url: url, dataType: "script", type: "GET", cache: false, callback: null, data: null});
};
Subject.prototype.handler = function (data) {
// do stuff with the returned JSON
};
s = new Subject();
s.populate("Germany");
I don't think you're going to be able to do this, just because of how JSONP works, look at how it actually comes back to the browser, it pretty much does this:
<script type="text/javascript">
handler({ title: "Germany", ...other properties... });
</script>
There's no way to maintain a reference here, you could do one request at a time, or keep an object map for each subject, but there's no way to do it in the JSONP request.
An object map would look something like this:
//delcare this once for the page
var subjects = {};
//do this per subject
var s = new Subject();
s.populate("Germany");
subjects["Germany"] = s;
Then in your hanldler, if any of the data properties is "Germany", you could get it that way, for example:
var handler = function (data) {
var subject = subjects[data.title];
//subject is your Germany subject, use it, go nuts!
};