How to have javascript read a JSON URL - javascript

I want my javascript file to search a URL that is a JSON and grab specific contents from the page. This is the URL
And I want to grab the averageratingscore_rf.
I've even tried this :
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
};
getJSON('https://search.mtvnservices.com/typeahead/suggest/?solrformat=true&rows=20&callback=noCB&q=burgos+AND+schoolid_s%3A1262&defType=edismax&qf=teacherfirstname_t%5E2000+teacherlastname_t%5E2000+teacherfullname_t%5E2000+autosuggest&bf=pow(total_number_of_ratings_i%2C2.1)&sort=total_number_of_ratings_i+desc&siteName=rmp&rows=20&start=0&fl=pk_id+teacherfirstname_t+teacherlastname_t+total_number_of_ratings_i+averageratingscore_rf+schoolid_s&fq=',
function(err, data) {
if (err !== null) {
alert('Something went wrong: ' + err);
} else {
console.log(data.response.docs.averageratingscore_rf);
}
});
But this doesn't work.

It's not a json, it's jsonp response.
JSONP requests perfomed by pass callback name and load this url into DOM script tag.
just don't try ajax+eval, anyway CORS restricts ajax here
Also, data.response.docs is an array, you should iterate it to access averageratingscore_rf
let cb = 'mycallback';
let url = `https://search.mtvnservices.com/typeahead/suggest/?solrformat=true&rows=20&callback=${cb}&q=burgos+AND+schoolid_s%3A1262&defType=edismax&qf=teacherfirstname_t%5E2000+teacherlastname_t%5E2000+teacherfullname_t%5E2000+autosuggest&bf=pow(total_number_of_ratings_i%2C2.1)&sort=total_number_of_ratings_i+desc&siteName=rmp&rows=20&start=0&fl=pk_id+teacherfirstname_t+teacherlastname_t+total_number_of_ratings_i+averageratingscore_rf+schoolid_s&fq=`
function mycallback(data) {
let res = data.response.docs.map(doc => doc.averageratingscore_rf)
console.log('averageratingscore_rf of docs:', res);
}
let script = document.createElement('script');
script.src = url;
document.body.appendChild(script)

Your URL is for JSONP, removing the callback argument returns JSON. (Remove callback=noCB)
Since you tagged google-chrome-extension Same Origin Policy may not apply but keep in mind Cross Origin Resource Sharing may need to be enabled.
... or you could handle the JSONP

Your URL isn't giving back pure JSON. There's a noCB() function wrapping it. That's probably why it's not being read.
Here's what I saw when I opened the URL:
noCB({ "responseHeader":{ "status":0, "QTime":1}, "response":{"numFound":1,"start":0,"docs":[ { "teacherlastname_t":"Burgos", "pk_id":282380, "schoolid_s":"1262", "averageratingscore_rf":2.47, "total_number_of_ratings_i":125, "teacherfirstname_t":"Fernando"}] }, "spellcheck":{ "suggestions":[]}} );
You may be able to execute that method, but if you only want the json, you can either strip out the "noCB(" and ");" at the beginning or the end when you get it, or strip it out at the server.

Related

how to get the filesize of an external image with javascript on front end before loading [duplicate]

Basically, I want to figure out whether I should download a file using AJAX, depending on how large the filesize is.
I guess this question could also be rephrased as: How do I get only the header of an ajax request?
EDIT: ultima-rat0 in the comments told me of two questions that had already been asked that apparently are the same as this one. They are very similar, but they both want jQuery. I want a non-jQuery solution to this.
You can get XHR response header data manually:
http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
This function will get the filesize of the requested URL:
function get_filesize(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("HEAD", url, true); // Notice "HEAD" instead of "GET",
// to get only the header
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
callback(parseInt(xhr.getResponseHeader("Content-Length")));
}
};
xhr.send();
}
get_filesize("http://example.com/foo.exe", function(size) {
alert("The size of foo.exe is: " + size + " bytes.");
});
Sometimes HEAD can act differently than GET so I suggest something like this that aborts the request after getting Content-Length header:
new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/a.bin', true);
xhr.onreadystatechange = () => {
resolve(+xhr.getResponseHeader("Content-Length"));
xhr.abort();
};
xhr.send();
}).then(console.log);
If HEAD request is not possible:
The solution Ebrahim did only not work in firefox for me because context-length was not available for aborted request in firefox. So I used 'onprogress' event instead of 'onreadystatechange' event:
new Promise(
(resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onprogress = (event) => {
if (event.lengthComputable) {
resolve(event.total);
} else {
reject(new Error('No content-length available'));
}
xhr.abort();
};
xhr.send();
}
);
1) If only headers are needed, 'HEAD' should be always preferred over 'GET' because of a simple but not widely known detail: Even if you use 'GET' and immediately abort on readyState === 2 (as suggested by other answers), you will have already received not only the headers, but the full first chunk of information (headers + part of the body) that can vary in size, but usually transfer size will be at least doubled unnecessarily. Using 'HEAD' instead, you can be sure that only headers will be transferred.
2) Content-Length header must be exposed by 'Access-Control-Expose-Headers' to be accessible client-side. If you are dealing with multiple origin resources and you are not sure if Content-Length has been exposed, to prevent exceptions, you can check that, inside an event handler, like this (or other many different ways):
let contentLength = null;
if (checkHeaders(e.target, ['*','Content-Length'])) {
// YOU CAN ACCESS HEADER
contentLength = parseInt(e.target.getResponseHeader("Content-Length"));
} else {
// YOU CAN NOT ACCESS HEADER
console.log('Content-Length NOT AVAILABLE');
}
function checkHeaders(request, headers) {
return (headers.some(function (elem) {
return (request.getResponseHeader("Access-Control-Expose-Headers").includes(elem));
}));
}
3) Content-Length header IS NOT forbidden when any type of encoding is applied (as suggested in some comments). But, be careful that Content-Length will be usually the size of the decoded body (even if it should not). This can be prevented in many different ways, but it is a server-side consideration.

How to get response value from fetch instead of a promise with no value?

I am building a chrome extension to pull data out of a page to build a url from the data and I want to have that url shortened as the final product. In my content scripts file I make a call out to a url shortener to compress a link. I keep getting returned a promise with no value which crashes react. In devtools I see that the callout is made successfully and the url is returned.
I have tried async await, a full async function, tried forcing the response.toString()
Here is the relevant section of code.
var listingInfo = new Map();
listingInfo.set('Address', 'some standard address');
var tinyLink = '(http://tinyurl.com)/api-create.php?url='; //() because I can't share shortener urls on this site.
/*-----------------------------------GET LINKS--------------------------*/
if(listingInfo.has('Address')){ var mapsLink = \`https://www.google.com/maps/place/${listingInfo.get('Address').replace(new RegExp(" ", "g"), '+')}\`;
tinyLink = \`${tinyLink}${mapsLink} `;
var dirLink = fetch(tinyLink, {
method: "GET",
mode: "no-cors",
headers: {"Content-Type": "text/html"} }).then((response)=>{
return response; });
listingInfo.set('dirLink', dirLink); }
I expected to receive a plain text string because in the network tab of devtools it shows a simple string url and not any JSON, but I keep receiving a resolved promise with value="".
// made this function to use XMLHttpRequest()
const setLink = (propName, url) => {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var link = xhr.responseText;
console.log(`link: '${link}'`);
listingInfo.set(propName, link);
}
}
xhr.send();
}
// Then called setLink()
if(listingInfo.has('Address')){
var mapsLink =
`https://www.google.com/maps/place/${listingInfo.get('Address').replace(new
RegExp(" ", "g"), '+')}`;
dirLink = `${tinyLink}${mapsLink}`;
console.log(dirLink);
setLink('dirLink', dirLink);
console.log(dirLink);
}

How can I convert this AJAX request function (raw Javascript) to use POST instead of GET?

I was looking for AJAX in pure JavaScript (without jQuery) for learning purposes and came across this video, along with the code (shown below) on how to make one. However, it's geared towards GET method and I'm not sure how to tweak it to accept additional parameters so that the function can be used for either POST or GET depending on my specified parameters. For example, the lines xhr.open('GET', url, true); and xhr.send(''); both are GET-specific (all other lines in the function are the same for both GET and POST methods)--I want to be able to be able to specify whether to use POST or GET as a parameter for function load for xhr.open and a string such as "username="+username+"&password="+password for function load for xhr.send('');
For example, the function below is for GET and is used like this load('emails.php', function(xhr) {...}. I want the function to be used like this: load('emails.php', 'POST', '"username="+username+"&password="+password' function(xhr) {...}` for POST andload('emails.php', 'GET', '', function(xhr) {...}`
The function for AJAX for GET:
function load(url, callback) {
var xhr;
if(typeof XMLHttpRequest !== 'undefined') xhr = new XMLHttpRequest();
else {
var versions = ["Microsoft.XmlHttp",
"MSXML2.XmlHttp",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.5.0"];
for(var i = 0, len = versions.length; i < len; i++) {
try {
xhr = new ActiveXObject(versions[i]);
break;
}
catch(e){}
} // end for
}
xhr.onreadystatechange = function() {
if((xhr.readyState < 4) || xhr.status !== 200) return;
callback(xhr);
};
xhr.open('GET', url, true);
xhr.send('');
}
Right now the request body is set to null and ignored since you are making a GET request. You should just be able to put whatever you want sent in the body of the POST request inside of the send method:
xhr.open('POST', url, true);
xhr.send(JSON.stringify(someJsonHere));
Check out the documentation for the xhr.send method here:
Here is also a link to a more thorough guide on using XMLHttpRequests; at the bottom it has a section specific to sending data.

How do i correctly format parameters passed server-side using javascript?

I cannot figure out how to get the following code working in my little demo ASP.NET application, and am hoping someone here can help.
Here is the javascript:
function checkUserName() {
var request = createRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var theName = document.getElementById("username").value;
var userName = escape(theName);
var url = "Default.aspx/CheckName";
request.onreadystatechange = createStateChangeCallback(request);
request.open("GET", url, true);
request.setRequestHeader("Content-Type", "application/json");
//none of my attempts to set the 'values' parameter work
var values = //JSON.stringify({userName:"userName"}); //"{userName:'temp name'}"; //JSON.stringify({ "userName":userName });
request.send(values);
}
}
Here is the method in my *.aspx.cs class:
[WebMethod]
[ScriptMethod(UseHttpGet=true)]
public static string CheckName(string userName)
{
string s = "userName";
return s + " modified backstage";
}
When this code runs I receive this exception:
---------------------------
Message from webpage
---------------------------
{"Message":"Invalid web service call, missing value for parameter: \u0027userName\u0027.","StackTrace":" at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)\r\n at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary`2 parameters)\r\n at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.InvalidOperationException"}
---------------------------
OK
---------------------------
I started searching here, then went on to several threads on SO, trying quite a few combinations of quotation marks and key-value pairs, but nothing I've tried has worked.
When I remove the parameter from the C# method and request.send(), I get a response in my JS callback that I can work with. But as soon as I try to do something with parameters, I get the above exception. I'd like to know how to do this without using jQuery, if possible.
Thanks in advance.
FINAL VERSION
Using Alexei's advice, I ended up with the following, which works. The URL was missing the apostrophes on either end of the parameter value; this was keeping the call from going through.
function checkUserName() {
var request = createRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var theName = document.getElementById("username").value;
var userName = encodeURIComponent(theName);
var url = "Default.aspx/CheckName?name='" + theName + "'";
request.onreadystatechange = createStateChangeCallback(request);
request.open("GET", url, true);
request.setRequestHeader("Content-Type", "application/json");
request.send();
}
}
request.send(values);
This won't work with a "GET". Try
request.open("POST", url, true);
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
You need to:
decide whether you want GET or POST. For GET request you need all parameters to be in Url (and body to be empty), for POST you can use both. As of current code you are expecting GET, but sending POST.
properly add query parameter - name and encoded value. encodeUriComponent is JavaScript function of choice, see Build URL from Form Fields with Javascript or jquery for details
if using POST you need to properly encode parameters there too as well specify correct "content-type" header.
if sending JSON you need to decode JSON server side.
Alternatively you can use hidden form to perform POST/GET as covered in JavaScript post request like a form submit
Side note: jQuery.ajax does most of that for you and good source to look through if you want to do all yourself.
Like Alan said, use the POST method. Or pass your arguments in your URL before opening it, e.g.
var url = "Default.aspx/CheckName?userName=" + values;
EDIT : no, it's probably a bad idea since you want to send JSON, forget what I said.
If you need to go for POST, then you need to send it like this.
var values = JSON.stringify({"'userName':'"+ userName+ "'"});
And you have to change HttpGet to HttpPost
Given that your server side method asks for GET, you need:
request.open("GET", url + "?username=" + userName, true);
request.send();
The works for me:
function checkUserName() {
var request = new XMLHttpRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var userName = "Shaun Luttin";
var url = '#Url.RouteUrl(new{ action="CheckName", controller="Home"})';
request.onreadystatechange = function() {
if (request.readyState == XMLHttpRequest.DONE ) {
if(request.status == 200){
document.getElementById("myDiv").innerHTML = request.responseText;
}
else if(request.status == 400) {
alert('There was an error 400')
}
else {
alert('something else other than 200 was returned')
}
}
}
request.open("GET", url + "?username=" + userName, true);
request.send();
}
}
With this on the server side:
[HttpGet]
public string CheckName(string userName)
{
return userName + " modified backstage";
}

Force "charset=x-user-defined'" on jQuery Ajax Post

I am trying to call a Hessian web service from a Javascript application, but I'm having issues parsing the response, since jQuery is treating the response as text and stripping the first bytes of it.
In my research, I have found out that you need to set the charset as 'charset=x-user-defined' in order to the browser leave my bytes as is. But, according the ajax docs:
Sending Data to the Server
By default, Ajax requests are sent using the GET HTTP method. If the
POST method is required, the method can be specified by setting a
value for the type option. This option affects how the contents of the
data option are sent to the server. POST data will always be
transmitted to the server using UTF-8 charset, per the W3C
XMLHTTPRequest standard.
And indeed, the charset is not changing regardless of the settings I used. I have tried the following, separately and all at once, with no luck
$.ajax({
type : 'POST',
url : url,
timeout : 3000,
data : parameters,
contentType : "x-application/hessian; charset=x-user-defined'",
mimeType: 'text/plain; charset=x-user-defined',
headers: {
Accept : "text/plain; charset=x-user-defined",
"Content-Type": "text/plain; charset=x-user-defined"
},
beforeSend : function(xhr) {
xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
})
Also I tried to mess around with the data converters and custom contenttypes defined in jQuery, with no succes.
It appears that as per the standard, I will not be able to do this. It works with GET but not with POST, and the Hessian protocol requires POST.
Do you have any ideas? Or do I need to start to build my XHR method form scratch?
Turns out that I was making a silly mistake somewhere else. But anyhow, I found a sweet way for handling binary data on request and responses, from here.
define(function() {
// Do setup work here
function configurationException(message) {
throw new Error(message + " missing from configuration object");
}
return {
post : function(config) {
if (config) {
var url = config.url || configurationException("url");
var done = config.done || configurationException("callback function");
var timeout = config.timeout || 10000;
var data;
if (config.data) {
data = config.data;
} else {
data = null;
console.warn('No data is specified in binaryPost');
}
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.responseType = "arraybuffer";
request.setRequestHeader("Content-Type", "x-application/hessian;");
request.onload = function(oEvent) {
var arrayBuffer = request.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
done(byteArray);
}
};
request.send(data);
} else {
throw new Error("Configuration object is missing");
}
}
};
});
Hope you find it useful

Categories

Resources